Skip to content

Commit 85f7695

Browse files
Merge pull request #9 from ROBACON/reversible_rate_update
Reversible rate update
2 parents 75ee66f + b5c047e commit 85f7695

9 files changed

+187
-61
lines changed

debugging_script.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,15 @@
3333
test_assignment_similar_species, test_blocked_names, test_blocked_names_2,
3434
test_update_parameter_for_multi_model, test_update_parameter_through_str,
3535
test_update_multiple_parameters_in_expression, test_update_parameter_with_unit,
36-
test_species_value_modification, test_all_value_modification]
36+
test_species_value_modification, test_all_value_modification, test_new_reversible_reaction_notation,
37+
test_2D_reaction_with_units]
3738

3839
# test_no_species_in_asg
3940
# test_illegal_unit_op_in_assignment
4041
# temporary_test_removal = [test_parameter_fit_with_units, test_multiple_runs_fit, test_simple_fit]
4142
test_remov = [test_antimony_compose_model_gen, test_antimony_model]
4243
sub_test = test_list
43-
#sub_test = [test_antimony_compose_model_gen]
44+
# sub_test = [test_parameters_with_sbml]
4445
def perform_tests():
4546
any_failed = False
4647
for test in sub_test:

for_local_use.py

+9-15
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,20 @@
22
from mobspy import modules
33

44
if __name__ == '__main__':
5+
from mobspy import *
56

6-
# TODO: Ask Matthias about removed tests
77

88
# Replace parameters using units
9-
A = BaseSpecies()
10-
A.a1, A.a2
11-
B = New(A)
12-
B.b1, B.b2
13-
k1 = ModelParameters(1)
9+
Color, Location = BaseSpecies()
10+
Color.red, Color.blue
11+
Location.here, Location.there
12+
Something = Color*Location
1413

15-
B >> Zero [k1]
14+
2*Something >> 3*Something [lambda r1, r2: 1*u.decimeter**2/u.h if Location(r1) == Location(r2) else 0.5*u.decimeter**2/u.h]
1615

17-
B(100), B.b2(100)
18-
S = Simulation(B)
19-
S.level = -1
20-
S.compile()
21-
22-
S.update_model([All[B], 200/u.l])
23-
24-
print(S.generate_sbml()[0])
16+
S = Simulation(Something)
17+
S.volume = 1*u.m**2
18+
print(S.compile())
2519

2620
# print(A.get_characteristics())
2721

mobspy/modules/function_rate_code.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ def extract_reaction_rate(combination_of_reactant_species, reactant_string_list
5555
reaction_rate_function, type_of_model, is_count)
5656

5757
elif function_rate_arguments is not None:
58-
5958
# [''] means that it is a function that takes no arguments (empty signature)
6059
if function_rate_arguments != ['']:
6160
arguments = prepare_arguments_for_callable(combination_of_reactant_species,
@@ -87,12 +86,14 @@ def extract_reaction_rate(combination_of_reactant_species, reactant_string_list
8786

8887
# Having an expression variable implies it is a constructed expression - not mass action
8988
if len(rate._expression_variables) > 0:
90-
reaction_rate_string, _ = rate.generate_string_operation(skip_check=skip_check)
89+
reaction_rate_string, _ = rate.generate_string_operation(skip_check=skip_check, dimension=dimension)
9190

9291
# Having no expression variables implies it is a constant for mass - action kinetics.
9392
elif len(rate._expression_variables) == 0:
93+
9494
rate_for_mass_action, is_count = \
95-
rate.generate_string_operation(reaction_order=len(reactant_string_list), skip_check=skip_check)
95+
rate.generate_string_operation(reaction_order=len(reactant_string_list), dimension=dimension,
96+
skip_check=skip_check)
9697
parameters_in_rate = rate._parameter_set
9798
parameters_in_reaction = parameters_in_reaction.union(parameters_in_rate)
9899

mobspy/modules/meta_class.py

+63-24
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
Bear in mind that they are not actually Python meta-classes. The first design utilized this feature but know there
55
are just regular classes
66
"""
7-
from mobspy.simulation_logging.log_scripts import error as simlog_error, debug as simlog_debug
7+
from copy import deepcopy
8+
9+
from mobspy.simulation_logging.log_scripts import error as simlog_error, debug as simlog_debug, error
810
from mobspy.modules.species_string_generator import construct_all_combinations as ssg_construct_all_combinations
911
from mobspy.modules.assignments_implementation import Assign as asgi_Assign, Asg as asgi_Asg
1012
from pint import Quantity
@@ -43,6 +45,30 @@ def override_get_item(cls, object_to_return, item):
4345
cls.last_rate = item
4446
return object_to_return
4547

48+
@classmethod
49+
def process_rate(cls, rate):
50+
51+
if isinstance(rate, (np_int_, np_float_)):
52+
rate = float(rate)
53+
54+
if isinstance(rate, Species) \
55+
or isinstance(rate, Reacting_Species) \
56+
or isinstance(rate, Reactions):
57+
simlog_error('Reaction rate of type ' + str(type(_Last_rate_storage.last_rate)) + ' not valid',
58+
stack_index=3)
59+
60+
if not (type(rate) == int or type(rate) == float
61+
or callable(rate) or type(rate) == str
62+
or isinstance(rate, me_OverrideQuantity)
63+
or isinstance(rate, Quantity)
64+
or isinstance(rate, mp_Mobspy_Parameter)
65+
or rate is None
66+
or isinstance(rate, me_ExpressionDefiner)):
67+
simlog_error('Reaction rate of type ' + str(type(rate)) + ' not valid',
68+
stack_index=3)
69+
70+
return rate
71+
4672

4773
class Reactions:
4874
"""
@@ -95,7 +121,7 @@ def __getitem__(self, item):
95121
"""
96122
return _Last_rate_storage.override_get_item(self, item)
97123

98-
def __init__(self, reactants, products):
124+
def __init__(self, reactants, products, rate=None):
99125
"""
100126
Constructor of the reaction object. For the object construction only the reactants and products are
101127
necessary - the order and the rate are assigned later by the compiler
@@ -117,7 +143,37 @@ def __init__(self, reactants, products):
117143
'A reaction was defined with the assignment context activated.'
118144
'The assignment context was deactivated. Please try to redefine the model')
119145

120-
# Add characteristics in Cts_context to each reactant and product
146+
# Setup rate - consider reversible reactions
147+
try:
148+
flag_len = len(_Last_rate_storage.last_rate) == 2
149+
except:
150+
flag_len = False
151+
152+
if flag_len and rate is None:
153+
154+
store_last_rate = _Last_rate_storage.last_rate[0]
155+
Reactions(reactants=products, products=reactants, rate=_Last_rate_storage.last_rate[1])
156+
rate = _Last_rate_storage.process_rate(store_last_rate)
157+
158+
elif rate is not None and not flag_len:
159+
160+
rate = _Last_rate_storage.process_rate(rate)
161+
162+
elif rate is None and not flag_len:
163+
164+
rate = _Last_rate_storage.process_rate(_Last_rate_storage.last_rate)
165+
166+
elif rate is not None and flag_len:
167+
168+
rate = _Last_rate_storage.process_rate(rate)
169+
170+
else:
171+
simlog_error('To many rate provided', stack_index=3)
172+
self.rate = rate
173+
if _Last_rate_storage.last_rate is not None:
174+
_Last_rate_storage.last_rate = None
175+
176+
# Add characteristics in Cts_context to each reactant and product
121177
if len(Species.meta_specie_named_any_context) != 0:
122178
for j in Species.meta_specie_named_any_context:
123179
for r in reactants:
@@ -143,29 +199,12 @@ def __init__(self, reactants, products):
143199

144200
# Assign default order
145201
self.order = None
146-
# Cast np to float
147-
if isinstance(_Last_rate_storage.last_rate, (np_int_, np_float_)):
148-
_Last_rate_storage.last_rate = float(_Last_rate_storage.last_rate)
149202

150-
if isinstance(_Last_rate_storage.last_rate, Species) \
151-
or isinstance(_Last_rate_storage.last_rate, Reacting_Species) \
152-
or isinstance(_Last_rate_storage.last_rate, Reactions):
153-
simlog_error('Reaction rate of type ' + str(type(_Last_rate_storage.last_rate)) + ' not valid',
154-
stack_index=3)
155-
156-
if not (type(_Last_rate_storage.last_rate) == int or type(_Last_rate_storage.last_rate) == float
157-
or callable(_Last_rate_storage.last_rate) or type(_Last_rate_storage.last_rate) == str
158-
or isinstance(_Last_rate_storage.last_rate, me_OverrideQuantity)
159-
or isinstance(_Last_rate_storage.last_rate, Quantity)
160-
or isinstance(_Last_rate_storage.last_rate, mp_Mobspy_Parameter)
161-
or _Last_rate_storage.last_rate is None
162-
or isinstance(_Last_rate_storage.last_rate, me_ExpressionDefiner)):
163-
simlog_error('Reaction rate of type ' + str(type(_Last_rate_storage.last_rate)) + ' not valid',
164-
stack_index=3)
203+
# Define reversible reaction with two rates
165204

166-
self.rate = _Last_rate_storage.last_rate
167-
if _Last_rate_storage.last_rate is not None:
168-
_Last_rate_storage.last_rate = None
205+
# Cast np to float
206+
#if _Last_rate_storage.last_rate is not None:
207+
# _Last_rate_storage.last_rate = None
169208

170209
# Here we extract all involved objects to pact them in a set
171210
# This is done to find the reactions associated with the species when the Compiler is started

mobspy/modules/mobspy_expressions.py

+8-7
Original file line numberDiff line numberDiff line change
@@ -806,7 +806,7 @@ def __getattr__(self, item):
806806
return super().__getattr__(item)
807807

808808
# Write string operation return and unit
809-
def generate_string_operation(self, skip_check=False, reaction_order=None):
809+
def generate_string_operation(self, skip_check=False, reaction_order=None, dimension=None):
810810
"""
811811
Converts the expression from what has been stored to a string format for the sbml file
812812
@@ -815,10 +815,11 @@ def generate_string_operation(self, skip_check=False, reaction_order=None):
815815
"""
816816
ur = u.unit_registry_object
817817

818-
if self._dimension is None:
819-
dimension = 3
820-
else:
821-
dimension = self._dimension
818+
if dimension is None:
819+
if self._dimension is None:
820+
dimension = 3
821+
else:
822+
dimension = self._dimension
822823

823824
operation = str(self._operation)
824825

@@ -829,9 +830,9 @@ def generate_string_operation(self, skip_check=False, reaction_order=None):
829830
self._count_in_expression = True
830831

831832
if self._has_units == 'T' and self._expression_variables == set() and reaction_order is not None:
832-
if self._unit_count_op.units == (1 / ur.second):
833+
if self._unit_count_op.units == (1 / ur.second).units:
833834
return operation, True
834-
elif self._unit_conc_op.units == (1*ur.decimeter**(3*reaction_order)/(ur.second*ur.decimeter**dimension)):
835+
elif self._unit_conc_op.units == (ur.decimeter**(dimension * (reaction_order - 1)) / ur.second):
835836
return operation, False
836837

837838
c1 = self._has_units == 'T'

test_plot_images/read_me.txt

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
This directory is used for test purposes. It received the images generated by the test script.
2+
Any plotting tests should create images here.
3+

test_script.py

+42-10
Original file line numberDiff line numberDiff line change
@@ -769,7 +769,7 @@ def test_bi_dimensional_rates():
769769
def test_dimension_in_function_only():
770770
A = BaseSpecies()
771771

772-
A + A >> 3 * A[lambda: 1 * u.milliliter / u.second]
772+
A + A >> 3 * A [lambda: 1 * u.milliliter / u.second]
773773

774774
A(1)
775775
S = Simulation(A)
@@ -958,7 +958,7 @@ def test_parameters_with_sbml():
958958
for data_for_sbml in parameter_sweep:
959959
model_str += order_model_str(data_for_sbml)
960960

961-
assert compare_model(model_str, 'test_tools/model_31.txt')
961+
assert compare_model_ignore_order(model_str, 'test_tools/model_31.txt')
962962

963963

964964
def test_shared_parameter_name():
@@ -1942,7 +1942,7 @@ def test_update_parameter_for_multi_model():
19421942

19431943
k1 = ModelParameters([1, 2, 3])
19441944

1945-
A >> Zero [2*k1]
1945+
A >> mobspy.Zero [2*k1]
19461946

19471947
A(100)
19481948
S1 = Simulation(A)
@@ -1952,7 +1952,7 @@ def test_update_parameter_for_multi_model():
19521952
# print(S.generate_sbml()[0])
19531953

19541954
A.reset_reactions()
1955-
B >> Zero [1]
1955+
B >> mobspy.Zero [1]
19561956

19571957
B(200)
19581958
S2 = Simulation(A | B)
@@ -1974,7 +1974,7 @@ def test_update_parameter_through_str():
19741974
A = BaseSpecies()
19751975
k1 = ModelParameters(0.00000001)
19761976

1977-
A >> Zero [k1]
1977+
A >> mobspy.Zero [k1]
19781978

19791979
S = Simulation(A)
19801980
S.level = -1
@@ -1989,7 +1989,7 @@ def test_update_multiple_parameters_in_expression():
19891989
A = BaseSpecies()
19901990
k1, k2 = ModelParameters(0.00000001, 10)
19911991

1992-
A >> Zero [k1 / (10 + k2 ** 4)]
1992+
A >> mobspy.Zero [k1 / (10 + k2 ** 4)]
19931993

19941994
S = Simulation(A)
19951995
S.level = -1
@@ -2005,7 +2005,7 @@ def test_update_parameter_with_unit():
20052005
A = BaseSpecies()
20062006
k1 = ModelParameters(1 / u.h)
20072007

2008-
A >> Zero[k1]
2008+
A >> mobspy.Zero[k1]
20092009

20102010
S = Simulation(A)
20112011
S.level = -1
@@ -2024,7 +2024,7 @@ def test_species_value_modification():
20242024
B.b1, B.b2
20252025
k1 = ModelParameters(1)
20262026

2027-
B >> Zero[k1]
2027+
B >> mobspy.Zero[k1]
20282028

20292029
B(100), B.b2(100)
20302030
S = Simulation(B)
@@ -2042,7 +2042,7 @@ def test_all_value_modification():
20422042
B.b1, B.b2
20432043
k1 = ModelParameters(1)
20442044

2045-
B >> Zero[k1]
2045+
B >> mobspy.Zero[k1]
20462046

20472047
B(100), B.b2(100)
20482048
S = Simulation(B)
@@ -2051,4 +2051,36 @@ def test_all_value_modification():
20512051

20522052
S.update_model([All[B], 200 / u.l])
20532053

2054-
assert compare_model_ignore_order(S.generate_sbml()[0], 'test_tools/model_62.txt')
2054+
assert compare_model_ignore_order(S.generate_sbml()[0], 'test_tools/model_62.txt')
2055+
2056+
2057+
def test_new_reversible_reaction_notation():
2058+
2059+
A = BaseSpecies()
2060+
k1, k2 = ModelParameters(1, 1)
2061+
2062+
A >> mobspy.Zero[1, 1]
2063+
A >> mobspy.Zero[1 / (k1 + k2), k1]
2064+
2065+
A >> 2 * A[10]
2066+
2067+
S = Simulation(A)
2068+
S.level = -1
2069+
assert compare_model(S.compile(), 'test_tools/model_63.txt')
2070+
2071+
2072+
def test_2D_reaction_with_units():
2073+
2074+
Color, Location = BaseSpecies()
2075+
Color.red, Color.blue
2076+
Location.here, Location.there
2077+
Something = Color * Location
2078+
2079+
rate = lambda r1, r2: 1 * u.decimeter ** 2 / u.h if Location(r1) == Location(r2) \
2080+
else 0.5 * u.decimeter ** 2 / u.h
2081+
2 * Something >> 3 * Something[rate]
2082+
2083+
S = Simulation(Something)
2084+
S.level = -1
2085+
S.volume = 1 * u.m ** 2
2086+
assert compare_model(S.compile(), 'test_tools/model_64.txt')

test_tools/model_63.txt

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
2+
Species
3+
A,0
4+
5+
Mappings
6+
A :
7+
A
8+
9+
Parameters
10+
k1,1
11+
k2,1
12+
volume,1
13+
14+
Reactions
15+
reaction_0,{'re': [(1, 'A')], 'pr': [(2, 'A')], 'kin': 'A * 10'}
16+
reaction_1,{'re': [(1, 'A')], 'pr': [], 'kin': 'A * (1/(k1+k2))'}
17+
reaction_2,{'re': [(1, 'A')], 'pr': [], 'kin': 'A * 1'}
18+
reaction_3,{'re': [], 'pr': [(1, 'A')], 'kin': '1 * volume'}
19+
reaction_4,{'re': [], 'pr': [(1, 'A')], 'kin': 'k1 * volume'}
20+

0 commit comments

Comments
 (0)