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/label_map.py
CHANGED
@@ -551,13 +551,13 @@ class LabelMapper:
|
|
551
551
|
|
552
552
|
m = Model()
|
553
553
|
|
554
|
-
m.add_parameters(self.model.
|
554
|
+
m.add_parameters(self.model.get_parameter_values())
|
555
555
|
|
556
|
-
for name, dp in self.model.
|
556
|
+
for name, dp in self.model.get_derived_parameters().items():
|
557
557
|
m.add_derived(name, fn=dp.fn, args=dp.args)
|
558
558
|
|
559
559
|
variables: dict[str, float | Derived] = {}
|
560
|
-
for k, v in self.model.
|
560
|
+
for k, v in self.model.get_initial_conditions().items():
|
561
561
|
if (isos := isotopomers.get(k)) is None:
|
562
562
|
variables[k] = v
|
563
563
|
else:
|
@@ -585,14 +585,14 @@ class LabelMapper:
|
|
585
585
|
args=label_names,
|
586
586
|
)
|
587
587
|
|
588
|
-
for name, dv in self.model.
|
588
|
+
for name, dv in self.model.get_derived_variables().items():
|
589
589
|
m.add_derived(
|
590
590
|
name,
|
591
591
|
fn=dv.fn,
|
592
592
|
args=[f"{i}__total" if i in isotopomers else i for i in dv.args],
|
593
593
|
)
|
594
594
|
|
595
|
-
for rxn_name, rxn in self.model.
|
595
|
+
for rxn_name, rxn in self.model.get_raw_reactions().items():
|
596
596
|
if (label_map := self.label_maps.get(rxn_name)) is None:
|
597
597
|
m.add_reaction(
|
598
598
|
rxn_name,
|
mxlpy/linear_label_map.py
CHANGED
@@ -272,8 +272,10 @@ class LinearLabelMapper:
|
|
272
272
|
m = Model()
|
273
273
|
m.add_variables(variables)
|
274
274
|
m.add_parameters(concs.to_dict() | fluxes.to_dict() | {"EXT": external_label})
|
275
|
+
|
276
|
+
rxns = self.model.get_raw_reactions()
|
275
277
|
for rxn_name, label_map in self.label_maps.items():
|
276
|
-
rxn =
|
278
|
+
rxn = rxns[rxn_name]
|
277
279
|
subs, prods = _unpack_stoichiometries(rxn.stoichiometry)
|
278
280
|
|
279
281
|
subs = _stoichiometry_to_duplicate_list(subs)
|
mxlpy/mc.py
CHANGED
@@ -22,7 +22,6 @@ from typing import TYPE_CHECKING, Protocol, cast
|
|
22
22
|
import pandas as pd
|
23
23
|
|
24
24
|
from mxlpy import mca, scan
|
25
|
-
from mxlpy.integrators import DefaultIntegrator
|
26
25
|
from mxlpy.parallel import Cache, parallelise
|
27
26
|
from mxlpy.scan import (
|
28
27
|
ProtocolWorker,
|
@@ -67,6 +66,7 @@ class ParameterScanWorker(Protocol):
|
|
67
66
|
model: Model,
|
68
67
|
*,
|
69
68
|
parameters: pd.DataFrame,
|
69
|
+
y0: dict[str, float] | None,
|
70
70
|
rel_norm: bool,
|
71
71
|
integrator: IntegratorType,
|
72
72
|
) -> SteadyStates:
|
@@ -78,6 +78,7 @@ def _parameter_scan_worker(
|
|
78
78
|
model: Model,
|
79
79
|
*,
|
80
80
|
parameters: pd.DataFrame,
|
81
|
+
y0: dict[str, float] | None,
|
81
82
|
rel_norm: bool,
|
82
83
|
integrator: IntegratorType,
|
83
84
|
) -> SteadyStates:
|
@@ -110,6 +111,7 @@ def _parameter_scan_worker(
|
|
110
111
|
parallel=False,
|
111
112
|
rel_norm=rel_norm,
|
112
113
|
integrator=integrator,
|
114
|
+
y0=y0,
|
113
115
|
)
|
114
116
|
|
115
117
|
|
@@ -122,7 +124,7 @@ def steady_state(
|
|
122
124
|
cache: Cache | None = None,
|
123
125
|
rel_norm: bool = False,
|
124
126
|
worker: SteadyStateWorker = _steady_state_worker,
|
125
|
-
integrator: IntegratorType =
|
127
|
+
integrator: IntegratorType | None = None,
|
126
128
|
) -> SteadyStates:
|
127
129
|
"""Monte-carlo scan of steady states.
|
128
130
|
|
@@ -153,6 +155,7 @@ def steady_state(
|
|
153
155
|
worker,
|
154
156
|
rel_norm=rel_norm,
|
155
157
|
integrator=integrator,
|
158
|
+
y0=None,
|
156
159
|
),
|
157
160
|
model=model,
|
158
161
|
),
|
@@ -161,8 +164,8 @@ def steady_state(
|
|
161
164
|
cache=cache,
|
162
165
|
)
|
163
166
|
return SteadyStates(
|
164
|
-
variables=pd.concat({k: v.variables for k, v in res
|
165
|
-
fluxes=pd.concat({k: v.fluxes for k, v in res
|
167
|
+
variables=pd.concat({k: v.variables for k, v in res}, axis=1).T,
|
168
|
+
fluxes=pd.concat({k: v.fluxes for k, v in res}, axis=1).T,
|
166
169
|
parameters=mc_to_scan,
|
167
170
|
)
|
168
171
|
|
@@ -176,7 +179,7 @@ def time_course(
|
|
176
179
|
max_workers: int | None = None,
|
177
180
|
cache: Cache | None = None,
|
178
181
|
worker: TimeCourseWorker = _time_course_worker,
|
179
|
-
integrator: IntegratorType =
|
182
|
+
integrator: IntegratorType | None = None,
|
180
183
|
) -> TimeCourseByPars:
|
181
184
|
"""MC time course.
|
182
185
|
|
@@ -207,6 +210,7 @@ def time_course(
|
|
207
210
|
worker,
|
208
211
|
time_points=time_points,
|
209
212
|
integrator=integrator,
|
213
|
+
y0=None,
|
210
214
|
),
|
211
215
|
model=model,
|
212
216
|
),
|
@@ -217,8 +221,8 @@ def time_course(
|
|
217
221
|
|
218
222
|
return TimeCourseByPars(
|
219
223
|
parameters=mc_to_scan,
|
220
|
-
variables=pd.concat({k: v.variables.T for k, v in res
|
221
|
-
fluxes=pd.concat({k: v.fluxes.T for k, v in res
|
224
|
+
variables=pd.concat({k: v.variables.T for k, v in res}, axis=1).T,
|
225
|
+
fluxes=pd.concat({k: v.fluxes.T for k, v in res}, axis=1).T,
|
222
226
|
)
|
223
227
|
|
224
228
|
|
@@ -232,7 +236,7 @@ def time_course_over_protocol(
|
|
232
236
|
max_workers: int | None = None,
|
233
237
|
cache: Cache | None = None,
|
234
238
|
worker: ProtocolWorker = _protocol_worker,
|
235
|
-
integrator: IntegratorType =
|
239
|
+
integrator: IntegratorType | None = None,
|
236
240
|
) -> ProtocolByPars:
|
237
241
|
"""MC time course.
|
238
242
|
|
@@ -264,6 +268,7 @@ def time_course_over_protocol(
|
|
264
268
|
worker,
|
265
269
|
protocol=protocol,
|
266
270
|
integrator=integrator,
|
271
|
+
y0=None,
|
267
272
|
time_points_per_step=time_points_per_step,
|
268
273
|
),
|
269
274
|
model=model,
|
@@ -272,8 +277,8 @@ def time_course_over_protocol(
|
|
272
277
|
max_workers=max_workers,
|
273
278
|
cache=cache,
|
274
279
|
)
|
275
|
-
concs = {k: v.variables.T for k, v in res
|
276
|
-
fluxes = {k: v.fluxes.T for k, v in res
|
280
|
+
concs = {k: v.variables.T for k, v in res}
|
281
|
+
fluxes = {k: v.fluxes.T for k, v in res}
|
277
282
|
return ProtocolByPars(
|
278
283
|
variables=pd.concat(concs, axis=1).T,
|
279
284
|
fluxes=pd.concat(fluxes, axis=1).T,
|
@@ -292,7 +297,7 @@ def scan_steady_state(
|
|
292
297
|
cache: Cache | None = None,
|
293
298
|
rel_norm: bool = False,
|
294
299
|
worker: ParameterScanWorker = _parameter_scan_worker,
|
295
|
-
integrator: IntegratorType =
|
300
|
+
integrator: IntegratorType | None = None,
|
296
301
|
) -> McSteadyStates:
|
297
302
|
"""Parameter scan of mc distributed steady states.
|
298
303
|
|
@@ -339,6 +344,7 @@ def scan_steady_state(
|
|
339
344
|
parameters=to_scan,
|
340
345
|
rel_norm=rel_norm,
|
341
346
|
integrator=integrator,
|
347
|
+
y0=None,
|
342
348
|
),
|
343
349
|
model=model,
|
344
350
|
),
|
@@ -346,8 +352,8 @@ def scan_steady_state(
|
|
346
352
|
cache=cache,
|
347
353
|
max_workers=max_workers,
|
348
354
|
)
|
349
|
-
concs = {k: v.variables.T for k, v in res
|
350
|
-
fluxes = {k: v.fluxes.T for k, v in res
|
355
|
+
concs = {k: v.variables.T for k, v in res}
|
356
|
+
fluxes = {k: v.fluxes.T for k, v in res}
|
351
357
|
return McSteadyStates(
|
352
358
|
variables=pd.concat(concs, axis=1).T,
|
353
359
|
fluxes=pd.concat(fluxes, axis=1).T,
|
@@ -422,7 +428,7 @@ def variable_elasticities(
|
|
422
428
|
cache=cache,
|
423
429
|
max_workers=max_workers,
|
424
430
|
)
|
425
|
-
return cast(pd.DataFrame, pd.concat(res))
|
431
|
+
return cast(pd.DataFrame, pd.concat(dict(res)))
|
426
432
|
|
427
433
|
|
428
434
|
def parameter_elasticities(
|
@@ -486,7 +492,7 @@ def parameter_elasticities(
|
|
486
492
|
cache=cache,
|
487
493
|
max_workers=max_workers,
|
488
494
|
)
|
489
|
-
return cast(pd.DataFrame, pd.concat(res))
|
495
|
+
return cast(pd.DataFrame, pd.concat(dict(res)))
|
490
496
|
|
491
497
|
|
492
498
|
def response_coefficients(
|
@@ -501,7 +507,7 @@ def response_coefficients(
|
|
501
507
|
disable_tqdm: bool = False,
|
502
508
|
max_workers: int | None = None,
|
503
509
|
rel_norm: bool = False,
|
504
|
-
integrator: IntegratorType =
|
510
|
+
integrator: IntegratorType | None = None,
|
505
511
|
) -> ResponseCoefficientsByPars:
|
506
512
|
"""Calculate response coefficients using Monte Carlo analysis.
|
507
513
|
|
@@ -558,9 +564,7 @@ def response_coefficients(
|
|
558
564
|
)
|
559
565
|
|
560
566
|
return ResponseCoefficientsByPars(
|
561
|
-
variables=cast(
|
562
|
-
|
563
|
-
),
|
564
|
-
fluxes=cast(pd.DataFrame, pd.concat({k: v.fluxes for k, v in res.items()})),
|
567
|
+
variables=cast(pd.DataFrame, pd.concat({k: v.variables for k, v in res})),
|
568
|
+
fluxes=cast(pd.DataFrame, pd.concat({k: v.fluxes for k, v in res})),
|
565
569
|
parameters=mc_to_scan,
|
566
570
|
)
|
mxlpy/mca.py
CHANGED
@@ -22,7 +22,6 @@ from typing import TYPE_CHECKING
|
|
22
22
|
|
23
23
|
import pandas as pd
|
24
24
|
|
25
|
-
from mxlpy.integrators import DefaultIntegrator
|
26
25
|
from mxlpy.parallel import parallelise
|
27
26
|
from mxlpy.scan import _steady_state_worker
|
28
27
|
from mxlpy.types import ResponseCoefficients
|
@@ -46,7 +45,7 @@ def _response_coefficient_worker(
|
|
46
45
|
normalized: bool,
|
47
46
|
rel_norm: bool,
|
48
47
|
displacement: float = 1e-4,
|
49
|
-
integrator: IntegratorType,
|
48
|
+
integrator: IntegratorType | None,
|
50
49
|
) -> tuple[pd.Series, pd.Series]:
|
51
50
|
"""Calculate response coefficients for a single parameter.
|
52
51
|
|
@@ -72,7 +71,7 @@ def _response_coefficient_worker(
|
|
72
71
|
- Series of flux response coefficients
|
73
72
|
|
74
73
|
"""
|
75
|
-
old = model.
|
74
|
+
old = model.get_parameter_values()[parameter]
|
76
75
|
if y0 is not None:
|
77
76
|
model.update_variables(y0)
|
78
77
|
|
@@ -81,6 +80,7 @@ def _response_coefficient_worker(
|
|
81
80
|
model,
|
82
81
|
rel_norm=rel_norm,
|
83
82
|
integrator=integrator,
|
83
|
+
y0=None,
|
84
84
|
)
|
85
85
|
|
86
86
|
model.update_parameters({parameter: old * (1 - displacement)})
|
@@ -88,6 +88,7 @@ def _response_coefficient_worker(
|
|
88
88
|
model,
|
89
89
|
rel_norm=rel_norm,
|
90
90
|
integrator=integrator,
|
91
|
+
y0=None,
|
91
92
|
)
|
92
93
|
|
93
94
|
conc_resp = (upper.variables - lower.variables) / (2 * displacement * old)
|
@@ -99,6 +100,7 @@ def _response_coefficient_worker(
|
|
99
100
|
model,
|
100
101
|
rel_norm=rel_norm,
|
101
102
|
integrator=integrator,
|
103
|
+
y0=None,
|
102
104
|
)
|
103
105
|
conc_resp *= old / norm.variables
|
104
106
|
flux_resp *= old / norm.fluxes
|
@@ -203,7 +205,7 @@ def parameter_elasticities(
|
|
203
205
|
|
204
206
|
variables = model.get_initial_conditions() if variables is None else variables
|
205
207
|
for par in to_scan:
|
206
|
-
old = model.
|
208
|
+
old = model.get_parameter_values()[par]
|
207
209
|
|
208
210
|
model.update_parameters({par: old * (1 + displacement)})
|
209
211
|
upper = model.get_fluxes(variables=variables, time=time)
|
@@ -237,7 +239,7 @@ def response_coefficients(
|
|
237
239
|
parallel: bool = True,
|
238
240
|
max_workers: int | None = None,
|
239
241
|
rel_norm: bool = False,
|
240
|
-
integrator: IntegratorType =
|
242
|
+
integrator: IntegratorType | None = None,
|
241
243
|
) -> ResponseCoefficients:
|
242
244
|
"""Calculate response coefficients.
|
243
245
|
|
@@ -284,6 +286,6 @@ def response_coefficients(
|
|
284
286
|
max_workers=max_workers,
|
285
287
|
)
|
286
288
|
return ResponseCoefficients(
|
287
|
-
variables=pd.DataFrame({k: v[0] for k, v in res
|
288
|
-
fluxes=pd.DataFrame({k: v[1] for k, v in res
|
289
|
+
variables=pd.DataFrame({k: v[0] for k, v in res}),
|
290
|
+
fluxes=pd.DataFrame({k: v[1] for k, v in res}),
|
289
291
|
)
|
mxlpy/meta/__init__.py
CHANGED
@@ -2,12 +2,14 @@
|
|
2
2
|
|
3
3
|
from __future__ import annotations
|
4
4
|
|
5
|
-
from .codegen_latex import generate_latex_code
|
6
|
-
from .
|
7
|
-
from .
|
5
|
+
from .codegen_latex import generate_latex_code, to_tex_export
|
6
|
+
from .codegen_model import generate_model_code_py, generate_model_code_rs
|
7
|
+
from .codegen_mxlpy import generate_mxlpy_code
|
8
8
|
|
9
9
|
__all__ = [
|
10
10
|
"generate_latex_code",
|
11
11
|
"generate_model_code_py",
|
12
|
+
"generate_model_code_rs",
|
12
13
|
"generate_mxlpy_code",
|
14
|
+
"to_tex_export",
|
13
15
|
]
|
mxlpy/meta/codegen_latex.py
CHANGED
@@ -7,7 +7,7 @@ from typing import TYPE_CHECKING
|
|
7
7
|
|
8
8
|
import sympy
|
9
9
|
|
10
|
-
from mxlpy.meta.
|
10
|
+
from mxlpy.meta.sympy_tools import fn_to_sympy, list_of_symbols
|
11
11
|
from mxlpy.types import Derived, RateFn
|
12
12
|
|
13
13
|
if TYPE_CHECKING:
|
@@ -21,6 +21,7 @@ __all__ = [
|
|
21
21
|
"default_init",
|
22
22
|
"generate_latex_code",
|
23
23
|
"get_model_tex_diff",
|
24
|
+
"to_tex_export",
|
24
25
|
]
|
25
26
|
|
26
27
|
cdot = r"\cdot"
|
@@ -31,10 +32,6 @@ newline = r"\\" + "\n"
|
|
31
32
|
floatbarrier = r"\FloatBarrier"
|
32
33
|
|
33
34
|
|
34
|
-
def _list_of_symbols(args: list[str]) -> list[sympy.Symbol | sympy.Expr]:
|
35
|
-
return [sympy.Symbol(arg) for arg in args]
|
36
|
-
|
37
|
-
|
38
35
|
def default_init[T1, T2](d: dict[T1, T2] | None) -> dict[T1, T2]:
|
39
36
|
"""Return empty dict if d is None.
|
40
37
|
|
@@ -63,10 +60,6 @@ def _gls(s: str) -> str:
|
|
63
60
|
return rf"\gls{{{s}}}"
|
64
61
|
|
65
62
|
|
66
|
-
def _abbrev_and_full(s: str) -> str:
|
67
|
-
return rf"\acrfull{{{s}}}"
|
68
|
-
|
69
|
-
|
70
63
|
def _gls_short(s: str) -> str:
|
71
64
|
return rf"\acrshort{{{s}}}"
|
72
65
|
|
@@ -75,6 +68,10 @@ def _gls_full(s: str) -> str:
|
|
75
68
|
return rf"\acrlong{{{s}}}"
|
76
69
|
|
77
70
|
|
71
|
+
def _gls_short_and_full(s: str) -> str:
|
72
|
+
return rf"\acrfull{{{s}}}"
|
73
|
+
|
74
|
+
|
78
75
|
def _rename_latex(s: str) -> str:
|
79
76
|
if s[0].isdigit():
|
80
77
|
s = s[1:]
|
@@ -109,6 +106,8 @@ def _sympy_to_latex(expr: sympy.Expr) -> str:
|
|
109
106
|
|
110
107
|
def _fn_to_latex(
|
111
108
|
fn: Callable,
|
109
|
+
*,
|
110
|
+
origin: str,
|
112
111
|
arg_names: list[str],
|
113
112
|
long_name_cutoff: int,
|
114
113
|
) -> tuple[str, dict[str, str]]:
|
@@ -121,10 +120,13 @@ def _fn_to_latex(
|
|
121
120
|
replacements = {k: _name_to_latex(f"_x{i}") for i, k in enumerate(long_names)}
|
122
121
|
|
123
122
|
expr = fn_to_sympy(
|
124
|
-
fn,
|
123
|
+
fn,
|
124
|
+
origin=origin,
|
125
|
+
model_args=list_of_symbols([replacements.get(k, k) for k in tex_names]),
|
125
126
|
)
|
126
|
-
|
127
|
-
|
127
|
+
if expr is None:
|
128
|
+
return rf"\textcolor{{red}}{{{origin}}}", replacements
|
129
|
+
return _sympy_to_latex(expr), replacements
|
128
130
|
|
129
131
|
|
130
132
|
def _table(
|
@@ -323,7 +325,8 @@ def _stoichs_to_latex(
|
|
323
325
|
)
|
324
326
|
sympy_fn = fn_to_sympy(
|
325
327
|
rxn_stoich.fn,
|
326
|
-
|
328
|
+
origin=rxn_name,
|
329
|
+
model_args=list_of_symbols([replacements.get(k, k) for k in arg_names]),
|
327
330
|
)
|
328
331
|
expr = expr + sympy_fn * sympy.Symbol(rxn_name) # type: ignore
|
329
332
|
else:
|
@@ -480,7 +483,7 @@ class TexExport:
|
|
480
483
|
|
481
484
|
def _add_gls_if_found(k: str) -> str:
|
482
485
|
if (new := gls.get(k)) is not None:
|
483
|
-
return
|
486
|
+
return _gls_short_and_full(new)
|
484
487
|
return k
|
485
488
|
|
486
489
|
return TexExport(
|
@@ -564,7 +567,7 @@ class TexExport:
|
|
564
567
|
|
565
568
|
def export_derived(
|
566
569
|
self,
|
567
|
-
long_name_cutoff: int,
|
570
|
+
long_name_cutoff: int = 10,
|
568
571
|
) -> str:
|
569
572
|
"""Export derived quantities as LaTeX equations.
|
570
573
|
|
@@ -587,16 +590,20 @@ class TexExport:
|
|
587
590
|
for k, v in sorted(self.derived.items()):
|
588
591
|
fn_str, repls = _fn_to_latex(
|
589
592
|
v.fn,
|
593
|
+
origin=k,
|
590
594
|
arg_names=v.args,
|
591
595
|
long_name_cutoff=long_name_cutoff,
|
592
596
|
)
|
593
|
-
rows.append(f"{_mathrm(_name_to_latex(k))} &= {fn_str} \\\\")
|
597
|
+
rows.append(f" {_mathrm(_name_to_latex(k))} &= {fn_str} \\\\")
|
594
598
|
if repls:
|
595
599
|
rows.append(_replacements_in_align(repls))
|
596
600
|
|
597
601
|
return _latex_align(rows)
|
598
602
|
|
599
|
-
def export_reactions(
|
603
|
+
def export_reactions(
|
604
|
+
self,
|
605
|
+
long_name_cutoff: int = 10,
|
606
|
+
) -> str:
|
600
607
|
"""Export reactions as LaTeX equations.
|
601
608
|
|
602
609
|
Returns
|
@@ -618,17 +625,18 @@ class TexExport:
|
|
618
625
|
for k, v in sorted(self.reactions.items()):
|
619
626
|
fn_str, repls = _fn_to_latex(
|
620
627
|
v.fn,
|
628
|
+
origin=k,
|
621
629
|
arg_names=v.args,
|
622
630
|
long_name_cutoff=long_name_cutoff,
|
623
631
|
)
|
624
|
-
rows.append(f"{_mathrm(_name_to_latex(k))} &= {fn_str} \\\\")
|
632
|
+
rows.append(f" {_mathrm(_name_to_latex(k))} &= {fn_str} \\\\")
|
625
633
|
if repls:
|
626
634
|
rows.append(_replacements_in_align(repls))
|
627
635
|
return _latex_align(rows)
|
628
636
|
|
629
637
|
def export_diff_eqs(
|
630
638
|
self,
|
631
|
-
long_name_cutoff: int,
|
639
|
+
long_name_cutoff: int = 10,
|
632
640
|
) -> str:
|
633
641
|
"""Export stoichiometries as LaTeX table.
|
634
642
|
|
@@ -654,12 +662,15 @@ class TexExport:
|
|
654
662
|
long_name_cutoff=long_name_cutoff,
|
655
663
|
)
|
656
664
|
|
657
|
-
rows.append(f"{dxdt} &= {stoich_str} \\\\")
|
665
|
+
rows.append(f" {dxdt} &= {stoich_str} \\\\")
|
658
666
|
if repls:
|
659
667
|
rows.append(_replacements_in_align(repls))
|
660
668
|
return _latex_align(rows)
|
661
669
|
|
662
|
-
def export_all(
|
670
|
+
def export_all(
|
671
|
+
self,
|
672
|
+
long_name_cutoff: int = 10,
|
673
|
+
) -> str:
|
663
674
|
"""Export all model parts as a complete LaTeX document section.
|
664
675
|
|
665
676
|
Returns
|
@@ -754,7 +765,7 @@ class TexExport:
|
|
754
765
|
\usepackage[a4paper,top=2cm,bottom=2cm,left=2cm,right=2cm,marginparwidth=1.75cm]{{geometry}}
|
755
766
|
\usepackage{{amsmath, amssymb, array, booktabs,
|
756
767
|
breqn, caption, longtable, mathtools, placeins,
|
757
|
-
ragged2e, tabularx, titlesec, titling}}
|
768
|
+
ragged2e, tabularx, titlesec, titling, xcolor}}
|
758
769
|
\newcommand{{\sectionbreak}}{{\clearpage}}
|
759
770
|
\setlength{{\parindent}}{{0pt}}
|
760
771
|
\allowdisplaybreaks
|
@@ -769,17 +780,20 @@ class TexExport:
|
|
769
780
|
"""
|
770
781
|
|
771
782
|
|
772
|
-
def
|
783
|
+
def to_tex_export(model: Model) -> TexExport:
|
784
|
+
"""Create TexExport object from a model."""
|
773
785
|
diff_eqs = {}
|
774
|
-
for rxn_name, rxn in
|
786
|
+
for rxn_name, rxn in model.get_raw_reactions().items():
|
775
787
|
for var_name, factor in rxn.stoichiometry.items():
|
776
788
|
diff_eqs.setdefault(var_name, {})[rxn_name] = factor
|
777
789
|
|
778
790
|
return TexExport(
|
779
|
-
parameters=
|
780
|
-
variables=
|
781
|
-
derived=
|
782
|
-
reactions={
|
791
|
+
parameters=model.get_parameter_values(),
|
792
|
+
variables=model.get_initial_conditions(), # FIXME: think about this later
|
793
|
+
derived=model.get_raw_derived(),
|
794
|
+
reactions={
|
795
|
+
k: TexReaction(v.fn, v.args) for k, v in model.get_raw_reactions().items()
|
796
|
+
},
|
783
797
|
diff_eqs=diff_eqs,
|
784
798
|
)
|
785
799
|
|
@@ -820,7 +834,7 @@ def generate_latex_code(
|
|
820
834
|
"""
|
821
835
|
gls = default_init(gls)
|
822
836
|
return (
|
823
|
-
|
837
|
+
to_tex_export(model)
|
824
838
|
.rename_with_glossary(gls)
|
825
839
|
.export_document(long_name_cutoff=long_name_cutoff)
|
826
840
|
)
|
@@ -866,7 +880,7 @@ def get_model_tex_diff(
|
|
866
880
|
return f"""{" start autogenerated ":%^60}
|
867
881
|
{_clearpage()}
|
868
882
|
{_subsubsection("Model changes")}{_label(section_label)}
|
869
|
-
{((
|
883
|
+
{((to_tex_export(m1) - to_tex_export(m2)).rename_with_glossary(gls).export_all(long_name_cutoff=long_name_cutoff))}
|
870
884
|
{_clearpage()}
|
871
885
|
{" end autogenerated ":%^60}
|
872
886
|
"""
|