mxlpy 0.21.0__py3-none-any.whl → 0.23.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 +15 -2
- mxlpy/carousel.py +6 -4
- mxlpy/compare.py +4 -8
- mxlpy/experimental/diff.py +1 -1
- mxlpy/fit.py +195 -99
- mxlpy/identify.py +14 -9
- mxlpy/integrators/__init__.py +4 -0
- mxlpy/integrators/int_assimulo.py +3 -3
- mxlpy/integrators/int_diffrax.py +119 -0
- mxlpy/integrators/int_scipy.py +15 -6
- mxlpy/label_map.py +6 -7
- mxlpy/linear_label_map.py +3 -1
- mxlpy/mc.py +25 -22
- mxlpy/mca.py +10 -6
- mxlpy/meta/__init__.py +5 -3
- mxlpy/meta/codegen_latex.py +44 -30
- mxlpy/meta/codegen_model.py +175 -0
- mxlpy/meta/codegen_mxlpy.py +254 -0
- mxlpy/meta/source_tools.py +506 -221
- mxlpy/meta/sympy_tools.py +117 -0
- mxlpy/model.py +758 -257
- mxlpy/plot.py +16 -14
- mxlpy/report.py +153 -90
- mxlpy/sbml/_export.py +22 -11
- mxlpy/sbml/_import.py +68 -547
- mxlpy/scan.py +39 -243
- mxlpy/simulator.py +109 -283
- mxlpy/symbolic/symbolic_model.py +29 -17
- mxlpy/types.py +694 -97
- mxlpy/units.py +133 -0
- {mxlpy-0.21.0.dist-info → mxlpy-0.23.0.dist-info}/METADATA +4 -1
- mxlpy-0.23.0.dist-info/RECORD +57 -0
- mxlpy/meta/codegen_modebase.py +0 -112
- mxlpy/meta/codegen_py.py +0 -115
- mxlpy/sbml/_mathml.py +0 -692
- mxlpy/sbml/_unit_conversion.py +0 -74
- mxlpy-0.21.0.dist-info/RECORD +0 -56
- {mxlpy-0.21.0.dist-info → mxlpy-0.23.0.dist-info}/WHEEL +0 -0
- {mxlpy-0.21.0.dist-info → mxlpy-0.23.0.dist-info}/licenses/LICENSE +0 -0
mxlpy/scan.py
CHANGED
@@ -15,16 +15,21 @@ Functions:
|
|
15
15
|
|
16
16
|
from __future__ import annotations
|
17
17
|
|
18
|
-
from dataclasses import dataclass
|
19
18
|
from functools import partial
|
20
|
-
from typing import TYPE_CHECKING, Protocol
|
19
|
+
from typing import TYPE_CHECKING, Protocol
|
21
20
|
|
22
21
|
import numpy as np
|
23
22
|
import pandas as pd
|
24
23
|
|
25
24
|
from mxlpy.parallel import Cache, parallelise
|
26
|
-
from mxlpy.simulator import
|
27
|
-
from mxlpy.types import
|
25
|
+
from mxlpy.simulator import Simulator
|
26
|
+
from mxlpy.types import (
|
27
|
+
IntegratorType,
|
28
|
+
ProtocolScan,
|
29
|
+
Result,
|
30
|
+
SteadyStateScan,
|
31
|
+
TimeCourseScan,
|
32
|
+
)
|
28
33
|
|
29
34
|
if TYPE_CHECKING:
|
30
35
|
from collections.abc import Callable
|
@@ -36,9 +41,7 @@ if TYPE_CHECKING:
|
|
36
41
|
__all__ = [
|
37
42
|
"ProtocolWorker",
|
38
43
|
"SteadyStateWorker",
|
39
|
-
"TimeCourse",
|
40
44
|
"TimeCourseWorker",
|
41
|
-
"TimePoint",
|
42
45
|
"steady_state",
|
43
46
|
"time_course",
|
44
47
|
"time_course_over_protocol",
|
@@ -67,206 +70,11 @@ def _update_parameters_and_initial_conditions[T](
|
|
67
70
|
return fn(model)
|
68
71
|
|
69
72
|
|
70
|
-
def _empty_conc_series(model: Model) -> pd.Series:
|
71
|
-
"""Create an empty concentration series for the model.
|
72
|
-
|
73
|
-
Args:
|
74
|
-
model: Model instance to generate the series for.
|
75
|
-
|
76
|
-
Returns:
|
77
|
-
pd.Series: Series with NaN values for each model variable.
|
78
|
-
|
79
|
-
"""
|
80
|
-
return pd.Series(
|
81
|
-
data=np.full(shape=len(model.get_variable_names()), fill_value=np.nan),
|
82
|
-
index=model.get_variable_names(),
|
83
|
-
)
|
84
|
-
|
85
|
-
|
86
|
-
def _empty_flux_series(model: Model) -> pd.Series:
|
87
|
-
"""Create an empty flux series for the model.
|
88
|
-
|
89
|
-
Args:
|
90
|
-
model: Model instance to generate the series for.
|
91
|
-
|
92
|
-
Returns:
|
93
|
-
pd.Series: Series with NaN values for each model reaction.
|
94
|
-
|
95
|
-
"""
|
96
|
-
return pd.Series(
|
97
|
-
data=np.full(shape=len(model.get_reaction_names()), fill_value=np.nan),
|
98
|
-
index=model.get_reaction_names(),
|
99
|
-
)
|
100
|
-
|
101
|
-
|
102
|
-
def _empty_conc_df(model: Model, time_points: Array) -> pd.DataFrame:
|
103
|
-
"""Create an empty concentration DataFrame for the model over given time points.
|
104
|
-
|
105
|
-
Args:
|
106
|
-
model: Model instance to generate the DataFrame for.
|
107
|
-
time_points: Array of time points.
|
108
|
-
|
109
|
-
Returns:
|
110
|
-
pd.DataFrame: DataFrame with NaN values for each model variable at each time point.
|
111
|
-
|
112
|
-
"""
|
113
|
-
return pd.DataFrame(
|
114
|
-
data=np.full(
|
115
|
-
shape=(len(time_points), len(model.get_variable_names())),
|
116
|
-
fill_value=np.nan,
|
117
|
-
),
|
118
|
-
index=time_points,
|
119
|
-
columns=model.get_variable_names(),
|
120
|
-
)
|
121
|
-
|
122
|
-
|
123
|
-
def _empty_flux_df(model: Model, time_points: Array) -> pd.DataFrame:
|
124
|
-
"""Create an empty concentration DataFrame for the model over given time points.
|
125
|
-
|
126
|
-
Args:
|
127
|
-
model: Model instance to generate the DataFrame for.
|
128
|
-
time_points: Array of time points.
|
129
|
-
|
130
|
-
Returns:
|
131
|
-
pd.DataFrame: DataFrame with NaN values for each model variable at each time point.
|
132
|
-
|
133
|
-
"""
|
134
|
-
return pd.DataFrame(
|
135
|
-
data=np.full(
|
136
|
-
shape=(len(time_points), len(model.get_reaction_names())),
|
137
|
-
fill_value=np.nan,
|
138
|
-
),
|
139
|
-
index=time_points,
|
140
|
-
columns=model.get_reaction_names(),
|
141
|
-
)
|
142
|
-
|
143
|
-
|
144
73
|
###############################################################################
|
145
74
|
# Single returns
|
146
75
|
###############################################################################
|
147
76
|
|
148
77
|
|
149
|
-
@dataclass(slots=True)
|
150
|
-
class TimePoint:
|
151
|
-
"""Represents a single time point in a simulation.
|
152
|
-
|
153
|
-
Attributes:
|
154
|
-
concs: Series of concentrations at the time point.
|
155
|
-
fluxes: Series of fluxes at the time point.
|
156
|
-
|
157
|
-
Args:
|
158
|
-
model: Model instance to generate the time point for.
|
159
|
-
concs: DataFrame of concentrations (default: None).
|
160
|
-
fluxes: DataFrame of fluxes (default: None).
|
161
|
-
idx: Index of the time point in the DataFrame (default: -1).
|
162
|
-
|
163
|
-
"""
|
164
|
-
|
165
|
-
variables: pd.Series
|
166
|
-
fluxes: pd.Series
|
167
|
-
|
168
|
-
@classmethod
|
169
|
-
def from_result(
|
170
|
-
cls,
|
171
|
-
*,
|
172
|
-
model: Model,
|
173
|
-
result: Result | None,
|
174
|
-
idx: int = -1,
|
175
|
-
) -> Self:
|
176
|
-
"""Initialize the Scan object.
|
177
|
-
|
178
|
-
Args:
|
179
|
-
model: The model object.
|
180
|
-
result: Result of the simulation
|
181
|
-
idx: Index to select specific row from concs and fluxes DataFrames.
|
182
|
-
|
183
|
-
"""
|
184
|
-
if result is None:
|
185
|
-
return cls(
|
186
|
-
variables=_empty_conc_series(model),
|
187
|
-
fluxes=_empty_flux_series(model),
|
188
|
-
)
|
189
|
-
|
190
|
-
return cls(
|
191
|
-
variables=result.variables.iloc[idx],
|
192
|
-
fluxes=result.fluxes.iloc[idx],
|
193
|
-
)
|
194
|
-
|
195
|
-
@property
|
196
|
-
def results(self) -> pd.Series:
|
197
|
-
"""Get the combined results of concentrations and fluxes.
|
198
|
-
|
199
|
-
Example:
|
200
|
-
>>> time_point.results
|
201
|
-
x1 1.0
|
202
|
-
x2 0.5
|
203
|
-
v1 0.1
|
204
|
-
v2 0.2
|
205
|
-
|
206
|
-
Returns:
|
207
|
-
pd.Series: Combined series of concentrations and fluxes.
|
208
|
-
|
209
|
-
"""
|
210
|
-
return pd.concat((self.variables, self.fluxes), axis=0)
|
211
|
-
|
212
|
-
|
213
|
-
@dataclass(slots=True)
|
214
|
-
class TimeCourse:
|
215
|
-
"""Represents a time course in a simulation.
|
216
|
-
|
217
|
-
Attributes:
|
218
|
-
variables: DataFrame of concentrations over time.
|
219
|
-
fluxes: DataFrame of fluxes over time.
|
220
|
-
|
221
|
-
"""
|
222
|
-
|
223
|
-
variables: pd.DataFrame
|
224
|
-
fluxes: pd.DataFrame
|
225
|
-
|
226
|
-
@classmethod
|
227
|
-
def from_scan(
|
228
|
-
cls,
|
229
|
-
*,
|
230
|
-
model: Model,
|
231
|
-
time_points: Array,
|
232
|
-
result: Result | None,
|
233
|
-
) -> Self:
|
234
|
-
"""Initialize the Scan object.
|
235
|
-
|
236
|
-
Args:
|
237
|
-
model (Model): The model object.
|
238
|
-
time_points (Array): Array of time points.
|
239
|
-
result: Result of the simulation
|
240
|
-
|
241
|
-
"""
|
242
|
-
if result is None:
|
243
|
-
return cls(
|
244
|
-
_empty_conc_df(model, time_points),
|
245
|
-
_empty_flux_df(model, time_points),
|
246
|
-
)
|
247
|
-
return cls(
|
248
|
-
result.variables,
|
249
|
-
result.fluxes,
|
250
|
-
)
|
251
|
-
|
252
|
-
@property
|
253
|
-
def results(self) -> pd.DataFrame:
|
254
|
-
"""Get the combined results of concentrations and fluxes over time.
|
255
|
-
|
256
|
-
Examples:
|
257
|
-
>>> time_course.results
|
258
|
-
Time x1 x2 v1 v2
|
259
|
-
0.0 1.0 1.00 1.00 1.00
|
260
|
-
0.1 0.9 0.99 0.99 0.99
|
261
|
-
0.2 0.8 0.99 0.99 0.99
|
262
|
-
|
263
|
-
Returns:
|
264
|
-
pd.DataFrame: Combined DataFrame of concentrations and fluxes.
|
265
|
-
|
266
|
-
"""
|
267
|
-
return pd.concat((self.variables, self.fluxes), axis=1)
|
268
|
-
|
269
|
-
|
270
78
|
###############################################################################
|
271
79
|
# Workers
|
272
80
|
###############################################################################
|
@@ -282,7 +90,7 @@ class SteadyStateWorker(Protocol):
|
|
282
90
|
rel_norm: bool,
|
283
91
|
integrator: IntegratorType | None,
|
284
92
|
y0: dict[str, float] | None,
|
285
|
-
) ->
|
93
|
+
) -> Result:
|
286
94
|
"""Call the worker function."""
|
287
95
|
...
|
288
96
|
|
@@ -297,7 +105,7 @@ class TimeCourseWorker(Protocol):
|
|
297
105
|
*,
|
298
106
|
integrator: IntegratorType | None,
|
299
107
|
y0: dict[str, float] | None,
|
300
|
-
) ->
|
108
|
+
) -> Result:
|
301
109
|
"""Call the worker function."""
|
302
110
|
...
|
303
111
|
|
@@ -313,7 +121,7 @@ class ProtocolWorker(Protocol):
|
|
313
121
|
integrator: IntegratorType | None,
|
314
122
|
y0: dict[str, float] | None,
|
315
123
|
time_points_per_step: int = 10,
|
316
|
-
) ->
|
124
|
+
) -> Result:
|
317
125
|
"""Call the worker function."""
|
318
126
|
...
|
319
127
|
|
@@ -324,7 +132,7 @@ def _steady_state_worker(
|
|
324
132
|
rel_norm: bool,
|
325
133
|
integrator: IntegratorType | None,
|
326
134
|
y0: dict[str, float] | None,
|
327
|
-
) ->
|
135
|
+
) -> Result:
|
328
136
|
"""Simulate the model to steady state and return concentrations and fluxes.
|
329
137
|
|
330
138
|
Args:
|
@@ -345,7 +153,9 @@ def _steady_state_worker(
|
|
345
153
|
)
|
346
154
|
except ZeroDivisionError:
|
347
155
|
res = None
|
348
|
-
return
|
156
|
+
return (
|
157
|
+
Result.default(model=model, time_points=np.array([0.0])) if res is None else res
|
158
|
+
)
|
349
159
|
|
350
160
|
|
351
161
|
def _time_course_worker(
|
@@ -353,7 +163,7 @@ def _time_course_worker(
|
|
353
163
|
time_points: Array,
|
354
164
|
y0: dict[str, float] | None,
|
355
165
|
integrator: IntegratorType | None,
|
356
|
-
) ->
|
166
|
+
) -> Result:
|
357
167
|
"""Simulate the model to steady state and return concentrations and fluxes.
|
358
168
|
|
359
169
|
Args:
|
@@ -374,11 +184,7 @@ def _time_course_worker(
|
|
374
184
|
)
|
375
185
|
except ZeroDivisionError:
|
376
186
|
res = None
|
377
|
-
return
|
378
|
-
model=model,
|
379
|
-
time_points=time_points,
|
380
|
-
result=res,
|
381
|
-
)
|
187
|
+
return Result.default(model=model, time_points=time_points) if res is None else res
|
382
188
|
|
383
189
|
|
384
190
|
def _protocol_worker(
|
@@ -388,7 +194,7 @@ def _protocol_worker(
|
|
388
194
|
integrator: IntegratorType | None,
|
389
195
|
y0: dict[str, float] | None,
|
390
196
|
time_points_per_step: int = 10,
|
391
|
-
) ->
|
197
|
+
) -> Result:
|
392
198
|
"""Simulate the model over a protocol and return concentrations and fluxes.
|
393
199
|
|
394
200
|
Args:
|
@@ -405,7 +211,7 @@ def _protocol_worker(
|
|
405
211
|
try:
|
406
212
|
res = (
|
407
213
|
Simulator(model, integrator=integrator, y0=y0)
|
408
|
-
.
|
214
|
+
.simulate_protocol(
|
409
215
|
protocol=protocol,
|
410
216
|
time_points_per_step=time_points_per_step,
|
411
217
|
)
|
@@ -419,11 +225,7 @@ def _protocol_worker(
|
|
419
225
|
protocol.index[-1].total_seconds(),
|
420
226
|
len(protocol) * time_points_per_step,
|
421
227
|
)
|
422
|
-
return
|
423
|
-
model=model,
|
424
|
-
time_points=time_points,
|
425
|
-
result=res,
|
426
|
-
)
|
228
|
+
return Result.default(model=model, time_points=time_points) if res is None else res
|
427
229
|
|
428
230
|
|
429
231
|
def steady_state(
|
@@ -436,7 +238,7 @@ def steady_state(
|
|
436
238
|
cache: Cache | None = None,
|
437
239
|
worker: SteadyStateWorker = _steady_state_worker,
|
438
240
|
integrator: IntegratorType | None = None,
|
439
|
-
) ->
|
241
|
+
) -> SteadyStateScan:
|
440
242
|
"""Get steady-state results over supplied values.
|
441
243
|
|
442
244
|
Args:
|
@@ -492,16 +294,16 @@ def steady_state(
|
|
492
294
|
cache=cache,
|
493
295
|
parallel=parallel,
|
494
296
|
)
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
297
|
+
|
298
|
+
return SteadyStateScan(
|
299
|
+
raw_index=(
|
300
|
+
pd.Index(to_scan.iloc[:, 0])
|
301
|
+
if to_scan.shape[1] == 1
|
302
|
+
else pd.MultiIndex.from_frame(to_scan)
|
303
|
+
),
|
304
|
+
raw_results=[i[1] for i in res],
|
305
|
+
to_scan=to_scan,
|
501
306
|
)
|
502
|
-
concs.index = idx
|
503
|
-
fluxes.index = idx
|
504
|
-
return SteadyStates(variables=concs, fluxes=fluxes, parameters=to_scan)
|
505
307
|
|
506
308
|
|
507
309
|
def time_course(
|
@@ -514,7 +316,7 @@ def time_course(
|
|
514
316
|
cache: Cache | None = None,
|
515
317
|
integrator: IntegratorType | None = None,
|
516
318
|
worker: TimeCourseWorker = _time_course_worker,
|
517
|
-
) ->
|
319
|
+
) -> TimeCourseScan:
|
518
320
|
"""Get time course for each supplied parameter.
|
519
321
|
|
520
322
|
Examples:
|
@@ -585,12 +387,9 @@ def time_course(
|
|
585
387
|
cache=cache,
|
586
388
|
parallel=parallel,
|
587
389
|
)
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
parameters=to_scan,
|
592
|
-
variables=pd.concat(concs, names=["n", "time"]),
|
593
|
-
fluxes=pd.concat(fluxes, names=["n", "time"]),
|
390
|
+
return TimeCourseScan(
|
391
|
+
to_scan=to_scan,
|
392
|
+
raw_results=dict(res),
|
594
393
|
)
|
595
394
|
|
596
395
|
|
@@ -605,7 +404,7 @@ def time_course_over_protocol(
|
|
605
404
|
cache: Cache | None = None,
|
606
405
|
worker: ProtocolWorker = _protocol_worker,
|
607
406
|
integrator: IntegratorType | None = None,
|
608
|
-
) ->
|
407
|
+
) -> ProtocolScan:
|
609
408
|
"""Get protocol series for each supplied parameter.
|
610
409
|
|
611
410
|
Examples:
|
@@ -656,11 +455,8 @@ def time_course_over_protocol(
|
|
656
455
|
cache=cache,
|
657
456
|
parallel=parallel,
|
658
457
|
)
|
659
|
-
|
660
|
-
|
661
|
-
return ProtocolByPars(
|
662
|
-
parameters=to_scan,
|
458
|
+
return ProtocolScan(
|
459
|
+
to_scan=to_scan,
|
663
460
|
protocol=protocol,
|
664
|
-
|
665
|
-
fluxes=pd.concat(fluxes, names=["n", "time"]),
|
461
|
+
raw_results=dict(res),
|
666
462
|
)
|