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/types.py
CHANGED
@@ -17,9 +17,18 @@ Classes:
|
|
17
17
|
from __future__ import annotations
|
18
18
|
|
19
19
|
from abc import abstractmethod
|
20
|
-
from collections.abc import Callable, Iterable, Iterator, Mapping
|
20
|
+
from collections.abc import Callable, Hashable, Iterable, Iterator, Mapping
|
21
21
|
from dataclasses import dataclass, field
|
22
|
-
from typing import
|
22
|
+
from typing import (
|
23
|
+
TYPE_CHECKING,
|
24
|
+
Any,
|
25
|
+
Literal,
|
26
|
+
ParamSpec,
|
27
|
+
Protocol,
|
28
|
+
TypeVar,
|
29
|
+
cast,
|
30
|
+
overload,
|
31
|
+
)
|
23
32
|
|
24
33
|
import numpy as np
|
25
34
|
import pandas as pd
|
@@ -31,21 +40,24 @@ __all__ = [
|
|
31
40
|
"Array",
|
32
41
|
"ArrayLike",
|
33
42
|
"Derived",
|
43
|
+
"InitialAssignment",
|
34
44
|
"IntegratorProtocol",
|
35
45
|
"IntegratorType",
|
36
46
|
"McSteadyStates",
|
37
47
|
"MockSurrogate",
|
38
48
|
"Param",
|
39
49
|
"Parameter",
|
40
|
-
"
|
50
|
+
"ProtocolScan",
|
41
51
|
"RateFn",
|
42
52
|
"Reaction",
|
43
53
|
"Readout",
|
44
54
|
"ResponseCoefficients",
|
45
55
|
"ResponseCoefficientsByPars",
|
56
|
+
"Result",
|
46
57
|
"RetType",
|
47
|
-
"
|
48
|
-
"
|
58
|
+
"Rhs",
|
59
|
+
"SteadyStateScan",
|
60
|
+
"TimeCourseScan",
|
49
61
|
"Variable",
|
50
62
|
"unwrap",
|
51
63
|
"unwrap2",
|
@@ -54,7 +66,13 @@ __all__ = [
|
|
54
66
|
type RateFn = Callable[..., float]
|
55
67
|
type Array = NDArray[np.floating[Any]]
|
56
68
|
type ArrayLike = NDArray[np.floating[Any]] | pd.Index | list[float]
|
57
|
-
|
69
|
+
type Rhs = Callable[
|
70
|
+
[
|
71
|
+
float, # t
|
72
|
+
Iterable[float], # y
|
73
|
+
],
|
74
|
+
tuple[float, ...],
|
75
|
+
]
|
58
76
|
|
59
77
|
Param = ParamSpec("Param")
|
60
78
|
RetType = TypeVar("RetType")
|
@@ -110,8 +128,8 @@ class IntegratorProtocol(Protocol):
|
|
110
128
|
|
111
129
|
def __init__(
|
112
130
|
self,
|
113
|
-
rhs:
|
114
|
-
y0:
|
131
|
+
rhs: Rhs,
|
132
|
+
y0: tuple[float, ...],
|
115
133
|
jacobian: Callable | None = None,
|
116
134
|
) -> None:
|
117
135
|
"""Initialise the integrator."""
|
@@ -147,24 +165,29 @@ class IntegratorProtocol(Protocol):
|
|
147
165
|
|
148
166
|
|
149
167
|
type IntegratorType = Callable[
|
150
|
-
[
|
168
|
+
[
|
169
|
+
Rhs, # model
|
170
|
+
tuple[float, ...], # y0
|
171
|
+
Callable | None, # jacobian
|
172
|
+
],
|
173
|
+
IntegratorProtocol,
|
151
174
|
]
|
152
175
|
|
153
176
|
|
154
177
|
@dataclass
|
155
|
-
class
|
156
|
-
"""Container for
|
178
|
+
class Variable:
|
179
|
+
"""Container for variable meta information."""
|
157
180
|
|
158
|
-
|
181
|
+
initial_value: float | InitialAssignment
|
159
182
|
unit: sympy.Expr | None = None
|
160
183
|
source: str | None = None
|
161
184
|
|
162
185
|
|
163
186
|
@dataclass
|
164
|
-
class
|
165
|
-
"""Container for
|
187
|
+
class Parameter:
|
188
|
+
"""Container for parameter meta information."""
|
166
189
|
|
167
|
-
|
190
|
+
value: float | InitialAssignment
|
168
191
|
unit: sympy.Expr | None = None
|
169
192
|
source: str | None = None
|
170
193
|
|
@@ -200,6 +223,37 @@ class Derived:
|
|
200
223
|
args[name] = cast(float, self.fn(*(args[arg] for arg in self.args)))
|
201
224
|
|
202
225
|
|
226
|
+
@dataclass(kw_only=True, slots=True)
|
227
|
+
class InitialAssignment:
|
228
|
+
"""Container for a derived value."""
|
229
|
+
|
230
|
+
fn: RateFn
|
231
|
+
args: list[str]
|
232
|
+
unit: sympy.Expr | None = None
|
233
|
+
|
234
|
+
def calculate(self, args: dict[str, Any]) -> float:
|
235
|
+
"""Calculate the derived value.
|
236
|
+
|
237
|
+
Args:
|
238
|
+
args: Dictionary of args variables.
|
239
|
+
|
240
|
+
Returns:
|
241
|
+
The calculated derived value.
|
242
|
+
|
243
|
+
"""
|
244
|
+
return cast(float, self.fn(*(args[arg] for arg in self.args)))
|
245
|
+
|
246
|
+
def calculate_inpl(self, name: str, args: dict[str, Any]) -> None:
|
247
|
+
"""Calculate the derived value in place.
|
248
|
+
|
249
|
+
Args:
|
250
|
+
name: Name of the derived variable.
|
251
|
+
args: Dictionary of args variables.
|
252
|
+
|
253
|
+
"""
|
254
|
+
args[name] = cast(float, self.fn(*(args[arg] for arg in self.args)))
|
255
|
+
|
256
|
+
|
203
257
|
@dataclass(kw_only=True, slots=True)
|
204
258
|
class Readout:
|
205
259
|
"""Container for a readout."""
|
@@ -322,22 +376,417 @@ class MockSurrogate(AbstractSurrogate):
|
|
322
376
|
) # type: ignore
|
323
377
|
|
324
378
|
|
379
|
+
@dataclass(kw_only=True)
|
380
|
+
class AbstractEstimator:
|
381
|
+
"""Abstract class for parameter estimation using neural networks."""
|
382
|
+
|
383
|
+
parameter_names: list[str]
|
384
|
+
|
385
|
+
@abstractmethod
|
386
|
+
def predict(self, features: pd.Series | pd.DataFrame) -> pd.DataFrame:
|
387
|
+
"""Predict the target values for the given features."""
|
388
|
+
|
389
|
+
|
390
|
+
###############################################################################
|
391
|
+
# Simulation results
|
392
|
+
###############################################################################
|
393
|
+
|
394
|
+
|
395
|
+
def _normalise_split_results(
|
396
|
+
results: list[pd.DataFrame],
|
397
|
+
normalise: float | ArrayLike,
|
398
|
+
) -> list[pd.DataFrame]:
|
399
|
+
"""Normalize split results by a given factor or array.
|
400
|
+
|
401
|
+
Args:
|
402
|
+
results: List of DataFrames containing the results to normalize.
|
403
|
+
normalise: Normalization factor or array.
|
404
|
+
|
405
|
+
Returns:
|
406
|
+
list[pd.DataFrame]: List of normalized DataFrames.
|
407
|
+
|
408
|
+
"""
|
409
|
+
if isinstance(normalise, int | float):
|
410
|
+
return [i / normalise for i in results]
|
411
|
+
if len(normalise) == len(results):
|
412
|
+
return [(i.T / j).T for i, j in zip(results, normalise, strict=True)]
|
413
|
+
|
414
|
+
results = []
|
415
|
+
start = 0
|
416
|
+
end = 0
|
417
|
+
for i in results:
|
418
|
+
end += len(i)
|
419
|
+
results.append(i / np.reshape(normalise[start:end], (len(i), 1))) # type: ignore
|
420
|
+
start += end
|
421
|
+
return results
|
422
|
+
|
423
|
+
|
325
424
|
@dataclass(kw_only=True, slots=True)
|
326
|
-
class
|
327
|
-
"""
|
425
|
+
class Result:
|
426
|
+
"""Simulation results."""
|
427
|
+
|
428
|
+
model: Model
|
429
|
+
raw_variables: list[pd.DataFrame]
|
430
|
+
raw_parameters: list[dict[str, float]]
|
431
|
+
raw_args: list[pd.DataFrame] = field(default_factory=list)
|
432
|
+
|
433
|
+
@classmethod
|
434
|
+
def default(cls, model: Model, time_points: Array) -> Result:
|
435
|
+
"""Get result filled with NaNs."""
|
436
|
+
return Result(
|
437
|
+
model=model,
|
438
|
+
raw_variables=[
|
439
|
+
pd.DataFrame(
|
440
|
+
data=np.full(
|
441
|
+
shape=(len(time_points), len(model.get_variable_names())),
|
442
|
+
fill_value=np.nan,
|
443
|
+
),
|
444
|
+
index=time_points,
|
445
|
+
columns=model.get_variable_names(),
|
446
|
+
)
|
447
|
+
],
|
448
|
+
raw_parameters=[model.get_parameter_values()],
|
449
|
+
)
|
328
450
|
|
329
|
-
|
330
|
-
|
451
|
+
@property
|
452
|
+
def variables(self) -> pd.DataFrame:
|
453
|
+
"""Simulation variables."""
|
454
|
+
return self.get_variables(
|
455
|
+
include_derived_variables=True,
|
456
|
+
include_readouts=True,
|
457
|
+
concatenated=True,
|
458
|
+
normalise=None,
|
459
|
+
)
|
460
|
+
|
461
|
+
@property
|
462
|
+
def fluxes(self) -> pd.DataFrame:
|
463
|
+
"""Simulation fluxes."""
|
464
|
+
return self.get_fluxes()
|
465
|
+
|
466
|
+
def _compute_args(self) -> list[pd.DataFrame]:
|
467
|
+
# Already computed
|
468
|
+
if len(self.raw_args) > 0:
|
469
|
+
return self.raw_args
|
470
|
+
|
471
|
+
# Compute new otherwise
|
472
|
+
for res, p in zip(self.raw_variables, self.raw_parameters, strict=True):
|
473
|
+
self.model.update_parameters(p)
|
474
|
+
self.raw_args.append(
|
475
|
+
self.model.get_args_time_course(
|
476
|
+
variables=res,
|
477
|
+
include_variables=True,
|
478
|
+
include_parameters=True,
|
479
|
+
include_derived_parameters=True,
|
480
|
+
include_derived_variables=True,
|
481
|
+
include_reactions=True,
|
482
|
+
include_surrogate_variables=True,
|
483
|
+
include_surrogate_fluxes=True,
|
484
|
+
include_readouts=True,
|
485
|
+
)
|
486
|
+
)
|
487
|
+
return self.raw_args
|
488
|
+
|
489
|
+
def _select_data(
|
490
|
+
self,
|
491
|
+
dependent: list[pd.DataFrame],
|
492
|
+
*,
|
493
|
+
include_variables: bool = False,
|
494
|
+
include_parameters: bool = False,
|
495
|
+
include_derived_parameters: bool = False,
|
496
|
+
include_derived_variables: bool = False,
|
497
|
+
include_reactions: bool = False,
|
498
|
+
include_surrogate_variables: bool = False,
|
499
|
+
include_surrogate_fluxes: bool = False,
|
500
|
+
include_readouts: bool = False,
|
501
|
+
) -> list[pd.DataFrame]:
|
502
|
+
names = self.model.get_arg_names(
|
503
|
+
include_time=False,
|
504
|
+
include_variables=include_variables,
|
505
|
+
include_parameters=include_parameters,
|
506
|
+
include_derived_parameters=include_derived_parameters,
|
507
|
+
include_derived_variables=include_derived_variables,
|
508
|
+
include_reactions=include_reactions,
|
509
|
+
include_surrogate_variables=include_surrogate_variables,
|
510
|
+
include_surrogate_fluxes=include_surrogate_fluxes,
|
511
|
+
include_readouts=include_readouts,
|
512
|
+
)
|
513
|
+
return [i.loc[:, names] for i in dependent]
|
514
|
+
|
515
|
+
def _adjust_data(
|
516
|
+
self,
|
517
|
+
data: list[pd.DataFrame],
|
518
|
+
normalise: float | ArrayLike | None = None,
|
519
|
+
*,
|
520
|
+
concatenated: bool = True,
|
521
|
+
) -> pd.DataFrame | list[pd.DataFrame]:
|
522
|
+
if normalise is not None:
|
523
|
+
data = _normalise_split_results(data, normalise=normalise)
|
524
|
+
if concatenated:
|
525
|
+
return pd.concat(data, axis=0)
|
526
|
+
return data
|
527
|
+
|
528
|
+
@overload
|
529
|
+
def get_args( # type: ignore
|
530
|
+
self,
|
531
|
+
*,
|
532
|
+
include_variables: bool = True,
|
533
|
+
include_parameters: bool = False,
|
534
|
+
include_derived_parameters: bool = False,
|
535
|
+
include_derived_variables: bool = True,
|
536
|
+
include_reactions: bool = True,
|
537
|
+
include_surrogate_variables: bool = False,
|
538
|
+
include_surrogate_fluxes: bool = False,
|
539
|
+
include_readouts: bool = False,
|
540
|
+
concatenated: Literal[False],
|
541
|
+
normalise: float | ArrayLike | None = None,
|
542
|
+
) -> list[pd.DataFrame]: ...
|
543
|
+
|
544
|
+
@overload
|
545
|
+
def get_args(
|
546
|
+
self,
|
547
|
+
*,
|
548
|
+
include_variables: bool = True,
|
549
|
+
include_parameters: bool = False,
|
550
|
+
include_derived_parameters: bool = False,
|
551
|
+
include_derived_variables: bool = True,
|
552
|
+
include_reactions: bool = True,
|
553
|
+
include_surrogate_variables: bool = False,
|
554
|
+
include_surrogate_fluxes: bool = False,
|
555
|
+
include_readouts: bool = False,
|
556
|
+
concatenated: Literal[True],
|
557
|
+
normalise: float | ArrayLike | None = None,
|
558
|
+
) -> pd.DataFrame: ...
|
559
|
+
|
560
|
+
@overload
|
561
|
+
def get_args(
|
562
|
+
self,
|
563
|
+
*,
|
564
|
+
include_variables: bool = True,
|
565
|
+
include_parameters: bool = False,
|
566
|
+
include_derived_parameters: bool = False,
|
567
|
+
include_derived_variables: bool = True,
|
568
|
+
include_reactions: bool = True,
|
569
|
+
include_surrogate_variables: bool = False,
|
570
|
+
include_surrogate_fluxes: bool = False,
|
571
|
+
include_readouts: bool = False,
|
572
|
+
concatenated: bool = True,
|
573
|
+
normalise: float | ArrayLike | None = None,
|
574
|
+
) -> pd.DataFrame: ...
|
575
|
+
|
576
|
+
def get_args(
|
577
|
+
self,
|
578
|
+
*,
|
579
|
+
include_variables: bool = True,
|
580
|
+
include_parameters: bool = False,
|
581
|
+
include_derived_parameters: bool = False,
|
582
|
+
include_derived_variables: bool = True,
|
583
|
+
include_reactions: bool = True,
|
584
|
+
include_surrogate_variables: bool = False,
|
585
|
+
include_surrogate_fluxes: bool = False,
|
586
|
+
include_readouts: bool = False,
|
587
|
+
concatenated: bool = True,
|
588
|
+
normalise: float | ArrayLike | None = None,
|
589
|
+
) -> pd.DataFrame | list[pd.DataFrame]:
|
590
|
+
"""Get the variables over time.
|
591
|
+
|
592
|
+
Examples:
|
593
|
+
>>> Result().get_variables()
|
594
|
+
Time ATP NADPH
|
595
|
+
0.000000 1.000000 1.000000
|
596
|
+
0.000100 0.999900 0.999900
|
597
|
+
0.000200 0.999800 0.999800
|
598
|
+
|
599
|
+
"""
|
600
|
+
variables = self._select_data(
|
601
|
+
self._compute_args(),
|
602
|
+
include_variables=include_variables,
|
603
|
+
include_parameters=include_parameters,
|
604
|
+
include_derived_parameters=include_derived_parameters,
|
605
|
+
include_derived_variables=include_derived_variables,
|
606
|
+
include_reactions=include_reactions,
|
607
|
+
include_surrogate_variables=include_surrogate_variables,
|
608
|
+
include_surrogate_fluxes=include_surrogate_fluxes,
|
609
|
+
include_readouts=include_readouts,
|
610
|
+
)
|
611
|
+
return self._adjust_data(
|
612
|
+
variables, normalise=normalise, concatenated=concatenated
|
613
|
+
)
|
614
|
+
|
615
|
+
@overload
|
616
|
+
def get_variables( # type: ignore
|
617
|
+
self,
|
618
|
+
*,
|
619
|
+
include_derived_variables: bool = True,
|
620
|
+
include_readouts: bool = True,
|
621
|
+
concatenated: Literal[False],
|
622
|
+
normalise: float | ArrayLike | None = None,
|
623
|
+
) -> list[pd.DataFrame]: ...
|
624
|
+
|
625
|
+
@overload
|
626
|
+
def get_variables(
|
627
|
+
self,
|
628
|
+
*,
|
629
|
+
include_derived_variables: bool = True,
|
630
|
+
include_readouts: bool = True,
|
631
|
+
concatenated: Literal[True],
|
632
|
+
normalise: float | ArrayLike | None = None,
|
633
|
+
) -> pd.DataFrame: ...
|
634
|
+
|
635
|
+
@overload
|
636
|
+
def get_variables(
|
637
|
+
self,
|
638
|
+
*,
|
639
|
+
include_derived_variables: bool = True,
|
640
|
+
include_readouts: bool = True,
|
641
|
+
concatenated: bool = True,
|
642
|
+
normalise: float | ArrayLike | None = None,
|
643
|
+
) -> pd.DataFrame: ...
|
644
|
+
|
645
|
+
def get_variables(
|
646
|
+
self,
|
647
|
+
*,
|
648
|
+
include_derived_variables: bool = True,
|
649
|
+
include_readouts: bool = True,
|
650
|
+
concatenated: bool = True,
|
651
|
+
normalise: float | ArrayLike | None = None,
|
652
|
+
) -> pd.DataFrame | list[pd.DataFrame]:
|
653
|
+
"""Get the variables over time.
|
654
|
+
|
655
|
+
Examples:
|
656
|
+
>>> Result().get_variables()
|
657
|
+
Time ATP NADPH
|
658
|
+
0.000000 1.000000 1.000000
|
659
|
+
0.000100 0.999900 0.999900
|
660
|
+
0.000200 0.999800 0.999800
|
661
|
+
|
662
|
+
"""
|
663
|
+
if not include_derived_variables and not include_readouts:
|
664
|
+
return self._adjust_data(
|
665
|
+
self.raw_variables,
|
666
|
+
normalise=normalise,
|
667
|
+
concatenated=concatenated,
|
668
|
+
)
|
669
|
+
|
670
|
+
variables = self._select_data(
|
671
|
+
self._compute_args(),
|
672
|
+
include_variables=True,
|
673
|
+
include_derived_variables=include_derived_variables,
|
674
|
+
include_readouts=include_readouts,
|
675
|
+
)
|
676
|
+
return self._adjust_data(
|
677
|
+
variables, normalise=normalise, concatenated=concatenated
|
678
|
+
)
|
679
|
+
|
680
|
+
@overload
|
681
|
+
def get_fluxes( # type: ignore
|
682
|
+
self,
|
683
|
+
*,
|
684
|
+
include_surrogates: bool = True,
|
685
|
+
normalise: float | ArrayLike | None = None,
|
686
|
+
concatenated: Literal[False],
|
687
|
+
) -> list[pd.DataFrame]: ...
|
688
|
+
|
689
|
+
@overload
|
690
|
+
def get_fluxes(
|
691
|
+
self,
|
692
|
+
*,
|
693
|
+
include_surrogates: bool = True,
|
694
|
+
normalise: float | ArrayLike | None = None,
|
695
|
+
concatenated: Literal[True],
|
696
|
+
) -> pd.DataFrame: ...
|
697
|
+
|
698
|
+
@overload
|
699
|
+
def get_fluxes(
|
700
|
+
self,
|
701
|
+
*,
|
702
|
+
include_surrogates: bool = True,
|
703
|
+
normalise: float | ArrayLike | None = None,
|
704
|
+
concatenated: bool = True,
|
705
|
+
) -> pd.DataFrame: ...
|
706
|
+
|
707
|
+
def get_fluxes(
|
708
|
+
self,
|
709
|
+
*,
|
710
|
+
include_surrogates: bool = True,
|
711
|
+
normalise: float | ArrayLike | None = None,
|
712
|
+
concatenated: bool = True,
|
713
|
+
) -> pd.DataFrame | list[pd.DataFrame]:
|
714
|
+
"""Get the flux results.
|
715
|
+
|
716
|
+
Examples:
|
717
|
+
>>> Result.get_fluxes()
|
718
|
+
Time v1 v2
|
719
|
+
0.000000 1.000000 10.00000
|
720
|
+
0.000100 0.999900 9.999000
|
721
|
+
0.000200 0.999800 9.998000
|
722
|
+
|
723
|
+
Returns:
|
724
|
+
pd.DataFrame: DataFrame of fluxes.
|
725
|
+
|
726
|
+
"""
|
727
|
+
fluxes = self._select_data(
|
728
|
+
self._compute_args(),
|
729
|
+
include_reactions=True,
|
730
|
+
include_surrogate_fluxes=include_surrogates,
|
731
|
+
)
|
732
|
+
return self._adjust_data(
|
733
|
+
fluxes,
|
734
|
+
normalise=normalise,
|
735
|
+
concatenated=concatenated,
|
736
|
+
)
|
737
|
+
|
738
|
+
def get_combined(self) -> pd.DataFrame:
|
739
|
+
"""Get the variables and fluxes as a single pandas.DataFrame.
|
740
|
+
|
741
|
+
Examples:
|
742
|
+
>>> Result.get_combined()
|
743
|
+
Time ATP NADPH v1 v2
|
744
|
+
0.000000 1.000000 1.000000 1.000000 10.00000
|
745
|
+
0.000100 0.999900 0.999900 0.999900 9.999000
|
746
|
+
0.000200 0.999800 0.999800 0.999800 9.998000
|
747
|
+
|
748
|
+
Returns:
|
749
|
+
pd.DataFrame: DataFrame of fluxes.
|
750
|
+
|
751
|
+
"""
|
752
|
+
return pd.concat((self.variables, self.fluxes), axis=1)
|
753
|
+
|
754
|
+
def get_new_y0(self) -> dict[str, float]:
|
755
|
+
"""Get the new initial conditions after the simulation.
|
756
|
+
|
757
|
+
Examples:
|
758
|
+
>>> Simulator(model).simulate_to_steady_state().get_new_y0()
|
759
|
+
{"ATP": 1.0, "NADPH": 1.0}
|
760
|
+
|
761
|
+
"""
|
762
|
+
return dict(
|
763
|
+
self.get_variables(
|
764
|
+
include_derived_variables=False,
|
765
|
+
include_readouts=False,
|
766
|
+
).iloc[-1]
|
767
|
+
)
|
331
768
|
|
332
769
|
def __iter__(self) -> Iterator[pd.DataFrame]:
|
333
770
|
"""Iterate over the concentration and flux response coefficients."""
|
334
771
|
return iter((self.variables, self.fluxes))
|
335
772
|
|
773
|
+
|
774
|
+
@dataclass(kw_only=True, slots=True)
|
775
|
+
class ResponseCoefficients:
|
776
|
+
"""Container for response coefficients."""
|
777
|
+
|
778
|
+
variables: pd.DataFrame
|
779
|
+
fluxes: pd.DataFrame
|
780
|
+
|
336
781
|
@property
|
337
|
-
def
|
782
|
+
def combined(self) -> pd.DataFrame:
|
338
783
|
"""Return the response coefficients as a DataFrame."""
|
339
784
|
return pd.concat((self.variables, self.fluxes), axis=1)
|
340
785
|
|
786
|
+
def __iter__(self) -> Iterator[pd.DataFrame]:
|
787
|
+
"""Iterate over the concentration and flux response coefficients."""
|
788
|
+
return iter((self.variables, self.fluxes))
|
789
|
+
|
341
790
|
|
342
791
|
@dataclass(kw_only=True, slots=True)
|
343
792
|
class ResponseCoefficientsByPars:
|
@@ -347,124 +796,247 @@ class ResponseCoefficientsByPars:
|
|
347
796
|
fluxes: pd.DataFrame
|
348
797
|
parameters: pd.DataFrame
|
349
798
|
|
350
|
-
def __iter__(self) -> Iterator[pd.DataFrame]:
|
351
|
-
"""Iterate over the concentration and flux response coefficients."""
|
352
|
-
return iter((self.variables, self.fluxes))
|
353
|
-
|
354
799
|
@property
|
355
|
-
def
|
800
|
+
def combined(self) -> pd.DataFrame:
|
356
801
|
"""Return the response coefficients as a DataFrame."""
|
357
802
|
return pd.concat((self.variables, self.fluxes), axis=1)
|
358
803
|
|
804
|
+
def __iter__(self) -> Iterator[pd.DataFrame]:
|
805
|
+
"""Iterate over the concentration and flux response coefficients."""
|
806
|
+
return iter((self.variables, self.fluxes))
|
807
|
+
|
359
808
|
|
360
809
|
@dataclass(kw_only=True, slots=True)
|
361
|
-
class
|
362
|
-
"""Container for steady states."""
|
363
|
-
|
364
|
-
variables: pd.DataFrame
|
365
|
-
fluxes: pd.DataFrame
|
366
|
-
parameters: pd.DataFrame
|
810
|
+
class SteadyStateScan:
|
811
|
+
"""Container for steady states by scanned values."""
|
367
812
|
|
368
|
-
|
369
|
-
|
370
|
-
|
813
|
+
to_scan: pd.DataFrame
|
814
|
+
raw_index: pd.Index | pd.MultiIndex
|
815
|
+
raw_results: list[Result]
|
371
816
|
|
372
817
|
@property
|
373
|
-
def
|
374
|
-
"""Return
|
375
|
-
return pd.
|
818
|
+
def variables(self) -> pd.DataFrame:
|
819
|
+
"""Return steady-state variables by scan."""
|
820
|
+
return pd.DataFrame(
|
821
|
+
[i.variables.iloc[-1].T for i in self.raw_results], index=self.raw_index
|
822
|
+
)
|
376
823
|
|
824
|
+
@property
|
825
|
+
def fluxes(self) -> pd.DataFrame:
|
826
|
+
"""Return steady-state fluxes by scan."""
|
827
|
+
return pd.DataFrame(
|
828
|
+
[i.fluxes.iloc[-1].T for i in self.raw_results], index=self.raw_index
|
829
|
+
)
|
377
830
|
|
378
|
-
@
|
379
|
-
|
380
|
-
|
831
|
+
@property
|
832
|
+
def combined(self) -> pd.DataFrame:
|
833
|
+
"""Return steady-state args by scan."""
|
834
|
+
return self.get_args()
|
381
835
|
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
836
|
+
def get_args(
|
837
|
+
self,
|
838
|
+
*,
|
839
|
+
include_variables: bool = True,
|
840
|
+
include_parameters: bool = False,
|
841
|
+
include_derived_parameters: bool = False,
|
842
|
+
include_derived_variables: bool = True,
|
843
|
+
include_reactions: bool = True,
|
844
|
+
include_surrogate_variables: bool = False,
|
845
|
+
include_surrogate_fluxes: bool = False,
|
846
|
+
include_readouts: bool = False,
|
847
|
+
) -> pd.DataFrame:
|
848
|
+
"""Return steady-state args by scan."""
|
849
|
+
return pd.DataFrame(
|
850
|
+
[
|
851
|
+
i.get_args(
|
852
|
+
include_variables=include_variables,
|
853
|
+
include_parameters=include_parameters,
|
854
|
+
include_derived_parameters=include_derived_parameters,
|
855
|
+
include_derived_variables=include_derived_variables,
|
856
|
+
include_reactions=include_reactions,
|
857
|
+
include_surrogate_variables=include_surrogate_variables,
|
858
|
+
include_surrogate_fluxes=include_surrogate_fluxes,
|
859
|
+
include_readouts=include_readouts,
|
860
|
+
)
|
861
|
+
.iloc[-1]
|
862
|
+
.T
|
863
|
+
for i in self.raw_results
|
864
|
+
],
|
865
|
+
index=self.raw_index,
|
866
|
+
)
|
386
867
|
|
387
868
|
def __iter__(self) -> Iterator[pd.DataFrame]:
|
388
869
|
"""Iterate over the concentration and flux steady states."""
|
389
870
|
return iter((self.variables, self.fluxes))
|
390
871
|
|
391
|
-
@property
|
392
|
-
def results(self) -> pd.DataFrame:
|
393
|
-
"""Return the steady states as a DataFrame."""
|
394
|
-
return pd.concat((self.variables, self.fluxes), axis=1)
|
395
|
-
|
396
872
|
|
397
873
|
@dataclass(kw_only=True, slots=True)
|
398
|
-
class
|
399
|
-
"""Container for time courses by
|
874
|
+
class TimeCourseScan:
|
875
|
+
"""Container for time courses by scanned values."""
|
400
876
|
|
401
|
-
|
402
|
-
|
403
|
-
parameters: pd.DataFrame
|
877
|
+
to_scan: pd.DataFrame
|
878
|
+
raw_results: dict[Hashable, Result]
|
404
879
|
|
405
|
-
|
406
|
-
|
407
|
-
|
880
|
+
@property
|
881
|
+
def variables(self) -> pd.DataFrame:
|
882
|
+
"""Return all args of the time courses."""
|
883
|
+
return pd.concat(
|
884
|
+
{k: i.variables for k, i in self.raw_results.items()}, names=["n", "time"]
|
885
|
+
)
|
886
|
+
|
887
|
+
@property
|
888
|
+
def fluxes(self) -> pd.DataFrame:
|
889
|
+
"""Return all args of the time courses."""
|
890
|
+
return pd.concat(
|
891
|
+
{k: i.fluxes for k, i in self.raw_results.items()}, names=["n", "time"]
|
892
|
+
)
|
408
893
|
|
409
894
|
@property
|
410
|
-
def
|
895
|
+
def combined(self) -> pd.DataFrame:
|
411
896
|
"""Return the time courses as a DataFrame."""
|
412
|
-
return
|
897
|
+
return self.get_args()
|
898
|
+
|
899
|
+
def get_args(
|
900
|
+
self,
|
901
|
+
*,
|
902
|
+
include_variables: bool = True,
|
903
|
+
include_parameters: bool = False,
|
904
|
+
include_derived_parameters: bool = False,
|
905
|
+
include_derived_variables: bool = True,
|
906
|
+
include_reactions: bool = True,
|
907
|
+
include_surrogate_variables: bool = False,
|
908
|
+
include_surrogate_fluxes: bool = False,
|
909
|
+
include_readouts: bool = False,
|
910
|
+
) -> pd.DataFrame:
|
911
|
+
"""Return all args of the time courses."""
|
912
|
+
return pd.concat(
|
913
|
+
{
|
914
|
+
k: i.get_args(
|
915
|
+
include_variables=include_variables,
|
916
|
+
include_parameters=include_parameters,
|
917
|
+
include_derived_parameters=include_derived_parameters,
|
918
|
+
include_derived_variables=include_derived_variables,
|
919
|
+
include_reactions=include_reactions,
|
920
|
+
include_surrogate_variables=include_surrogate_variables,
|
921
|
+
include_surrogate_fluxes=include_surrogate_fluxes,
|
922
|
+
include_readouts=include_readouts,
|
923
|
+
)
|
924
|
+
for k, i in self.raw_results.items()
|
925
|
+
},
|
926
|
+
names=["n", "time"],
|
927
|
+
)
|
413
928
|
|
414
929
|
def get_by_name(self, name: str) -> pd.DataFrame:
|
415
930
|
"""Get time courses by name."""
|
416
|
-
return self.
|
931
|
+
return self.combined[name].unstack().T
|
417
932
|
|
418
933
|
def get_agg_per_time(self, agg: str | Callable) -> pd.DataFrame:
|
419
934
|
"""Get aggregated time courses."""
|
420
|
-
mean = cast(pd.DataFrame, self.
|
935
|
+
mean = cast(pd.DataFrame, self.combined.unstack(level=1).agg(agg, axis=0))
|
421
936
|
return cast(pd.DataFrame, mean.unstack().T)
|
422
937
|
|
423
938
|
def get_agg_per_run(self, agg: str | Callable) -> pd.DataFrame:
|
424
939
|
"""Get aggregated time courses."""
|
425
|
-
mean = cast(pd.DataFrame, self.
|
940
|
+
mean = cast(pd.DataFrame, self.combined.unstack(level=0).agg(agg, axis=0))
|
426
941
|
return cast(pd.DataFrame, mean.unstack().T)
|
427
942
|
|
943
|
+
def __iter__(self) -> Iterator[pd.DataFrame]:
|
944
|
+
"""Iterate over the concentration and flux time courses."""
|
945
|
+
return iter((self.variables, self.fluxes))
|
946
|
+
|
428
947
|
|
429
948
|
@dataclass(kw_only=True, slots=True)
|
430
|
-
class
|
431
|
-
"""Container for protocols by
|
949
|
+
class ProtocolScan:
|
950
|
+
"""Container for protocols by scanned values."""
|
432
951
|
|
433
|
-
|
434
|
-
fluxes: pd.DataFrame
|
435
|
-
parameters: pd.DataFrame
|
952
|
+
to_scan: pd.DataFrame
|
436
953
|
protocol: pd.DataFrame
|
954
|
+
raw_results: dict[Hashable, Result]
|
437
955
|
|
438
|
-
|
439
|
-
|
440
|
-
|
956
|
+
@property
|
957
|
+
def variables(self) -> pd.DataFrame:
|
958
|
+
"""Return all args of the time courses."""
|
959
|
+
return pd.concat(
|
960
|
+
{k: i.variables for k, i in self.raw_results.items()},
|
961
|
+
names=["n", "time"],
|
962
|
+
)
|
441
963
|
|
442
964
|
@property
|
443
|
-
def
|
444
|
-
"""Return
|
445
|
-
return pd.concat(
|
965
|
+
def fluxes(self) -> pd.DataFrame:
|
966
|
+
"""Return all args of the time courses."""
|
967
|
+
return pd.concat(
|
968
|
+
{k: i.fluxes for k, i in self.raw_results.items()},
|
969
|
+
names=["n", "time"],
|
970
|
+
)
|
971
|
+
|
972
|
+
@property
|
973
|
+
def combined(self) -> pd.DataFrame:
|
974
|
+
"""Return the time courses as a DataFrame."""
|
975
|
+
return self.get_args()
|
976
|
+
|
977
|
+
def get_args(
|
978
|
+
self,
|
979
|
+
*,
|
980
|
+
include_variables: bool = True,
|
981
|
+
include_parameters: bool = False,
|
982
|
+
include_derived_parameters: bool = False,
|
983
|
+
include_derived_variables: bool = True,
|
984
|
+
include_reactions: bool = True,
|
985
|
+
include_surrogate_variables: bool = False,
|
986
|
+
include_surrogate_fluxes: bool = False,
|
987
|
+
include_readouts: bool = False,
|
988
|
+
) -> pd.DataFrame:
|
989
|
+
"""Return all args of the time courses."""
|
990
|
+
return pd.concat(
|
991
|
+
{
|
992
|
+
k: i.get_args(
|
993
|
+
include_variables=include_variables,
|
994
|
+
include_parameters=include_parameters,
|
995
|
+
include_derived_parameters=include_derived_parameters,
|
996
|
+
include_derived_variables=include_derived_variables,
|
997
|
+
include_reactions=include_reactions,
|
998
|
+
include_surrogate_variables=include_surrogate_variables,
|
999
|
+
include_surrogate_fluxes=include_surrogate_fluxes,
|
1000
|
+
include_readouts=include_readouts,
|
1001
|
+
)
|
1002
|
+
for k, i in self.raw_results.items()
|
1003
|
+
},
|
1004
|
+
names=["n", "time"],
|
1005
|
+
)
|
446
1006
|
|
447
1007
|
def get_by_name(self, name: str) -> pd.DataFrame:
|
448
1008
|
"""Get concentration or flux by name."""
|
449
|
-
return self.
|
1009
|
+
return self.combined[name].unstack().T
|
450
1010
|
|
451
1011
|
def get_agg_per_time(self, agg: str | Callable) -> pd.DataFrame:
|
452
1012
|
"""Get aggregated concentration or flux."""
|
453
|
-
mean = cast(pd.DataFrame, self.
|
1013
|
+
mean = cast(pd.DataFrame, self.combined.unstack(level=1).agg(agg, axis=0))
|
454
1014
|
return cast(pd.DataFrame, mean.unstack().T)
|
455
1015
|
|
456
1016
|
def get_agg_per_run(self, agg: str | Callable) -> pd.DataFrame:
|
457
1017
|
"""Get aggregated concentration or flux."""
|
458
|
-
mean = cast(pd.DataFrame, self.
|
1018
|
+
mean = cast(pd.DataFrame, self.combined.unstack(level=0).agg(agg, axis=0))
|
459
1019
|
return cast(pd.DataFrame, mean.unstack().T)
|
460
1020
|
|
1021
|
+
def __iter__(self) -> Iterator[pd.DataFrame]:
|
1022
|
+
"""Iterate over the concentration and flux protocols."""
|
1023
|
+
return iter((self.variables, self.fluxes))
|
461
1024
|
|
462
|
-
@dataclass(kw_only=True)
|
463
|
-
class AbstractEstimator:
|
464
|
-
"""Abstract class for parameter estimation using neural networks."""
|
465
1025
|
|
466
|
-
|
1026
|
+
@dataclass(kw_only=True, slots=True)
|
1027
|
+
class McSteadyStates:
|
1028
|
+
"""Container for Monte Carlo steady states."""
|
467
1029
|
|
468
|
-
|
469
|
-
|
470
|
-
|
1030
|
+
variables: pd.DataFrame
|
1031
|
+
fluxes: pd.DataFrame
|
1032
|
+
parameters: pd.DataFrame
|
1033
|
+
mc_to_scan: pd.DataFrame
|
1034
|
+
|
1035
|
+
@property
|
1036
|
+
def combined(self) -> pd.DataFrame:
|
1037
|
+
"""Return the steady states as a DataFrame."""
|
1038
|
+
return pd.concat((self.variables, self.fluxes), axis=1)
|
1039
|
+
|
1040
|
+
def __iter__(self) -> Iterator[pd.DataFrame]:
|
1041
|
+
"""Iterate over the concentration and flux steady states."""
|
1042
|
+
return iter((self.variables, self.fluxes))
|