modelbase2 0.1.78__py3-none-any.whl → 0.2.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.
- modelbase2/__init__.py +138 -26
- modelbase2/distributions.py +306 -0
- modelbase2/experimental/__init__.py +17 -0
- modelbase2/experimental/codegen.py +239 -0
- modelbase2/experimental/diff.py +227 -0
- modelbase2/experimental/notes.md +4 -0
- modelbase2/experimental/tex.py +521 -0
- modelbase2/fit.py +284 -0
- modelbase2/fns.py +185 -0
- modelbase2/integrators/__init__.py +19 -0
- modelbase2/integrators/int_assimulo.py +146 -0
- modelbase2/integrators/int_scipy.py +147 -0
- modelbase2/label_map.py +610 -0
- modelbase2/linear_label_map.py +301 -0
- modelbase2/mc.py +548 -0
- modelbase2/mca.py +280 -0
- modelbase2/model.py +1621 -0
- modelbase2/npe.py +343 -0
- modelbase2/parallel.py +171 -0
- modelbase2/parameterise.py +28 -0
- modelbase2/paths.py +36 -0
- modelbase2/plot.py +829 -0
- modelbase2/sbml/__init__.py +14 -0
- modelbase2/sbml/_data.py +77 -0
- modelbase2/sbml/_export.py +656 -0
- modelbase2/sbml/_import.py +585 -0
- modelbase2/sbml/_mathml.py +691 -0
- modelbase2/sbml/_name_conversion.py +52 -0
- modelbase2/sbml/_unit_conversion.py +74 -0
- modelbase2/scan.py +616 -0
- modelbase2/scope.py +96 -0
- modelbase2/simulator.py +635 -0
- modelbase2/surrogates/__init__.py +32 -0
- modelbase2/surrogates/_poly.py +66 -0
- modelbase2/surrogates/_torch.py +249 -0
- modelbase2/surrogates.py +316 -0
- modelbase2/types.py +352 -11
- modelbase2-0.2.0.dist-info/METADATA +81 -0
- modelbase2-0.2.0.dist-info/RECORD +42 -0
- {modelbase2-0.1.78.dist-info → modelbase2-0.2.0.dist-info}/WHEEL +1 -1
- modelbase2/core/__init__.py +0 -29
- modelbase2/core/algebraic_module_container.py +0 -130
- modelbase2/core/constant_container.py +0 -113
- modelbase2/core/data.py +0 -109
- modelbase2/core/name_container.py +0 -29
- modelbase2/core/reaction_container.py +0 -115
- modelbase2/core/utils.py +0 -28
- modelbase2/core/variable_container.py +0 -24
- modelbase2/ode/__init__.py +0 -13
- modelbase2/ode/integrator.py +0 -80
- modelbase2/ode/mca.py +0 -270
- modelbase2/ode/model.py +0 -470
- modelbase2/ode/simulator.py +0 -153
- modelbase2/utils/__init__.py +0 -0
- modelbase2/utils/plotting.py +0 -372
- modelbase2-0.1.78.dist-info/METADATA +0 -44
- modelbase2-0.1.78.dist-info/RECORD +0 -22
- {modelbase2-0.1.78.dist-info → modelbase2-0.2.0.dist-info/licenses}/LICENSE +0 -0
modelbase2/ode/model.py
DELETED
@@ -1,470 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
|
3
|
-
import numpy as np
|
4
|
-
import pandas as pd
|
5
|
-
from ..core import (
|
6
|
-
AlgebraicModule,
|
7
|
-
AlgebraicModuleContainer,
|
8
|
-
Constant,
|
9
|
-
ConstantContainer,
|
10
|
-
DerivedConstant,
|
11
|
-
NameContainer,
|
12
|
-
Reaction,
|
13
|
-
ReactionContainer,
|
14
|
-
Variable,
|
15
|
-
VariableContainer,
|
16
|
-
)
|
17
|
-
from ..core.data import (
|
18
|
-
DerivedStoichiometry,
|
19
|
-
ModuleFunction,
|
20
|
-
RateFunction,
|
21
|
-
StoichiometryByReaction,
|
22
|
-
StoichiometryByVariable,
|
23
|
-
)
|
24
|
-
from ..types import Array, Series
|
25
|
-
from dataclasses import dataclass, field
|
26
|
-
from functools import singledispatchmethod
|
27
|
-
from modelbase.ode import Model as OldModel
|
28
|
-
from typing import Iterable, Literal, Optional, Union, overload
|
29
|
-
|
30
|
-
|
31
|
-
def _sort_derived_compounds(m: Model, max_iterations: int = 10_000) -> list[str]:
|
32
|
-
from queue import Empty, SimpleQueue
|
33
|
-
|
34
|
-
available = set(m.constants)
|
35
|
-
order = []
|
36
|
-
to_sort: SimpleQueue = SimpleQueue()
|
37
|
-
for v in m.derived_constants.values():
|
38
|
-
to_sort.put((v.name, set(v.args)))
|
39
|
-
|
40
|
-
last_name: str | None = None
|
41
|
-
i = 0
|
42
|
-
while True:
|
43
|
-
try:
|
44
|
-
name, args = to_sort.get_nowait()
|
45
|
-
except Empty:
|
46
|
-
break
|
47
|
-
if args.issubset(available):
|
48
|
-
available.add(name)
|
49
|
-
order.append(name)
|
50
|
-
else:
|
51
|
-
if last_name == name:
|
52
|
-
order.append(name)
|
53
|
-
break
|
54
|
-
to_sort.put((name, args))
|
55
|
-
last_name = name
|
56
|
-
i += 1
|
57
|
-
if i > max_iterations:
|
58
|
-
while True:
|
59
|
-
try:
|
60
|
-
name, args = to_sort.get_nowait()
|
61
|
-
print(name, args)
|
62
|
-
except Empty:
|
63
|
-
break
|
64
|
-
|
65
|
-
raise ValueError(
|
66
|
-
"Exceeded max iterations on sorting. Check if there are circular references."
|
67
|
-
)
|
68
|
-
return order
|
69
|
-
|
70
|
-
|
71
|
-
@dataclass
|
72
|
-
class Model:
|
73
|
-
_algebraic_modules: AlgebraicModuleContainer = field(
|
74
|
-
default_factory=AlgebraicModuleContainer
|
75
|
-
)
|
76
|
-
_variables: VariableContainer = field(default_factory=VariableContainer)
|
77
|
-
_constants: ConstantContainer = field(default_factory=ConstantContainer)
|
78
|
-
_reactions: ReactionContainer = field(default_factory=ReactionContainer)
|
79
|
-
_names: NameContainer = field(default_factory=NameContainer)
|
80
|
-
|
81
|
-
def __add__(self, other: "Model") -> "Model":
|
82
|
-
for name, variable in other.variables.items():
|
83
|
-
if name in self.variables:
|
84
|
-
continue
|
85
|
-
else:
|
86
|
-
self.add_variable(variable)
|
87
|
-
|
88
|
-
for name, constant in other.constants.items():
|
89
|
-
if name in self.constants:
|
90
|
-
self.update_constant(name, constant.value)
|
91
|
-
else:
|
92
|
-
self.add_constant(constant)
|
93
|
-
|
94
|
-
# for name, derived_constant in other.derived_constants.items():
|
95
|
-
for name in other._constants._derived_constant_order:
|
96
|
-
derived_constant = other.derived_constants[name]
|
97
|
-
if name in self.derived_constants:
|
98
|
-
self.update_derived_constant(
|
99
|
-
name,
|
100
|
-
derived_constant.function,
|
101
|
-
derived_constant.args,
|
102
|
-
derived_constant.unit,
|
103
|
-
)
|
104
|
-
else:
|
105
|
-
self.add_derived_constant(derived_constant)
|
106
|
-
|
107
|
-
# for name, module in other.algebraic_modules.items():
|
108
|
-
for name in other._algebraic_modules.module_order:
|
109
|
-
module = other.algebraic_modules[name]
|
110
|
-
if name in self.algebraic_modules:
|
111
|
-
self.update_algebraic_module(
|
112
|
-
name,
|
113
|
-
module.function,
|
114
|
-
module.derived_variables,
|
115
|
-
module.args,
|
116
|
-
)
|
117
|
-
else:
|
118
|
-
self.add_algebraic_module(module)
|
119
|
-
|
120
|
-
for name, reaction in other.reactions.items():
|
121
|
-
if reaction.name in self.reactions:
|
122
|
-
self.update_reaction(
|
123
|
-
reaction.name,
|
124
|
-
reaction.function,
|
125
|
-
reaction.stoichiometry,
|
126
|
-
reaction.derived_stoichiometry,
|
127
|
-
reaction.args,
|
128
|
-
)
|
129
|
-
else:
|
130
|
-
self.add_reaction(
|
131
|
-
Reaction(
|
132
|
-
name=reaction.name,
|
133
|
-
function=reaction.function,
|
134
|
-
stoichiometry=reaction.stoichiometry,
|
135
|
-
derived_stoichiometry=reaction.derived_stoichiometry,
|
136
|
-
args=reaction.args,
|
137
|
-
)
|
138
|
-
)
|
139
|
-
|
140
|
-
return self
|
141
|
-
|
142
|
-
@property
|
143
|
-
def constants(self) -> dict[str, Constant]:
|
144
|
-
return self._constants.constants
|
145
|
-
|
146
|
-
@property
|
147
|
-
def derived_constants(self) -> dict[str, DerivedConstant]:
|
148
|
-
return self._constants.derived_constants
|
149
|
-
|
150
|
-
@property
|
151
|
-
def constant_values(self) -> dict[str, float]:
|
152
|
-
return self._constants.values
|
153
|
-
|
154
|
-
@property
|
155
|
-
def variables(self) -> dict[str, Variable]:
|
156
|
-
return self._variables.variables
|
157
|
-
|
158
|
-
@property
|
159
|
-
def derived_variables(self) -> list[str]:
|
160
|
-
return self._algebraic_modules.get_derived_variables()
|
161
|
-
|
162
|
-
@property
|
163
|
-
def all_variables(self) -> list[str]:
|
164
|
-
return list(self.variables) + self.derived_variables
|
165
|
-
|
166
|
-
@property
|
167
|
-
def algebraic_modules(self) -> dict[str, AlgebraicModule]:
|
168
|
-
return self._algebraic_modules.modules
|
169
|
-
|
170
|
-
@property
|
171
|
-
def reactions(self) -> dict[str, Reaction]:
|
172
|
-
return self._reactions.reactions
|
173
|
-
|
174
|
-
@property
|
175
|
-
def stoichiometries(self) -> dict[str, StoichiometryByVariable]:
|
176
|
-
return self._reactions.stoichiometries_by_variables
|
177
|
-
|
178
|
-
@singledispatchmethod
|
179
|
-
def add(
|
180
|
-
self,
|
181
|
-
element: Union[list, Constant, DerivedConstant, Variable, AlgebraicModule],
|
182
|
-
) -> None:
|
183
|
-
raise NotImplementedError(element.__class__.__name__)
|
184
|
-
|
185
|
-
@add.register
|
186
|
-
def _add_iterable(self, elements: list) -> None:
|
187
|
-
for element in elements:
|
188
|
-
self.add(element)
|
189
|
-
|
190
|
-
##########################################################################
|
191
|
-
# Constants
|
192
|
-
##########################################################################
|
193
|
-
|
194
|
-
@add.register
|
195
|
-
def add_constant(self, constant: Constant) -> None:
|
196
|
-
self._names.add(constant.name, "constant")
|
197
|
-
self._constants.add_basic(constant)
|
198
|
-
|
199
|
-
def scale_constant(self, name: str, factor: float) -> None:
|
200
|
-
value = self.constant_values[name]
|
201
|
-
self.update_constant(name, value * factor)
|
202
|
-
|
203
|
-
def update_constant(self, name: str, value: float) -> None:
|
204
|
-
self._constants.update_basic(name, value)
|
205
|
-
self._reactions.update_derived_stoichiometries(self.constant_values)
|
206
|
-
|
207
|
-
def update_constants(self, constants: dict[str, float]) -> None:
|
208
|
-
for name, value in constants.items():
|
209
|
-
self.update_constant(name, value)
|
210
|
-
|
211
|
-
def remove_constant(self, name: str) -> None:
|
212
|
-
self._names.remove(name)
|
213
|
-
self._constants.remove_basic(name)
|
214
|
-
|
215
|
-
def remove_constants(self, names: Iterable[str]) -> None:
|
216
|
-
for name in names:
|
217
|
-
self.remove_constant(name)
|
218
|
-
|
219
|
-
##########################################################################
|
220
|
-
# Derived Constants
|
221
|
-
##########################################################################
|
222
|
-
|
223
|
-
@add.register
|
224
|
-
def add_derived_constant(self, constant: DerivedConstant) -> None:
|
225
|
-
self._names.require_multiple(constant.args)
|
226
|
-
self._names.add(constant.name, "derived_constant")
|
227
|
-
self._constants.add_derived(constant)
|
228
|
-
|
229
|
-
def update_derived_constant(
|
230
|
-
self,
|
231
|
-
name: str,
|
232
|
-
function: Optional[RateFunction] = None,
|
233
|
-
args: Optional[Iterable[str]] = None,
|
234
|
-
unit: Optional[str] = None,
|
235
|
-
) -> None:
|
236
|
-
old = self.remove_derived_constant(name)
|
237
|
-
if function is None:
|
238
|
-
function = old.function
|
239
|
-
if args is None:
|
240
|
-
args = old.args
|
241
|
-
if unit is None:
|
242
|
-
unit = old.unit
|
243
|
-
self.add_derived_constant(DerivedConstant(name, function, list(args), unit))
|
244
|
-
self._reactions.update_derived_stoichiometries(self.constant_values)
|
245
|
-
|
246
|
-
def remove_derived_constant(self, name: str) -> DerivedConstant:
|
247
|
-
self._names.remove(name)
|
248
|
-
return self._constants.remove_derived(name)
|
249
|
-
|
250
|
-
def remove_derived_constants(self, names: Iterable[str]) -> None:
|
251
|
-
for name in names:
|
252
|
-
self.remove_derived_constant(name)
|
253
|
-
|
254
|
-
##########################################################################
|
255
|
-
# Variables
|
256
|
-
##########################################################################
|
257
|
-
|
258
|
-
@add.register
|
259
|
-
def add_variable(self, variable: Variable) -> None:
|
260
|
-
self._names.add(variable.name, "variable")
|
261
|
-
self._variables.add(variable)
|
262
|
-
|
263
|
-
def remove_variable(self, name: str) -> None:
|
264
|
-
self._names.remove(name)
|
265
|
-
self._variables.remove(name)
|
266
|
-
|
267
|
-
def remove_variables(self, names: Iterable[str]) -> None:
|
268
|
-
for name in names:
|
269
|
-
self.remove_variable(name)
|
270
|
-
|
271
|
-
##########################################################################
|
272
|
-
# Algebraic Modules
|
273
|
-
##########################################################################
|
274
|
-
|
275
|
-
def _get_available_args(self) -> set[str]:
|
276
|
-
return set(self.all_variables) | set(self._constants.values)
|
277
|
-
|
278
|
-
@add.register
|
279
|
-
def add_algebraic_module(self, module: AlgebraicModule) -> None:
|
280
|
-
for name in module.derived_variables:
|
281
|
-
self._names.add(name, "derived_variable")
|
282
|
-
self._names.require_multiple(module.args)
|
283
|
-
self._algebraic_modules.add(
|
284
|
-
module,
|
285
|
-
self._get_available_args(),
|
286
|
-
sort_modules=True,
|
287
|
-
)
|
288
|
-
|
289
|
-
def remove_algebraic_module(self, name: str) -> AlgebraicModule:
|
290
|
-
module = self._algebraic_modules.remove(
|
291
|
-
name,
|
292
|
-
set(),
|
293
|
-
sort_modules=False,
|
294
|
-
)
|
295
|
-
for name in module.derived_variables:
|
296
|
-
self._names.remove(name)
|
297
|
-
return module
|
298
|
-
|
299
|
-
def remove_algebraic_modules(self, names: Iterable[str]) -> None:
|
300
|
-
for name in names:
|
301
|
-
self.remove_algebraic_module(name)
|
302
|
-
|
303
|
-
def update_algebraic_module(
|
304
|
-
self,
|
305
|
-
name: str,
|
306
|
-
function: Optional[ModuleFunction] = None,
|
307
|
-
derived_variables: Optional[list[str]] = None,
|
308
|
-
args: Optional[list[str]] = None,
|
309
|
-
) -> None:
|
310
|
-
old_module = self.remove_algebraic_module(name)
|
311
|
-
if function is None:
|
312
|
-
function = old_module.function
|
313
|
-
if derived_variables is None:
|
314
|
-
derived_variables = old_module.derived_variables
|
315
|
-
if args is None:
|
316
|
-
args = old_module.args
|
317
|
-
self.add_algebraic_module(
|
318
|
-
AlgebraicModule(name, function, derived_variables, args)
|
319
|
-
)
|
320
|
-
|
321
|
-
self._algebraic_modules.update(
|
322
|
-
name,
|
323
|
-
function,
|
324
|
-
derived_variables,
|
325
|
-
args,
|
326
|
-
self._get_available_args(),
|
327
|
-
)
|
328
|
-
|
329
|
-
##########################################################################
|
330
|
-
# Reactions
|
331
|
-
##########################################################################
|
332
|
-
|
333
|
-
@add.register
|
334
|
-
def add_reaction(
|
335
|
-
self,
|
336
|
-
reaction: Reaction,
|
337
|
-
) -> None:
|
338
|
-
self._names.require_multiple(reaction.args)
|
339
|
-
self._reactions.add(reaction, self.constant_values)
|
340
|
-
|
341
|
-
def remove_reaction(self, name: str) -> None:
|
342
|
-
self._reactions.remove(name=name)
|
343
|
-
|
344
|
-
def remove_reactions(self, names: Iterable[str]) -> None:
|
345
|
-
for name in names:
|
346
|
-
self.remove_reaction(name=name)
|
347
|
-
|
348
|
-
def update_reaction(
|
349
|
-
self,
|
350
|
-
name: str,
|
351
|
-
function: Optional[RateFunction] = None,
|
352
|
-
stoichiometry: Optional[StoichiometryByReaction] = None,
|
353
|
-
# derived_stoichiometry: Optional[DerivedStoichiometry] = None,
|
354
|
-
derived_stoichiometry: Optional[dict[str, DerivedStoichiometry]] = None,
|
355
|
-
args: list[str] | None = None,
|
356
|
-
) -> None:
|
357
|
-
self._reactions.update(
|
358
|
-
name,
|
359
|
-
function,
|
360
|
-
stoichiometry,
|
361
|
-
derived_stoichiometry,
|
362
|
-
args,
|
363
|
-
self.constant_values,
|
364
|
-
)
|
365
|
-
|
366
|
-
def get_stoichiometries(self) -> pd.DataFrame:
|
367
|
-
return self._reactions.get_stoichiometries()
|
368
|
-
|
369
|
-
# ##########################################################################
|
370
|
-
# # Simulation functions
|
371
|
-
# ##########################################################################
|
372
|
-
|
373
|
-
def _get_problem(self, t: float, y: Iterable[float]) -> list[float]:
|
374
|
-
"""Integration function"""
|
375
|
-
variables = dict(zip(self.stoichiometries, y)) | {"time": t}
|
376
|
-
args = variables | self.constant_values
|
377
|
-
args |= self._algebraic_modules.get_values_float(args)
|
378
|
-
fluxes = self._reactions.get_fluxes_float(args)
|
379
|
-
rhs = self._reactions.get_right_hand_side_float(fluxes)
|
380
|
-
return list(rhs.values())
|
381
|
-
|
382
|
-
def _get_all_args(self, variables: dict[str, float], time: float) -> dict[str, float]:
|
383
|
-
args = variables | self.constant_values | {"time": time}
|
384
|
-
args |= self._algebraic_modules.get_values_float(args)
|
385
|
-
return args
|
386
|
-
|
387
|
-
def get_derived_variables(
|
388
|
-
self, variables: dict[str, float], time: float = 0.0
|
389
|
-
) -> dict[str, float]:
|
390
|
-
args = variables | self.constant_values | {"time": time}
|
391
|
-
return self._algebraic_modules.get_values_float(args)
|
392
|
-
|
393
|
-
@overload
|
394
|
-
def get_fluxes(
|
395
|
-
self,
|
396
|
-
variables: dict[str, float],
|
397
|
-
return_type: Literal["dict"],
|
398
|
-
time: float = 0,
|
399
|
-
) -> dict[str, float]:
|
400
|
-
...
|
401
|
-
|
402
|
-
@overload
|
403
|
-
def get_fluxes(
|
404
|
-
self,
|
405
|
-
variables: dict[str, float],
|
406
|
-
return_type: Literal["array"],
|
407
|
-
time: float = 0,
|
408
|
-
) -> Array:
|
409
|
-
...
|
410
|
-
|
411
|
-
@overload
|
412
|
-
def get_fluxes(
|
413
|
-
self,
|
414
|
-
variables: dict[str, float],
|
415
|
-
return_type: Literal["series"],
|
416
|
-
time: float = 0,
|
417
|
-
) -> Series:
|
418
|
-
...
|
419
|
-
|
420
|
-
@overload
|
421
|
-
def get_fluxes(
|
422
|
-
self,
|
423
|
-
variables: dict[str, float],
|
424
|
-
return_type: Literal["dict"] = "dict",
|
425
|
-
time: float = 0,
|
426
|
-
) -> dict[str, float]:
|
427
|
-
...
|
428
|
-
|
429
|
-
def get_fluxes(
|
430
|
-
self,
|
431
|
-
variables: dict[str, float],
|
432
|
-
return_type: Literal["array", "dict", "series"] = "dict",
|
433
|
-
time: float = 0.0,
|
434
|
-
) -> Union[Array, dict[str, float], pd.Series]:
|
435
|
-
args = self._get_all_args(variables, time)
|
436
|
-
fluxes_dict = self._reactions.get_fluxes_float(args)
|
437
|
-
if return_type == "dict":
|
438
|
-
return fluxes_dict
|
439
|
-
elif return_type == "series":
|
440
|
-
return pd.Series(fluxes_dict)
|
441
|
-
elif return_type == "array":
|
442
|
-
return np.fromiter(fluxes_dict.values(), dtype="float")
|
443
|
-
else:
|
444
|
-
raise NotImplementedError(f"Unknown return type {return_type}")
|
445
|
-
|
446
|
-
def get_right_hand_side(
|
447
|
-
self, variables: dict[str, float], time: float = 0.0
|
448
|
-
) -> dict[str, float]:
|
449
|
-
fluxes = self.get_fluxes(variables, time=time)
|
450
|
-
return self._reactions.get_right_hand_side_float(fluxes)
|
451
|
-
|
452
|
-
def to_version_1(self) -> OldModel:
|
453
|
-
old = OldModel()
|
454
|
-
|
455
|
-
old.add_compounds(list(self.variables))
|
456
|
-
|
457
|
-
old.add_parameters({k: v.value for k, v in self.constants.items()})
|
458
|
-
|
459
|
-
for k in _sort_derived_compounds(self):
|
460
|
-
dc = self.derived_constants[k]
|
461
|
-
old.add_derived_parameter(k, dc.function, dc.args)
|
462
|
-
|
463
|
-
for k, am in self.algebraic_modules.items():
|
464
|
-
old.add_algebraic_module_from_args(
|
465
|
-
k, am.function, am.derived_variables, am.args
|
466
|
-
)
|
467
|
-
|
468
|
-
for r in self.reactions.values():
|
469
|
-
old.add_reaction_from_args(r.name, r.function, r.stoichiometry, r.args)
|
470
|
-
return old
|
modelbase2/ode/simulator.py
DELETED
@@ -1,153 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
|
3
|
-
import logging
|
4
|
-
import numpy as np
|
5
|
-
import pandas as pd
|
6
|
-
from ..types import Array
|
7
|
-
from .integrator import Assimulo
|
8
|
-
from .model import Model
|
9
|
-
from dataclasses import dataclass, field
|
10
|
-
from typing import Any, Optional, Type
|
11
|
-
|
12
|
-
logger = logging.getLogger()
|
13
|
-
|
14
|
-
|
15
|
-
@dataclass(repr=False)
|
16
|
-
class SimulationResult:
|
17
|
-
time: Array
|
18
|
-
values: dict[str, Array]
|
19
|
-
constants: dict[str, float]
|
20
|
-
|
21
|
-
def __repr__(self) -> str:
|
22
|
-
return f"Simulation until t={self.time[-1]}"
|
23
|
-
|
24
|
-
def to_frame(self) -> pd.DataFrame:
|
25
|
-
return pd.DataFrame(
|
26
|
-
data=self.values,
|
27
|
-
index=self.time, # type: ignore
|
28
|
-
)
|
29
|
-
|
30
|
-
|
31
|
-
def concatenate_results(results: list[SimulationResult]) -> pd.DataFrame:
|
32
|
-
df = results[0].to_frame()
|
33
|
-
if len(results) > 1:
|
34
|
-
for result in results[1:]:
|
35
|
-
df = pd.concat((df, result.to_frame().iloc[1:]))
|
36
|
-
return df
|
37
|
-
|
38
|
-
|
39
|
-
@dataclass(init=False)
|
40
|
-
class Simulator:
|
41
|
-
model: Model
|
42
|
-
integrator: Assimulo
|
43
|
-
y0: list[float] = field(default_factory=list)
|
44
|
-
# Could also be ResultContainer once you add other model types again
|
45
|
-
results: list[SimulationResult] = field(default_factory=list)
|
46
|
-
|
47
|
-
def __init__(
|
48
|
-
self,
|
49
|
-
model: Model,
|
50
|
-
integrator: Type[Assimulo],
|
51
|
-
y0: dict[str, float],
|
52
|
-
results: Optional[SimulationResult] = None,
|
53
|
-
):
|
54
|
-
self.model = model
|
55
|
-
self.update_y0(y0)
|
56
|
-
self.integrator = integrator(rhs=self.model._get_problem, y0=self.y0)
|
57
|
-
if results is None:
|
58
|
-
self.results = list()
|
59
|
-
|
60
|
-
def __reduce__(self) -> Any:
|
61
|
-
return (
|
62
|
-
self.__class__,
|
63
|
-
(
|
64
|
-
self.model,
|
65
|
-
self.integrator,
|
66
|
-
self.y0,
|
67
|
-
),
|
68
|
-
(("results", self.results),),
|
69
|
-
)
|
70
|
-
|
71
|
-
def update_y0(self, y0: dict[str, float]) -> None:
|
72
|
-
self.y0 = [y0[i] for i in self.model.stoichiometries]
|
73
|
-
|
74
|
-
def clear_results(self) -> None:
|
75
|
-
self.results = list()
|
76
|
-
self.integrator.reset()
|
77
|
-
|
78
|
-
def simulate(
|
79
|
-
self,
|
80
|
-
t_end: float,
|
81
|
-
) -> Optional[SimulationResult]:
|
82
|
-
if (integration := self.integrator.integrate(t_end, None, None)) is None:
|
83
|
-
logger.warning("Simulation failed")
|
84
|
-
return None
|
85
|
-
res = SimulationResult(
|
86
|
-
integration.time,
|
87
|
-
dict(zip(self.model.stoichiometries, integration.values.T)),
|
88
|
-
self.model.constant_values,
|
89
|
-
)
|
90
|
-
self.results.append(res)
|
91
|
-
return res
|
92
|
-
|
93
|
-
def simulate_to_steady_state(
|
94
|
-
self, tolerance: float = 1e-6
|
95
|
-
) -> Optional[dict[str, float]]:
|
96
|
-
if (
|
97
|
-
integration := self.integrator.integrate_to_steady_state(tolerance)
|
98
|
-
) is not None:
|
99
|
-
return dict(zip(self.model.stoichiometries, integration))
|
100
|
-
else:
|
101
|
-
logger.warning("Simulation failed")
|
102
|
-
return None
|
103
|
-
|
104
|
-
def get_results(self) -> pd.DataFrame:
|
105
|
-
return concatenate_results(self.results)
|
106
|
-
|
107
|
-
def _get_result_constants(self, result: SimulationResult) -> dict[str, Array]:
|
108
|
-
return {k: np.full(len(result.time), v) for k, v in result.constants.items()}
|
109
|
-
|
110
|
-
def _get_result_derived_variables(
|
111
|
-
self,
|
112
|
-
args: dict[str, Array],
|
113
|
-
) -> dict[str, Array]:
|
114
|
-
return self.model._algebraic_modules.get_values_array(args)
|
115
|
-
|
116
|
-
def _get_result_all_variables(
|
117
|
-
self, result: SimulationResult, constants: dict[str, Array]
|
118
|
-
) -> dict[str, Array]:
|
119
|
-
args = result.values | constants | {"time": result.time}
|
120
|
-
return result.values | self._get_result_derived_variables(args)
|
121
|
-
|
122
|
-
def _get_result_fluxes(self, result: SimulationResult) -> dict[str, Array]:
|
123
|
-
constants = self._get_result_constants(result)
|
124
|
-
all_variables = self._get_result_all_variables(result, constants)
|
125
|
-
args = all_variables | constants | {"time": result.time}
|
126
|
-
return self.model._reactions.get_fluxes_array(args)
|
127
|
-
|
128
|
-
def get_full_results(self) -> pd.DataFrame:
|
129
|
-
full_results: list[SimulationResult] = []
|
130
|
-
for result in self.results:
|
131
|
-
full_results.append(
|
132
|
-
SimulationResult(
|
133
|
-
values=self._get_result_all_variables(
|
134
|
-
result, self._get_result_constants(result)
|
135
|
-
),
|
136
|
-
time=result.time,
|
137
|
-
constants=result.constants,
|
138
|
-
)
|
139
|
-
)
|
140
|
-
return concatenate_results(full_results)
|
141
|
-
|
142
|
-
def get_fluxes(self) -> pd.DataFrame:
|
143
|
-
fluxes: list[SimulationResult] = []
|
144
|
-
for result in self.results:
|
145
|
-
result_fluxes = self._get_result_fluxes(result)
|
146
|
-
fluxes.append(
|
147
|
-
SimulationResult(
|
148
|
-
values=result_fluxes,
|
149
|
-
time=result.time,
|
150
|
-
constants=result.constants,
|
151
|
-
)
|
152
|
-
)
|
153
|
-
return concatenate_results(fluxes)
|
modelbase2/utils/__init__.py
DELETED
File without changes
|