mxlpy 0.22.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 +11 -2
- mxlpy/carousel.py +6 -4
- mxlpy/compare.py +2 -2
- 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 +12 -6
- mxlpy/label_map.py +1 -2
- mxlpy/mc.py +22 -22
- mxlpy/mca.py +8 -4
- mxlpy/meta/codegen_model.py +2 -1
- mxlpy/meta/codegen_mxlpy.py +194 -58
- mxlpy/meta/source_tools.py +124 -80
- mxlpy/meta/sympy_tools.py +5 -5
- mxlpy/model.py +288 -91
- mxlpy/plot.py +16 -14
- mxlpy/sbml/_export.py +13 -5
- mxlpy/sbml/_import.py +68 -547
- mxlpy/scan.py +38 -242
- mxlpy/simulator.py +4 -359
- mxlpy/types.py +655 -83
- mxlpy/units.py +5 -0
- {mxlpy-0.22.0.dist-info → mxlpy-0.23.0.dist-info}/METADATA +4 -1
- {mxlpy-0.22.0.dist-info → mxlpy-0.23.0.dist-info}/RECORD +26 -27
- mxlpy/sbml/_mathml.py +0 -692
- mxlpy/sbml/_unit_conversion.py +0 -74
- {mxlpy-0.22.0.dist-info → mxlpy-0.23.0.dist-info}/WHEEL +0 -0
- {mxlpy-0.22.0.dist-info → mxlpy-0.23.0.dist-info}/licenses/LICENSE +0 -0
mxlpy/simulator.py
CHANGED
@@ -11,8 +11,8 @@ Classes:
|
|
11
11
|
from __future__ import annotations
|
12
12
|
|
13
13
|
import logging
|
14
|
-
from dataclasses import dataclass
|
15
|
-
from typing import TYPE_CHECKING,
|
14
|
+
from dataclasses import dataclass
|
15
|
+
from typing import TYPE_CHECKING, Self, cast
|
16
16
|
|
17
17
|
import numpy as np
|
18
18
|
import pandas as pd
|
@@ -20,374 +20,19 @@ from sympy import lambdify
|
|
20
20
|
|
21
21
|
from mxlpy.integrators import DefaultIntegrator
|
22
22
|
from mxlpy.symbolic import to_symbolic_model
|
23
|
+
from mxlpy.types import Result
|
23
24
|
|
24
25
|
if TYPE_CHECKING:
|
25
|
-
from collections.abc import Iterator
|
26
|
-
|
27
26
|
from mxlpy.model import Model
|
28
27
|
from mxlpy.types import Array, ArrayLike, IntegratorProtocol, IntegratorType
|
29
28
|
|
30
29
|
_LOGGER = logging.getLogger(__name__)
|
31
30
|
|
32
31
|
__all__ = [
|
33
|
-
"Result",
|
34
32
|
"Simulator",
|
35
33
|
]
|
36
34
|
|
37
35
|
|
38
|
-
def _normalise_split_results(
|
39
|
-
results: list[pd.DataFrame],
|
40
|
-
normalise: float | ArrayLike,
|
41
|
-
) -> list[pd.DataFrame]:
|
42
|
-
"""Normalize split results by a given factor or array.
|
43
|
-
|
44
|
-
Args:
|
45
|
-
results: List of DataFrames containing the results to normalize.
|
46
|
-
normalise: Normalization factor or array.
|
47
|
-
|
48
|
-
Returns:
|
49
|
-
list[pd.DataFrame]: List of normalized DataFrames.
|
50
|
-
|
51
|
-
"""
|
52
|
-
if isinstance(normalise, int | float):
|
53
|
-
return [i / normalise for i in results]
|
54
|
-
if len(normalise) == len(results):
|
55
|
-
return [(i.T / j).T for i, j in zip(results, normalise, strict=True)]
|
56
|
-
|
57
|
-
results = []
|
58
|
-
start = 0
|
59
|
-
end = 0
|
60
|
-
for i in results:
|
61
|
-
end += len(i)
|
62
|
-
results.append(i / np.reshape(normalise[start:end], (len(i), 1))) # type: ignore
|
63
|
-
start += end
|
64
|
-
return results
|
65
|
-
|
66
|
-
|
67
|
-
@dataclass(kw_only=True, slots=True)
|
68
|
-
class Result:
|
69
|
-
"""Simulation results."""
|
70
|
-
|
71
|
-
model: Model
|
72
|
-
raw_variables: list[pd.DataFrame]
|
73
|
-
raw_parameters: list[dict[str, float]]
|
74
|
-
raw_args: list[pd.DataFrame] = field(default_factory=list)
|
75
|
-
|
76
|
-
@property
|
77
|
-
def variables(self) -> pd.DataFrame:
|
78
|
-
"""Simulation variables."""
|
79
|
-
return self.get_variables(
|
80
|
-
include_derived_variables=True,
|
81
|
-
include_readouts=True,
|
82
|
-
concatenated=True,
|
83
|
-
normalise=None,
|
84
|
-
)
|
85
|
-
|
86
|
-
@property
|
87
|
-
def fluxes(self) -> pd.DataFrame:
|
88
|
-
"""Simulation fluxes."""
|
89
|
-
return self.get_fluxes()
|
90
|
-
|
91
|
-
def __iter__(self) -> Iterator[pd.DataFrame]:
|
92
|
-
"""Iterate over the concentration and flux response coefficients."""
|
93
|
-
return iter((self.variables, self.fluxes))
|
94
|
-
|
95
|
-
def _compute_args(self) -> list[pd.DataFrame]:
|
96
|
-
# Already computed
|
97
|
-
if len(self.raw_args) > 0:
|
98
|
-
return self.raw_args
|
99
|
-
|
100
|
-
# Compute new otherwise
|
101
|
-
for res, p in zip(self.raw_variables, self.raw_parameters, strict=True):
|
102
|
-
self.model.update_parameters(p)
|
103
|
-
self.raw_args.append(
|
104
|
-
self.model.get_args_time_course(
|
105
|
-
variables=res,
|
106
|
-
include_variables=True,
|
107
|
-
include_parameters=True,
|
108
|
-
include_derived_parameters=True,
|
109
|
-
include_derived_variables=True,
|
110
|
-
include_reactions=True,
|
111
|
-
include_surrogate_outputs=True,
|
112
|
-
include_readouts=True,
|
113
|
-
)
|
114
|
-
)
|
115
|
-
return self.raw_args
|
116
|
-
|
117
|
-
def _select_data(
|
118
|
-
self,
|
119
|
-
dependent: list[pd.DataFrame],
|
120
|
-
*,
|
121
|
-
include_variables: bool = False,
|
122
|
-
include_parameters: bool = False,
|
123
|
-
include_derived_parameters: bool = False,
|
124
|
-
include_derived_variables: bool = False,
|
125
|
-
include_reactions: bool = False,
|
126
|
-
include_surrogate_outputs: bool = False,
|
127
|
-
include_readouts: bool = False,
|
128
|
-
) -> list[pd.DataFrame]:
|
129
|
-
names = self.model.get_arg_names(
|
130
|
-
include_time=False,
|
131
|
-
include_variables=include_variables,
|
132
|
-
include_parameters=include_parameters,
|
133
|
-
include_derived_parameters=include_derived_parameters,
|
134
|
-
include_derived_variables=include_derived_variables,
|
135
|
-
include_reactions=include_reactions,
|
136
|
-
include_surrogate_outputs=include_surrogate_outputs,
|
137
|
-
include_readouts=include_readouts,
|
138
|
-
)
|
139
|
-
return [i.loc[:, names] for i in dependent]
|
140
|
-
|
141
|
-
def _adjust_data(
|
142
|
-
self,
|
143
|
-
data: list[pd.DataFrame],
|
144
|
-
normalise: float | ArrayLike | None = None,
|
145
|
-
*,
|
146
|
-
concatenated: bool = True,
|
147
|
-
) -> pd.DataFrame | list[pd.DataFrame]:
|
148
|
-
if normalise is not None:
|
149
|
-
data = _normalise_split_results(data, normalise=normalise)
|
150
|
-
if concatenated:
|
151
|
-
return pd.concat(data, axis=0)
|
152
|
-
return data
|
153
|
-
|
154
|
-
@overload
|
155
|
-
def get_args( # type: ignore
|
156
|
-
self,
|
157
|
-
*,
|
158
|
-
include_variables: bool = True,
|
159
|
-
include_parameters: bool = False,
|
160
|
-
include_derived_parameters: bool = False,
|
161
|
-
include_derived_variables: bool = True,
|
162
|
-
include_reactions: bool = True,
|
163
|
-
include_surrogate_outputs: bool = False,
|
164
|
-
include_readouts: bool = False,
|
165
|
-
concatenated: Literal[False],
|
166
|
-
normalise: float | ArrayLike | None = None,
|
167
|
-
) -> list[pd.DataFrame]: ...
|
168
|
-
|
169
|
-
@overload
|
170
|
-
def get_args(
|
171
|
-
self,
|
172
|
-
*,
|
173
|
-
include_variables: bool = True,
|
174
|
-
include_parameters: bool = False,
|
175
|
-
include_derived_parameters: bool = False,
|
176
|
-
include_derived_variables: bool = True,
|
177
|
-
include_reactions: bool = True,
|
178
|
-
include_surrogate_outputs: bool = False,
|
179
|
-
include_readouts: bool = False,
|
180
|
-
concatenated: Literal[True],
|
181
|
-
normalise: float | ArrayLike | None = None,
|
182
|
-
) -> pd.DataFrame: ...
|
183
|
-
|
184
|
-
@overload
|
185
|
-
def get_args(
|
186
|
-
self,
|
187
|
-
*,
|
188
|
-
include_variables: bool = True,
|
189
|
-
include_parameters: bool = False,
|
190
|
-
include_derived_parameters: bool = False,
|
191
|
-
include_derived_variables: bool = True,
|
192
|
-
include_reactions: bool = True,
|
193
|
-
include_surrogate_outputs: bool = False,
|
194
|
-
include_readouts: bool = False,
|
195
|
-
concatenated: bool = True,
|
196
|
-
normalise: float | ArrayLike | None = None,
|
197
|
-
) -> pd.DataFrame: ...
|
198
|
-
|
199
|
-
def get_args(
|
200
|
-
self,
|
201
|
-
*,
|
202
|
-
include_variables: bool = True,
|
203
|
-
include_parameters: bool = False,
|
204
|
-
include_derived_parameters: bool = False,
|
205
|
-
include_derived_variables: bool = True,
|
206
|
-
include_reactions: bool = True,
|
207
|
-
include_surrogate_outputs: bool = False,
|
208
|
-
include_readouts: bool = False,
|
209
|
-
concatenated: bool = True,
|
210
|
-
normalise: float | ArrayLike | None = None,
|
211
|
-
) -> pd.DataFrame | list[pd.DataFrame]:
|
212
|
-
"""Get the variables over time.
|
213
|
-
|
214
|
-
Examples:
|
215
|
-
>>> Result().get_variables()
|
216
|
-
Time ATP NADPH
|
217
|
-
0.000000 1.000000 1.000000
|
218
|
-
0.000100 0.999900 0.999900
|
219
|
-
0.000200 0.999800 0.999800
|
220
|
-
|
221
|
-
"""
|
222
|
-
variables = self._select_data(
|
223
|
-
self._compute_args(),
|
224
|
-
include_variables=include_variables,
|
225
|
-
include_parameters=include_parameters,
|
226
|
-
include_derived_parameters=include_derived_parameters,
|
227
|
-
include_derived_variables=include_derived_variables,
|
228
|
-
include_reactions=include_reactions,
|
229
|
-
include_surrogate_outputs=include_surrogate_outputs,
|
230
|
-
include_readouts=include_readouts,
|
231
|
-
)
|
232
|
-
return self._adjust_data(
|
233
|
-
variables, normalise=normalise, concatenated=concatenated
|
234
|
-
)
|
235
|
-
|
236
|
-
@overload
|
237
|
-
def get_variables( # type: ignore
|
238
|
-
self,
|
239
|
-
*,
|
240
|
-
include_derived_variables: bool = True,
|
241
|
-
include_readouts: bool = True,
|
242
|
-
concatenated: Literal[False],
|
243
|
-
normalise: float | ArrayLike | None = None,
|
244
|
-
) -> list[pd.DataFrame]: ...
|
245
|
-
|
246
|
-
@overload
|
247
|
-
def get_variables(
|
248
|
-
self,
|
249
|
-
*,
|
250
|
-
include_derived_variables: bool = True,
|
251
|
-
include_readouts: bool = True,
|
252
|
-
concatenated: Literal[True],
|
253
|
-
normalise: float | ArrayLike | None = None,
|
254
|
-
) -> pd.DataFrame: ...
|
255
|
-
|
256
|
-
@overload
|
257
|
-
def get_variables(
|
258
|
-
self,
|
259
|
-
*,
|
260
|
-
include_derived_variables: bool = True,
|
261
|
-
include_readouts: bool = True,
|
262
|
-
concatenated: bool = True,
|
263
|
-
normalise: float | ArrayLike | None = None,
|
264
|
-
) -> pd.DataFrame: ...
|
265
|
-
|
266
|
-
def get_variables(
|
267
|
-
self,
|
268
|
-
*,
|
269
|
-
include_derived_variables: bool = True,
|
270
|
-
include_readouts: bool = True,
|
271
|
-
concatenated: bool = True,
|
272
|
-
normalise: float | ArrayLike | None = None,
|
273
|
-
) -> pd.DataFrame | list[pd.DataFrame]:
|
274
|
-
"""Get the variables over time.
|
275
|
-
|
276
|
-
Examples:
|
277
|
-
>>> Result().get_variables()
|
278
|
-
Time ATP NADPH
|
279
|
-
0.000000 1.000000 1.000000
|
280
|
-
0.000100 0.999900 0.999900
|
281
|
-
0.000200 0.999800 0.999800
|
282
|
-
|
283
|
-
"""
|
284
|
-
if not include_derived_variables and not include_readouts:
|
285
|
-
return self._adjust_data(
|
286
|
-
self.raw_variables,
|
287
|
-
normalise=normalise,
|
288
|
-
concatenated=concatenated,
|
289
|
-
)
|
290
|
-
|
291
|
-
variables = self._select_data(
|
292
|
-
self._compute_args(),
|
293
|
-
include_variables=True,
|
294
|
-
include_derived_variables=include_derived_variables,
|
295
|
-
include_readouts=include_readouts,
|
296
|
-
)
|
297
|
-
return self._adjust_data(
|
298
|
-
variables, normalise=normalise, concatenated=concatenated
|
299
|
-
)
|
300
|
-
|
301
|
-
@overload
|
302
|
-
def get_fluxes( # type: ignore
|
303
|
-
self,
|
304
|
-
*,
|
305
|
-
include_surrogates: bool = True,
|
306
|
-
normalise: float | ArrayLike | None = None,
|
307
|
-
concatenated: Literal[False],
|
308
|
-
) -> list[pd.DataFrame]: ...
|
309
|
-
|
310
|
-
@overload
|
311
|
-
def get_fluxes(
|
312
|
-
self,
|
313
|
-
*,
|
314
|
-
include_surrogates: bool = True,
|
315
|
-
normalise: float | ArrayLike | None = None,
|
316
|
-
concatenated: Literal[True],
|
317
|
-
) -> pd.DataFrame: ...
|
318
|
-
|
319
|
-
@overload
|
320
|
-
def get_fluxes(
|
321
|
-
self,
|
322
|
-
*,
|
323
|
-
include_surrogates: bool = True,
|
324
|
-
normalise: float | ArrayLike | None = None,
|
325
|
-
concatenated: bool = True,
|
326
|
-
) -> pd.DataFrame: ...
|
327
|
-
|
328
|
-
def get_fluxes(
|
329
|
-
self,
|
330
|
-
*,
|
331
|
-
include_surrogates: bool = True,
|
332
|
-
normalise: float | ArrayLike | None = None,
|
333
|
-
concatenated: bool = True,
|
334
|
-
) -> pd.DataFrame | list[pd.DataFrame]:
|
335
|
-
"""Get the flux results.
|
336
|
-
|
337
|
-
Examples:
|
338
|
-
>>> Result.get_fluxes()
|
339
|
-
Time v1 v2
|
340
|
-
0.000000 1.000000 10.00000
|
341
|
-
0.000100 0.999900 9.999000
|
342
|
-
0.000200 0.999800 9.998000
|
343
|
-
|
344
|
-
Returns:
|
345
|
-
pd.DataFrame: DataFrame of fluxes.
|
346
|
-
|
347
|
-
"""
|
348
|
-
fluxes = self._select_data(
|
349
|
-
self._compute_args(),
|
350
|
-
include_reactions=True,
|
351
|
-
include_surrogate_outputs=include_surrogates,
|
352
|
-
)
|
353
|
-
return self._adjust_data(
|
354
|
-
fluxes,
|
355
|
-
normalise=normalise,
|
356
|
-
concatenated=concatenated,
|
357
|
-
)
|
358
|
-
|
359
|
-
def get_combined(self) -> pd.DataFrame:
|
360
|
-
"""Get the variables and fluxes as a single pandas.DataFrame.
|
361
|
-
|
362
|
-
Examples:
|
363
|
-
>>> Result.get_combined()
|
364
|
-
Time ATP NADPH v1 v2
|
365
|
-
0.000000 1.000000 1.000000 1.000000 10.00000
|
366
|
-
0.000100 0.999900 0.999900 0.999900 9.999000
|
367
|
-
0.000200 0.999800 0.999800 0.999800 9.998000
|
368
|
-
|
369
|
-
Returns:
|
370
|
-
pd.DataFrame: DataFrame of fluxes.
|
371
|
-
|
372
|
-
"""
|
373
|
-
return pd.concat((self.variables, self.fluxes), axis=1)
|
374
|
-
|
375
|
-
def get_new_y0(self) -> dict[str, float]:
|
376
|
-
"""Get the new initial conditions after the simulation.
|
377
|
-
|
378
|
-
Examples:
|
379
|
-
>>> Simulator(model).simulate_to_steady_state().get_new_y0()
|
380
|
-
{"ATP": 1.0, "NADPH": 1.0}
|
381
|
-
|
382
|
-
"""
|
383
|
-
return dict(
|
384
|
-
self.get_variables(
|
385
|
-
include_derived_variables=False,
|
386
|
-
include_readouts=False,
|
387
|
-
).iloc[-1]
|
388
|
-
)
|
389
|
-
|
390
|
-
|
391
36
|
@dataclass(
|
392
37
|
init=False,
|
393
38
|
slots=True,
|
@@ -478,7 +123,7 @@ class Simulator:
|
|
478
123
|
y0 = self.y0
|
479
124
|
self.integrator = self._integrator_type(
|
480
125
|
self.model,
|
481
|
-
|
126
|
+
tuple(y0[k] for k in self.model.get_variable_names()),
|
482
127
|
jac_fn,
|
483
128
|
)
|
484
129
|
|