mxlpy 0.20.0__py3-none-any.whl → 0.22.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mxlpy/__init__.py +5 -1
- mxlpy/carousel.py +166 -0
- mxlpy/compare.py +2 -6
- mxlpy/experimental/diff.py +1 -1
- mxlpy/fit.py +386 -44
- mxlpy/identify.py +20 -16
- mxlpy/integrators/int_scipy.py +3 -0
- mxlpy/label_map.py +5 -5
- mxlpy/linear_label_map.py +3 -1
- mxlpy/mc.py +24 -20
- mxlpy/mca.py +9 -7
- mxlpy/meta/__init__.py +5 -3
- mxlpy/meta/codegen_latex.py +44 -30
- mxlpy/meta/codegen_model.py +174 -0
- mxlpy/meta/{codegen_modebase.py → codegen_mxlpy.py} +35 -29
- mxlpy/meta/source_tools.py +408 -167
- mxlpy/meta/sympy_tools.py +117 -0
- mxlpy/model.py +528 -224
- mxlpy/parallel.py +7 -6
- mxlpy/report.py +153 -90
- mxlpy/sbml/_export.py +11 -8
- mxlpy/sbml/_import.py +7 -7
- mxlpy/scan.py +32 -20
- mxlpy/simulator.py +240 -59
- mxlpy/symbolic/symbolic_model.py +29 -17
- mxlpy/types.py +45 -20
- mxlpy/units.py +128 -0
- {mxlpy-0.20.0.dist-info → mxlpy-0.22.0.dist-info}/METADATA +3 -1
- mxlpy-0.22.0.dist-info/RECORD +58 -0
- mxlpy/meta/codegen_py.py +0 -115
- mxlpy-0.20.0.dist-info/RECORD +0 -55
- {mxlpy-0.20.0.dist-info → mxlpy-0.22.0.dist-info}/WHEEL +0 -0
- {mxlpy-0.20.0.dist-info → mxlpy-0.22.0.dist-info}/licenses/LICENSE +0 -0
mxlpy/parallel.py
CHANGED
@@ -103,7 +103,7 @@ def parallelise[K: Hashable, Tin, Tout](
|
|
103
103
|
timeout: float | None = None,
|
104
104
|
disable_tqdm: bool = False,
|
105
105
|
tqdm_desc: str | None = None,
|
106
|
-
) ->
|
106
|
+
) -> list[tuple[K, Tout]]:
|
107
107
|
"""Execute a function in parallel over a collection of inputs.
|
108
108
|
|
109
109
|
Examples:
|
@@ -136,9 +136,9 @@ def parallelise[K: Hashable, Tin, Tout](
|
|
136
136
|
cache=cache,
|
137
137
|
) # type: ignore
|
138
138
|
|
139
|
-
results:
|
139
|
+
results: list[tuple[K, Tout]]
|
140
140
|
if parallel:
|
141
|
-
results =
|
141
|
+
results = []
|
142
142
|
max_workers = (
|
143
143
|
multiprocessing.cpu_count() if max_workers is None else max_workers
|
144
144
|
)
|
@@ -157,18 +157,19 @@ def parallelise[K: Hashable, Tin, Tout](
|
|
157
157
|
try:
|
158
158
|
key, value = next(it)
|
159
159
|
pbar.update(1)
|
160
|
-
results
|
160
|
+
results.append((key, value))
|
161
161
|
except StopIteration:
|
162
162
|
break
|
163
163
|
except TimeoutError:
|
164
164
|
pbar.update(1)
|
165
165
|
else:
|
166
|
-
results =
|
166
|
+
results = list(
|
167
167
|
tqdm(
|
168
168
|
map(worker, inputs), # type: ignore
|
169
169
|
total=len(inputs),
|
170
170
|
disable=disable_tqdm,
|
171
171
|
desc=tqdm_desc,
|
172
|
-
)
|
172
|
+
)
|
173
173
|
) # type: ignore
|
174
|
+
|
174
175
|
return results
|
mxlpy/report.py
CHANGED
@@ -3,25 +3,25 @@
|
|
3
3
|
from __future__ import annotations
|
4
4
|
|
5
5
|
from collections.abc import Callable
|
6
|
+
from dataclasses import dataclass
|
6
7
|
from datetime import UTC, datetime
|
7
8
|
from pathlib import Path
|
8
9
|
from typing import cast
|
9
10
|
|
10
11
|
import sympy
|
11
12
|
|
12
|
-
from mxlpy.meta.
|
13
|
+
from mxlpy.meta.sympy_tools import fn_to_sympy, list_of_symbols
|
13
14
|
from mxlpy.model import Model
|
14
15
|
|
15
|
-
__all__ = [
|
16
|
-
"AnalysisFn",
|
17
|
-
"markdown",
|
18
|
-
]
|
16
|
+
__all__ = ["AnalysisFn", "MarkdownReport", "markdown"]
|
19
17
|
|
20
18
|
type AnalysisFn = Callable[[Model, Model, Path], tuple[str, Path]]
|
21
19
|
|
22
20
|
|
23
|
-
def
|
24
|
-
|
21
|
+
def _latex_view(expr: sympy.Expr | None) -> str:
|
22
|
+
if expr is None:
|
23
|
+
return "<span style='color:red'>PARSE ERROR<span>"
|
24
|
+
return f"${sympy.latex(expr)}$"
|
25
25
|
|
26
26
|
|
27
27
|
def _new_removed_changed[T](
|
@@ -44,48 +44,71 @@ def _table_header(items: list[str]) -> str:
|
|
44
44
|
return f"{_table_row(items)}\n{_table_row(['---'] * len(items))}"
|
45
45
|
|
46
46
|
|
47
|
+
@dataclass
|
48
|
+
class MarkdownReport:
|
49
|
+
"""Report of model comparison."""
|
50
|
+
|
51
|
+
data: str
|
52
|
+
|
53
|
+
def __str__(self) -> str:
|
54
|
+
"""Markdown string representation."""
|
55
|
+
return self.data
|
56
|
+
|
57
|
+
def __repr__(self) -> str:
|
58
|
+
"""Markdown string representation."""
|
59
|
+
return self.data
|
60
|
+
|
61
|
+
def _repr_markdown_(self) -> str:
|
62
|
+
return self.data
|
63
|
+
|
64
|
+
def write(self, path: Path) -> None:
|
65
|
+
"""Write report to file."""
|
66
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
67
|
+
|
68
|
+
with path.open("w+") as fp:
|
69
|
+
fp.write(self.data)
|
70
|
+
|
71
|
+
|
47
72
|
def markdown(
|
48
73
|
m1: Model,
|
49
74
|
m2: Model,
|
75
|
+
*,
|
50
76
|
analyses: list[AnalysisFn] | None = None,
|
51
77
|
rel_change: float = 1e-2,
|
52
78
|
img_path: Path = Path(),
|
53
|
-
|
79
|
+
m1_name: str = "model 1",
|
80
|
+
m2_name: str = "model 2",
|
81
|
+
include_rhs: bool = True,
|
82
|
+
) -> MarkdownReport:
|
54
83
|
"""Generate a markdown report comparing two models.
|
55
84
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
The
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
>>> # With custom analysis function
|
84
|
-
>>> def custom_analysis(m1, m2, path):
|
85
|
-
... return "## Custom analysis", path / "image.png"
|
86
|
-
>>> report = markdown(m1, m2, analyses=[custom_analysis])
|
87
|
-
>>> "Custom analysis" in report
|
88
|
-
True
|
85
|
+
Args:
|
86
|
+
m1: The first model to compare
|
87
|
+
m2: The second model to compare
|
88
|
+
analyses: A list of functions that analyze both models and return a report section with image
|
89
|
+
rel_change: The relative change threshold for numerical differences
|
90
|
+
img_path: The path to save images
|
91
|
+
m1_name: Name of the first model
|
92
|
+
m2_name: Name of the second model
|
93
|
+
include_rhs: Whether to include numerical differences in the right hand side
|
94
|
+
|
95
|
+
Returns:
|
96
|
+
str: Markdown formatted report comparing the two models
|
97
|
+
|
98
|
+
Examples:
|
99
|
+
>>> from mxlpy import Model
|
100
|
+
>>> m1 = Model().add_parameter("k1", 0.1).add_variable("S", 1.0)
|
101
|
+
>>> m2 = Model().add_parameter("k1", 0.2).add_variable("S", 1.0)
|
102
|
+
>>> report = markdown(m1, m2)
|
103
|
+
>>> "Parameters" in report and "k1" in report
|
104
|
+
True
|
105
|
+
|
106
|
+
>>> # With custom analysis function
|
107
|
+
>>> def custom_analysis(m1, m2, path):
|
108
|
+
... return "## Custom analysis", path / "image.png"
|
109
|
+
>>> report = markdown(m1, m2, analyses=[custom_analysis])
|
110
|
+
>>> "Custom analysis" in report
|
111
|
+
True
|
89
112
|
|
90
113
|
"""
|
91
114
|
content: list[str] = [
|
@@ -101,20 +124,20 @@ def markdown(
|
|
101
124
|
# Model stats
|
102
125
|
content.extend(
|
103
126
|
[
|
104
|
-
"| Model component |
|
127
|
+
f"| Model component | {m1_name} | {m2_name} |",
|
105
128
|
"| --- | --- | --- |",
|
106
|
-
f"| variables | {len(m1.
|
107
|
-
f"| parameters | {len(m1.
|
108
|
-
f"| derived parameters | {len(m1.
|
109
|
-
f"| derived variables | {len(m1.
|
110
|
-
f"| reactions | {len(m1.
|
129
|
+
f"| variables | {len(m1.get_raw_parameters())} | {len(m2.get_raw_parameters())}|",
|
130
|
+
f"| parameters | {len(m1.get_parameter_values())} | {len(m2.get_parameter_values())}|",
|
131
|
+
f"| derived parameters | {len(m1.get_derived_parameters())} | {len(m2.get_derived_parameters())}|",
|
132
|
+
f"| derived variables | {len(m1.get_derived_variables())} | {len(m2.get_derived_variables())}|",
|
133
|
+
f"| reactions | {len(m1.get_raw_reactions())} | {len(m2.get_raw_reactions())}|",
|
111
134
|
f"| surrogates | {len(m1._surrogates)} | {len(m2._surrogates)}|", # noqa: SLF001
|
112
135
|
]
|
113
136
|
)
|
114
137
|
|
115
138
|
# Variables
|
116
139
|
new_variables, removed_variables, changed_variables = _new_removed_changed(
|
117
|
-
m1.
|
140
|
+
m1.get_initial_conditions(), m2.get_initial_conditions()
|
118
141
|
)
|
119
142
|
variables = []
|
120
143
|
variables.extend(
|
@@ -131,8 +154,8 @@ def markdown(
|
|
131
154
|
if len(variables) >= 1:
|
132
155
|
content.extend(
|
133
156
|
(
|
134
|
-
"## Variables\n
|
135
|
-
"| Name |
|
157
|
+
"\n## Variables\n",
|
158
|
+
f"| Name | {m1_name} | {m2_name} |",
|
136
159
|
"| ---- | --------- | --------- |",
|
137
160
|
)
|
138
161
|
)
|
@@ -140,7 +163,7 @@ def markdown(
|
|
140
163
|
|
141
164
|
# Parameters
|
142
165
|
new_parameters, removed_parameters, changed_parameters = _new_removed_changed(
|
143
|
-
m1.
|
166
|
+
m1.get_parameter_values(), m2.get_parameter_values()
|
144
167
|
)
|
145
168
|
pars = []
|
146
169
|
pars.extend(
|
@@ -157,8 +180,8 @@ def markdown(
|
|
157
180
|
if len(pars) >= 1:
|
158
181
|
content.extend(
|
159
182
|
(
|
160
|
-
"## Parameters\n
|
161
|
-
"| Name |
|
183
|
+
"\n## Parameters\n",
|
184
|
+
f"| Name | {m1_name} | {m2_name} |",
|
162
185
|
"| ---- | --------- | --------- |",
|
163
186
|
)
|
164
187
|
)
|
@@ -166,17 +189,37 @@ def markdown(
|
|
166
189
|
|
167
190
|
# Derived
|
168
191
|
new_derived, removed_derived, changed_derived = _new_removed_changed(
|
169
|
-
m1.
|
192
|
+
m1.get_raw_derived(),
|
193
|
+
m2.get_raw_derived(),
|
170
194
|
)
|
171
195
|
derived = []
|
172
196
|
for k, v in new_derived.items():
|
173
|
-
expr =
|
174
|
-
|
197
|
+
expr = _latex_view(
|
198
|
+
fn_to_sympy(
|
199
|
+
v.fn,
|
200
|
+
origin=k,
|
201
|
+
model_args=list_of_symbols(v.args),
|
202
|
+
)
|
203
|
+
)
|
204
|
+
derived.append(f"| <span style='color:green'>{k}<span> | - | {expr} |")
|
205
|
+
|
175
206
|
for k, (v1, v2) in changed_derived.items():
|
176
|
-
expr1 =
|
177
|
-
|
207
|
+
expr1 = _latex_view(
|
208
|
+
fn_to_sympy(
|
209
|
+
v1.fn,
|
210
|
+
origin=k,
|
211
|
+
model_args=list_of_symbols(v1.args),
|
212
|
+
)
|
213
|
+
)
|
214
|
+
expr2 = _latex_view(
|
215
|
+
fn_to_sympy(
|
216
|
+
v2.fn,
|
217
|
+
origin=k,
|
218
|
+
model_args=list_of_symbols(v2.args),
|
219
|
+
)
|
220
|
+
)
|
178
221
|
derived.append(
|
179
|
-
f"| <span style='color: orange'>{k}</span> |
|
222
|
+
f"| <span style='color: orange'>{k}</span> | {expr1} | {expr2} |"
|
180
223
|
)
|
181
224
|
derived.extend(
|
182
225
|
f"| <span style='color:red'>{k}</span> | - | - |" for k in removed_derived
|
@@ -184,8 +227,8 @@ def markdown(
|
|
184
227
|
if len(derived) >= 1:
|
185
228
|
content.extend(
|
186
229
|
(
|
187
|
-
"## Derived\n
|
188
|
-
"| Name |
|
230
|
+
"\n## Derived\n",
|
231
|
+
f"| Name | {m1_name} | {m2_name} |",
|
189
232
|
"| ---- | --------- | --------- |",
|
190
233
|
)
|
191
234
|
)
|
@@ -193,17 +236,36 @@ def markdown(
|
|
193
236
|
|
194
237
|
# Reactions
|
195
238
|
new_reactions, removed_reactions, changed_reactions = _new_removed_changed(
|
196
|
-
m1.
|
239
|
+
m1.get_raw_reactions(), m2.get_raw_reactions()
|
197
240
|
)
|
198
241
|
reactions = []
|
199
242
|
for k, v in new_reactions.items():
|
200
|
-
expr =
|
201
|
-
|
243
|
+
expr = _latex_view(
|
244
|
+
fn_to_sympy(
|
245
|
+
v.fn,
|
246
|
+
origin=k,
|
247
|
+
model_args=list_of_symbols(v.args),
|
248
|
+
)
|
249
|
+
)
|
250
|
+
reactions.append(f"| <span style='color:green'>{k}<span> | - | {expr} |")
|
251
|
+
|
202
252
|
for k, (v1, v2) in changed_reactions.items():
|
203
|
-
expr1 =
|
204
|
-
|
253
|
+
expr1 = _latex_view(
|
254
|
+
fn_to_sympy(
|
255
|
+
v1.fn,
|
256
|
+
origin=k,
|
257
|
+
model_args=list_of_symbols(v1.args),
|
258
|
+
)
|
259
|
+
)
|
260
|
+
expr2 = _latex_view(
|
261
|
+
fn_to_sympy(
|
262
|
+
v2.fn,
|
263
|
+
origin=k,
|
264
|
+
model_args=list_of_symbols(v2.args),
|
265
|
+
)
|
266
|
+
)
|
205
267
|
reactions.append(
|
206
|
-
f"| <span style='color: orange'>{k}</span> |
|
268
|
+
f"| <span style='color: orange'>{k}</span> | {expr1} | {expr2} |"
|
207
269
|
)
|
208
270
|
reactions.extend(
|
209
271
|
f"| <span style='color:red'>{k}</span> | - | - |" for k in removed_reactions
|
@@ -212,8 +274,8 @@ def markdown(
|
|
212
274
|
if len(reactions) >= 1:
|
213
275
|
content.extend(
|
214
276
|
(
|
215
|
-
"## Reactions\n
|
216
|
-
"| Name |
|
277
|
+
"\n## Reactions\n",
|
278
|
+
f"| Name | {m1_name} | {m2_name} |",
|
217
279
|
"| ---- | --------- | --------- |",
|
218
280
|
)
|
219
281
|
)
|
@@ -221,8 +283,8 @@ def markdown(
|
|
221
283
|
|
222
284
|
# Now check for any numerical differences
|
223
285
|
dependent = []
|
224
|
-
d1 = m1.
|
225
|
-
d2 = m2.
|
286
|
+
d1 = m1.get_args()
|
287
|
+
d2 = m2.get_args()
|
226
288
|
rel_diff = ((d1 - d2) / d1).dropna()
|
227
289
|
for k, v in rel_diff.loc[rel_diff.abs() >= rel_change].items():
|
228
290
|
k = cast(str, k)
|
@@ -233,30 +295,31 @@ def markdown(
|
|
233
295
|
content.extend(
|
234
296
|
(
|
235
297
|
"## Numerical differences of dependent values\n\n",
|
236
|
-
"| Name |
|
298
|
+
f"| Name | {m1_name} | {m2_name} | Relative Change | ",
|
237
299
|
"| ---- | --------- | --------- | --------------- | ",
|
238
300
|
)
|
239
301
|
)
|
240
302
|
content.append("\n".join(dependent))
|
241
303
|
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
k
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
if len(rhs) >= 1:
|
252
|
-
content.extend(
|
253
|
-
(
|
254
|
-
"## Numerical differences of right hand side values\n\n",
|
255
|
-
"| Name | Old Value | New Value | Relative Change | ",
|
256
|
-
"| ---- | --------- | --------- | --------------- | ",
|
304
|
+
if include_rhs:
|
305
|
+
rhs = []
|
306
|
+
r1 = m1.get_right_hand_side()
|
307
|
+
r2 = m2.get_right_hand_side()
|
308
|
+
rel_diff = ((r1 - r2) / r1).dropna()
|
309
|
+
for k, v in rel_diff.loc[rel_diff.abs() >= rel_change].items():
|
310
|
+
k = cast(str, k)
|
311
|
+
rhs.append(
|
312
|
+
f"| <span style='color:orange'>{k}</span> | {r1[k]:.2f} | {r2[k]:.2f} | {v:.1%} |"
|
257
313
|
)
|
258
|
-
)
|
259
|
-
|
314
|
+
if len(rhs) >= 1:
|
315
|
+
content.extend(
|
316
|
+
(
|
317
|
+
"\n## Numerical differences of right hand side values\n",
|
318
|
+
f"| Name | {m1_name} | {m2_name} | Relative Change | ",
|
319
|
+
"| ---- | --------- | --------- | --------------- | ",
|
320
|
+
)
|
321
|
+
)
|
322
|
+
content.append("\n".join(rhs))
|
260
323
|
|
261
324
|
# Comparison functions
|
262
325
|
if analyses is not None:
|
@@ -266,4 +329,4 @@ def markdown(
|
|
266
329
|
# content.append(f"")
|
267
330
|
content.append(f"<img src='{img_path}' alt='{name}' width='500'/>")
|
268
331
|
|
269
|
-
return "\n".join(content)
|
332
|
+
return MarkdownReport(data="\n".join(content))
|
mxlpy/sbml/_export.py
CHANGED
@@ -440,30 +440,32 @@ def _create_sbml_variables(
|
|
440
440
|
sbml_model : libsbml.Model
|
441
441
|
|
442
442
|
"""
|
443
|
-
for name,
|
443
|
+
for name, variable in model.get_raw_variables().items():
|
444
444
|
cpd = sbml_model.createSpecies()
|
445
445
|
cpd.setId(_convert_id_to_sbml(id_=name, prefix="CPD"))
|
446
446
|
|
447
447
|
cpd.setConstant(False)
|
448
448
|
cpd.setBoundaryCondition(False)
|
449
449
|
cpd.setHasOnlySubstanceUnits(False)
|
450
|
-
|
450
|
+
# cpd.setUnit() # FIXME: implement
|
451
|
+
if isinstance((init := variable.initial_value), Derived):
|
451
452
|
ar = sbml_model.createInitialAssignment()
|
452
453
|
ar.setId(_convert_id_to_sbml(id_=name, prefix="IA"))
|
453
454
|
ar.setName(_convert_id_to_sbml(id_=name, prefix="IA"))
|
454
455
|
ar.setVariable(_convert_id_to_sbml(id_=name, prefix="IA"))
|
455
|
-
ar.setMath(_sbmlify_fn(
|
456
|
+
ar.setMath(_sbmlify_fn(init.fn, init.args))
|
456
457
|
else:
|
457
|
-
cpd.setInitialAmount(float(
|
458
|
+
cpd.setInitialAmount(float(init))
|
458
459
|
|
459
460
|
|
460
461
|
def _create_sbml_derived_variables(*, model: Model, sbml_model: libsbml.Model) -> None:
|
461
|
-
for name, dv in model.
|
462
|
+
for name, dv in model.get_derived_variables().items():
|
462
463
|
sbml_ar = sbml_model.createAssignmentRule()
|
463
464
|
sbml_ar.setId(_convert_id_to_sbml(id_=name, prefix="AR"))
|
464
465
|
sbml_ar.setName(_convert_id_to_sbml(id_=name, prefix="AR"))
|
465
466
|
sbml_ar.setVariable(_convert_id_to_sbml(id_=name, prefix="AR"))
|
466
467
|
sbml_ar.setMath(_sbmlify_fn(dv.fn, dv.args))
|
468
|
+
# cpd.setUnit() # FIXME: implement
|
467
469
|
|
468
470
|
|
469
471
|
def _create_derived_parameter(
|
@@ -477,6 +479,7 @@ def _create_derived_parameter(
|
|
477
479
|
ar.setName(_convert_id_to_sbml(id_=name, prefix="AR"))
|
478
480
|
ar.setVariable(_convert_id_to_sbml(id_=name, prefix="AR"))
|
479
481
|
ar.setMath(_sbmlify_fn(dp.fn, dp.args))
|
482
|
+
# cpd.setUnit() # FIXME: implement
|
480
483
|
|
481
484
|
|
482
485
|
def _create_sbml_parameters(
|
@@ -491,7 +494,7 @@ def _create_sbml_parameters(
|
|
491
494
|
sbml_model : libsbml.Model
|
492
495
|
|
493
496
|
"""
|
494
|
-
for parameter_id, value in model.
|
497
|
+
for parameter_id, value in model.get_parameter_values().items():
|
495
498
|
k = sbml_model.createParameter()
|
496
499
|
k.setId(_convert_id_to_sbml(id_=parameter_id, prefix="PAR"))
|
497
500
|
k.setConstant(True)
|
@@ -499,7 +502,7 @@ def _create_sbml_parameters(
|
|
499
502
|
|
500
503
|
|
501
504
|
def _create_sbml_derived_parameters(*, model: Model, sbml_model: libsbml.Model) -> None:
|
502
|
-
for name, dp in model.
|
505
|
+
for name, dp in model.get_derived_parameters().items():
|
503
506
|
_create_derived_parameter(sbml_model, name, dp)
|
504
507
|
|
505
508
|
|
@@ -509,7 +512,7 @@ def _create_sbml_reactions(
|
|
509
512
|
sbml_model: libsbml.Model,
|
510
513
|
) -> None:
|
511
514
|
"""Create the reactions for the sbml model."""
|
512
|
-
for name, rxn in model.
|
515
|
+
for name, rxn in model.get_raw_reactions().items():
|
513
516
|
sbml_rxn = sbml_model.createReaction()
|
514
517
|
sbml_rxn.setId(_convert_id_to_sbml(id_=name, prefix="RXN"))
|
515
518
|
sbml_rxn.setName(name)
|
mxlpy/sbml/_import.py
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
+
import logging
|
3
4
|
import math # noqa: F401 # models might need it
|
4
5
|
import re
|
5
|
-
import warnings
|
6
6
|
from collections import defaultdict
|
7
7
|
from dataclasses import dataclass, field
|
8
8
|
from pathlib import Path
|
@@ -32,6 +32,8 @@ from mxlpy.types import unwrap
|
|
32
32
|
if TYPE_CHECKING:
|
33
33
|
from collections.abc import Callable
|
34
34
|
|
35
|
+
_LOGGER = logging.getLogger(__name__)
|
36
|
+
|
35
37
|
__all__ = [
|
36
38
|
"INDENT",
|
37
39
|
"OPERATOR_MAPPINGS",
|
@@ -216,10 +218,8 @@ class Parser:
|
|
216
218
|
|
217
219
|
node = assignment.getMath()
|
218
220
|
if node is None:
|
219
|
-
|
220
|
-
|
221
|
-
stacklevel=1,
|
222
|
-
)
|
221
|
+
msg = f"Unusable math for {name}"
|
222
|
+
_LOGGER.warning(msg)
|
223
223
|
continue
|
224
224
|
|
225
225
|
body, args = parse_sbml_math(node)
|
@@ -493,7 +493,7 @@ def _codgen(name: str, sbml: Parser) -> Path:
|
|
493
493
|
variables[k] = v.size
|
494
494
|
|
495
495
|
# Ensure non-zero value for initial assignments
|
496
|
-
# EXPLAIN: we need to do this for the first round of
|
496
|
+
# EXPLAIN: we need to do this for the first round of get_args to work
|
497
497
|
# otherwise we run into a ton of DivisionByZero errors.
|
498
498
|
# Since the values are overwritte afterwards, it doesn't really matter anyways
|
499
499
|
for k in sbml.initial_assignment:
|
@@ -552,7 +552,7 @@ def get_model() -> Model:
|
|
552
552
|
{variables_str}
|
553
553
|
{derived_str}
|
554
554
|
{rxn_str}
|
555
|
-
args = m.
|
555
|
+
args = m.get_args()
|
556
556
|
{initial_assignment_source}
|
557
557
|
return m
|
558
558
|
"""
|