modelbase2 0.1.79__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.79.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.79.dist-info/METADATA +0 -44
- modelbase2-0.1.79.dist-info/RECORD +0 -22
- {modelbase2-0.1.79.dist-info → modelbase2-0.2.0.dist-info/licenses}/LICENSE +0 -0
modelbase2/types.py
CHANGED
@@ -1,20 +1,361 @@
|
|
1
|
+
"""Types Module.
|
2
|
+
|
3
|
+
This module provides type definitions and utility types for use throughout the project.
|
4
|
+
It includes type aliases for arrays, numbers, and callable functions, as well as re-exports
|
5
|
+
of common types from standard libraries.
|
6
|
+
|
7
|
+
Classes:
|
8
|
+
DerivedFn: Callable type for derived functions.
|
9
|
+
Array: Type alias for numpy arrays of float64.
|
10
|
+
Number: Type alias for float, list of floats, or numpy arrays.
|
11
|
+
Param: Type alias for parameter specifications.
|
12
|
+
RetType: Type alias for return types.
|
13
|
+
Axes: Type alias for numpy arrays of matplotlib axes.
|
14
|
+
ArrayLike: Type alias for numpy arrays or lists of floats.
|
15
|
+
"""
|
16
|
+
|
1
17
|
from __future__ import annotations
|
2
18
|
|
19
|
+
from abc import abstractmethod
|
20
|
+
from dataclasses import dataclass, field
|
21
|
+
|
22
|
+
import pandas as pd
|
23
|
+
|
3
24
|
__all__ = [
|
25
|
+
"AbstractSurrogate",
|
4
26
|
"Array",
|
5
|
-
"
|
6
|
-
"
|
7
|
-
"
|
8
|
-
"
|
27
|
+
"ArrayLike",
|
28
|
+
"Derived",
|
29
|
+
"Float",
|
30
|
+
"IntegratorProtocol",
|
31
|
+
"McSteadyStates",
|
32
|
+
"MockSurrogate",
|
33
|
+
"Param",
|
34
|
+
"ProtocolByPars",
|
35
|
+
"RateFn",
|
36
|
+
"Reaction",
|
37
|
+
"Readout",
|
38
|
+
"ResponseCoefficients",
|
39
|
+
"ResponseCoefficientsByPars",
|
40
|
+
"RetType",
|
41
|
+
"SteadyStates",
|
42
|
+
"TimeCourseByPars",
|
43
|
+
"unwrap",
|
44
|
+
"unwrap2",
|
9
45
|
]
|
10
46
|
|
47
|
+
# Re-exporting some types here, because their imports have
|
48
|
+
# changed between Python versions and I have no interest in
|
49
|
+
# fixing it in every file
|
50
|
+
from collections.abc import Callable, Iterator, Mapping
|
51
|
+
from typing import TYPE_CHECKING, Any, ParamSpec, Protocol, TypeVar, cast
|
52
|
+
|
11
53
|
import numpy as np
|
12
54
|
import numpy.typing as npt
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
55
|
+
from numpy.typing import NDArray
|
56
|
+
|
57
|
+
type Float = npt.NDArray[np.floating[Any]] | float
|
58
|
+
type RateFn = Callable[..., Float]
|
59
|
+
type Array = NDArray[np.floating[Any]]
|
60
|
+
type ArrayLike = NDArray[np.floating[Any]] | list[float]
|
61
|
+
|
62
|
+
|
63
|
+
Param = ParamSpec("Param")
|
64
|
+
RetType = TypeVar("RetType")
|
65
|
+
|
66
|
+
|
67
|
+
if TYPE_CHECKING:
|
68
|
+
from modelbase2.model import Model
|
69
|
+
|
70
|
+
|
71
|
+
def unwrap[T](el: T | None) -> T:
|
72
|
+
"""Unwraps an optional value, raising an error if the value is None.
|
73
|
+
|
74
|
+
Args:
|
75
|
+
el: The value to unwrap. It can be of type T or None.
|
76
|
+
|
77
|
+
Returns:
|
78
|
+
The unwrapped value if it is not None.
|
79
|
+
|
80
|
+
Raises:
|
81
|
+
ValueError: If the provided value is None.
|
82
|
+
|
83
|
+
"""
|
84
|
+
if el is None:
|
85
|
+
msg = "Unexpected None"
|
86
|
+
raise ValueError(msg)
|
87
|
+
return el
|
88
|
+
|
89
|
+
|
90
|
+
def unwrap2[T1, T2](tpl: tuple[T1 | None, T2 | None]) -> tuple[T1, T2]:
|
91
|
+
"""Unwraps a tuple of optional values, raising an error if either of them is None.
|
92
|
+
|
93
|
+
Args:
|
94
|
+
tpl: The value to unwrap.
|
95
|
+
|
96
|
+
Returns:
|
97
|
+
The unwrapped values if it is not None.
|
98
|
+
|
99
|
+
Raises:
|
100
|
+
ValueError: If the provided value is None.
|
101
|
+
|
102
|
+
"""
|
103
|
+
a, b = tpl
|
104
|
+
if a is None or b is None:
|
105
|
+
msg = "Unexpected None"
|
106
|
+
raise ValueError(msg)
|
107
|
+
return a, b
|
108
|
+
|
109
|
+
|
110
|
+
class IntegratorProtocol(Protocol):
|
111
|
+
"""Protocol for numerical integrators."""
|
112
|
+
|
113
|
+
def __init__(
|
114
|
+
self,
|
115
|
+
rhs: Callable,
|
116
|
+
y0: ArrayLike,
|
117
|
+
) -> None:
|
118
|
+
"""Initialise the integrator."""
|
119
|
+
...
|
120
|
+
|
121
|
+
def reset(self) -> None:
|
122
|
+
"""Reset the integrator."""
|
123
|
+
...
|
124
|
+
|
125
|
+
def integrate(
|
126
|
+
self,
|
127
|
+
*,
|
128
|
+
t_end: float,
|
129
|
+
steps: int | None = None,
|
130
|
+
) -> tuple[ArrayLike | None, ArrayLike | None]:
|
131
|
+
"""Integrate the system."""
|
132
|
+
...
|
133
|
+
|
134
|
+
def integrate_time_course(
|
135
|
+
self, *, time_points: ArrayLike
|
136
|
+
) -> tuple[ArrayLike | None, ArrayLike | None]:
|
137
|
+
"""Integrate the system over a time course."""
|
138
|
+
...
|
139
|
+
|
140
|
+
def integrate_to_steady_state(
|
141
|
+
self,
|
142
|
+
*,
|
143
|
+
tolerance: float,
|
144
|
+
rel_norm: bool,
|
145
|
+
) -> tuple[float | None, ArrayLike | None]:
|
146
|
+
"""Integrate the system to steady state."""
|
147
|
+
...
|
148
|
+
|
149
|
+
|
150
|
+
@dataclass(slots=True)
|
151
|
+
class Derived:
|
152
|
+
"""Container for a derived value."""
|
153
|
+
|
154
|
+
fn: RateFn
|
155
|
+
args: list[str]
|
156
|
+
math: str | None = None
|
157
|
+
|
158
|
+
|
159
|
+
@dataclass(slots=True)
|
160
|
+
class Readout:
|
161
|
+
"""Container for a readout."""
|
162
|
+
|
163
|
+
fn: RateFn
|
164
|
+
args: list[str]
|
165
|
+
|
166
|
+
|
167
|
+
@dataclass(slots=True)
|
168
|
+
class Reaction:
|
169
|
+
"""Container for a reaction."""
|
170
|
+
|
171
|
+
fn: RateFn
|
172
|
+
stoichiometry: Mapping[str, float | Derived]
|
173
|
+
args: list[str]
|
174
|
+
math: str | None = None
|
175
|
+
|
176
|
+
def get_modifiers(self, model: Model) -> list[str]:
|
177
|
+
"""Get the modifiers of the reaction."""
|
178
|
+
include = set(model.variables)
|
179
|
+
exclude = set(self.stoichiometry)
|
180
|
+
|
181
|
+
return [k for k in self.args if k in include and k not in exclude]
|
182
|
+
|
183
|
+
|
184
|
+
@dataclass(slots=True)
|
185
|
+
class ResponseCoefficients:
|
186
|
+
"""Container for response coefficients."""
|
187
|
+
|
188
|
+
concs: pd.DataFrame
|
189
|
+
fluxes: pd.DataFrame
|
190
|
+
|
191
|
+
def __iter__(self) -> Iterator[pd.DataFrame]:
|
192
|
+
"""Iterate over the concentration and flux response coefficients."""
|
193
|
+
return iter((self.concs, self.fluxes))
|
194
|
+
|
195
|
+
@property
|
196
|
+
def results(self) -> pd.DataFrame:
|
197
|
+
"""Return the response coefficients as a DataFrame."""
|
198
|
+
return pd.concat((self.concs, self.fluxes), axis=1)
|
199
|
+
|
200
|
+
|
201
|
+
@dataclass(slots=True)
|
202
|
+
class ResponseCoefficientsByPars:
|
203
|
+
"""Container for response coefficients by parameter."""
|
204
|
+
|
205
|
+
concs: pd.DataFrame
|
206
|
+
fluxes: pd.DataFrame
|
207
|
+
parameters: pd.DataFrame
|
208
|
+
|
209
|
+
def __iter__(self) -> Iterator[pd.DataFrame]:
|
210
|
+
"""Iterate over the concentration and flux response coefficients."""
|
211
|
+
return iter((self.concs, self.fluxes))
|
212
|
+
|
213
|
+
@property
|
214
|
+
def results(self) -> pd.DataFrame:
|
215
|
+
"""Return the response coefficients as a DataFrame."""
|
216
|
+
return pd.concat((self.concs, self.fluxes), axis=1)
|
217
|
+
|
218
|
+
|
219
|
+
@dataclass(slots=True)
|
220
|
+
class SteadyStates:
|
221
|
+
"""Container for steady states."""
|
222
|
+
|
223
|
+
concs: pd.DataFrame
|
224
|
+
fluxes: pd.DataFrame
|
225
|
+
parameters: pd.DataFrame
|
226
|
+
|
227
|
+
def __iter__(self) -> Iterator[pd.DataFrame]:
|
228
|
+
"""Iterate over the concentration and flux steady states."""
|
229
|
+
return iter((self.concs, self.fluxes))
|
230
|
+
|
231
|
+
@property
|
232
|
+
def results(self) -> pd.DataFrame:
|
233
|
+
"""Return the steady states as a DataFrame."""
|
234
|
+
return pd.concat((self.concs, self.fluxes), axis=1)
|
235
|
+
|
236
|
+
|
237
|
+
@dataclass(slots=True)
|
238
|
+
class McSteadyStates:
|
239
|
+
"""Container for Monte Carlo steady states."""
|
240
|
+
|
241
|
+
concs: pd.DataFrame
|
242
|
+
fluxes: pd.DataFrame
|
243
|
+
parameters: pd.DataFrame
|
244
|
+
mc_parameters: pd.DataFrame
|
245
|
+
|
246
|
+
def __iter__(self) -> Iterator[pd.DataFrame]:
|
247
|
+
"""Iterate over the concentration and flux steady states."""
|
248
|
+
return iter((self.concs, self.fluxes))
|
249
|
+
|
250
|
+
@property
|
251
|
+
def results(self) -> pd.DataFrame:
|
252
|
+
"""Return the steady states as a DataFrame."""
|
253
|
+
return pd.concat((self.concs, self.fluxes), axis=1)
|
254
|
+
|
255
|
+
|
256
|
+
@dataclass(slots=True)
|
257
|
+
class TimeCourseByPars:
|
258
|
+
"""Container for time courses by parameter."""
|
259
|
+
|
260
|
+
concs: pd.DataFrame
|
261
|
+
fluxes: pd.DataFrame
|
262
|
+
parameters: pd.DataFrame
|
263
|
+
|
264
|
+
def __iter__(self) -> Iterator[pd.DataFrame]:
|
265
|
+
"""Iterate over the concentration and flux time courses."""
|
266
|
+
return iter((self.concs, self.fluxes))
|
267
|
+
|
268
|
+
@property
|
269
|
+
def results(self) -> pd.DataFrame:
|
270
|
+
"""Return the time courses as a DataFrame."""
|
271
|
+
return pd.concat((self.concs, self.fluxes), axis=1)
|
272
|
+
|
273
|
+
def get_by_name(self, name: str) -> pd.DataFrame:
|
274
|
+
"""Get time courses by name."""
|
275
|
+
return self.results[name].unstack().T
|
276
|
+
|
277
|
+
def get_agg_per_time(self, agg: str | Callable) -> pd.DataFrame:
|
278
|
+
"""Get aggregated time courses."""
|
279
|
+
mean = cast(pd.DataFrame, self.results.unstack(level=1).agg(agg, axis=0))
|
280
|
+
return cast(pd.DataFrame, mean.unstack().T)
|
281
|
+
|
282
|
+
def get_agg_per_run(self, agg: str | Callable) -> pd.DataFrame:
|
283
|
+
"""Get aggregated time courses."""
|
284
|
+
mean = cast(pd.DataFrame, self.results.unstack(level=0).agg(agg, axis=0))
|
285
|
+
return cast(pd.DataFrame, mean.unstack().T)
|
286
|
+
|
287
|
+
|
288
|
+
@dataclass(slots=True)
|
289
|
+
class ProtocolByPars:
|
290
|
+
"""Container for protocols by parameter."""
|
291
|
+
|
292
|
+
concs: pd.DataFrame
|
293
|
+
fluxes: pd.DataFrame
|
294
|
+
parameters: pd.DataFrame
|
295
|
+
protocol: pd.DataFrame
|
296
|
+
|
297
|
+
def __iter__(self) -> Iterator[pd.DataFrame]:
|
298
|
+
"""Iterate over the concentration and flux protocols."""
|
299
|
+
return iter((self.concs, self.fluxes))
|
300
|
+
|
301
|
+
@property
|
302
|
+
def results(self) -> pd.DataFrame:
|
303
|
+
"""Return the protocols as a DataFrame."""
|
304
|
+
return pd.concat((self.concs, self.fluxes), axis=1)
|
305
|
+
|
306
|
+
def get_by_name(self, name: str) -> pd.DataFrame:
|
307
|
+
"""Get concentration or flux by name."""
|
308
|
+
return self.results[name].unstack().T
|
309
|
+
|
310
|
+
def get_agg_per_time(self, agg: str | Callable) -> pd.DataFrame:
|
311
|
+
"""Get aggregated concentration or flux."""
|
312
|
+
mean = cast(pd.DataFrame, self.results.unstack(level=1).agg(agg, axis=0))
|
313
|
+
return cast(pd.DataFrame, mean.unstack().T)
|
314
|
+
|
315
|
+
def get_agg_per_run(self, agg: str | Callable) -> pd.DataFrame:
|
316
|
+
"""Get aggregated concentration or flux."""
|
317
|
+
mean = cast(pd.DataFrame, self.results.unstack(level=0).agg(agg, axis=0))
|
318
|
+
return cast(pd.DataFrame, mean.unstack().T)
|
319
|
+
|
320
|
+
|
321
|
+
@dataclass(kw_only=True)
|
322
|
+
class AbstractSurrogate:
|
323
|
+
"""Abstract base class for surrogate models.
|
324
|
+
|
325
|
+
Attributes:
|
326
|
+
inputs: List of input variable names.
|
327
|
+
stoichiometries: Dictionary mapping reaction names to stoichiometries.
|
328
|
+
|
329
|
+
Methods:
|
330
|
+
predict: Abstract method to predict outputs based on input data.
|
331
|
+
|
332
|
+
"""
|
333
|
+
|
334
|
+
args: list[str] = field(default_factory=list)
|
335
|
+
stoichiometries: dict[str, dict[str, float]] = field(default_factory=dict)
|
336
|
+
|
337
|
+
@abstractmethod
|
338
|
+
def predict_raw(self, y: np.ndarray) -> np.ndarray:
|
339
|
+
"""Predict outputs based on input data."""
|
340
|
+
|
341
|
+
def predict(self, y: np.ndarray) -> dict[str, float]:
|
342
|
+
"""Predict outputs based on input data."""
|
343
|
+
return dict(
|
344
|
+
zip(
|
345
|
+
self.stoichiometries,
|
346
|
+
self.predict_raw(y),
|
347
|
+
strict=True,
|
348
|
+
)
|
349
|
+
)
|
350
|
+
|
351
|
+
|
352
|
+
@dataclass(kw_only=True)
|
353
|
+
class MockSurrogate(AbstractSurrogate):
|
354
|
+
"""Mock surrogate model for testing purposes."""
|
17
355
|
|
18
|
-
|
19
|
-
|
20
|
-
|
356
|
+
def predict_raw(
|
357
|
+
self,
|
358
|
+
y: np.ndarray,
|
359
|
+
) -> np.ndarray:
|
360
|
+
"""Predict outputs based on input data."""
|
361
|
+
return y
|
@@ -0,0 +1,81 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: modelbase2
|
3
|
+
Version: 0.2.0
|
4
|
+
Summary: A package to build metabolic models
|
5
|
+
Author-email: Marvin van Aalst <marvin.vanaalst@gmail.com>
|
6
|
+
Maintainer-email: Marvin van Aalst <marvin.vanaalst@gmail.com>
|
7
|
+
License-Expression: GPL-3.0-or-later
|
8
|
+
License-File: LICENSE
|
9
|
+
Keywords: metabolic,modelling,ode
|
10
|
+
Classifier: Development Status :: 5 - Production/Stable
|
11
|
+
Classifier: Environment :: Console
|
12
|
+
Classifier: Intended Audience :: Developers
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
14
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
|
15
|
+
Classifier: Operating System :: MacOS
|
16
|
+
Classifier: Operating System :: Microsoft :: Windows
|
17
|
+
Classifier: Operating System :: OS Independent
|
18
|
+
Classifier: Operating System :: POSIX
|
19
|
+
Classifier: Operating System :: Unix
|
20
|
+
Classifier: Programming Language :: Python :: 3
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
22
|
+
Classifier: Topic :: Scientific/Engineering
|
23
|
+
Classifier: Topic :: Software Development
|
24
|
+
Requires-Python: >=3.12
|
25
|
+
Requires-Dist: dill>=0.3.9
|
26
|
+
Requires-Dist: latexify-py>=0.4.4
|
27
|
+
Requires-Dist: matplotlib>=3.9.2
|
28
|
+
Requires-Dist: more-itertools>=10.5.0
|
29
|
+
Requires-Dist: numpy>=2.1.2
|
30
|
+
Requires-Dist: pandas>=2.2.3
|
31
|
+
Requires-Dist: parameteriser>=0.1.0
|
32
|
+
Requires-Dist: pebble>=5.0.7
|
33
|
+
Requires-Dist: python-libsbml>=5.20.4
|
34
|
+
Requires-Dist: scipy>=1.14.1
|
35
|
+
Requires-Dist: seaborn>=0.13.2
|
36
|
+
Requires-Dist: sympy>=1.13.1
|
37
|
+
Requires-Dist: tabulate>=0.9.0
|
38
|
+
Requires-Dist: tqdm>=4.66.6
|
39
|
+
Requires-Dist: typing-extensions>=4.12.2
|
40
|
+
Provides-Extra: dev
|
41
|
+
Requires-Dist: coverage>=7.6.4; extra == 'dev'
|
42
|
+
Requires-Dist: jupyter>=1.1.1; extra == 'dev'
|
43
|
+
Requires-Dist: mkdocs-jupyter>=0.25.1; extra == 'dev'
|
44
|
+
Requires-Dist: mkdocs-material>=9.5.42; extra == 'dev'
|
45
|
+
Requires-Dist: mkdocs>=1.6.1; extra == 'dev'
|
46
|
+
Requires-Dist: mypy>=1.13.0; extra == 'dev'
|
47
|
+
Requires-Dist: pre-commit>=4.0.1; extra == 'dev'
|
48
|
+
Requires-Dist: pyright>=1.1.387; extra == 'dev'
|
49
|
+
Requires-Dist: pytest-cov>=5.0.0; extra == 'dev'
|
50
|
+
Requires-Dist: pytest>=8.3.3; extra == 'dev'
|
51
|
+
Requires-Dist: qtbmodels<0.2,>=0.1.0; extra == 'dev'
|
52
|
+
Requires-Dist: requests>=2.32.3; extra == 'dev'
|
53
|
+
Requires-Dist: ruff>=0.7.1; extra == 'dev'
|
54
|
+
Requires-Dist: ssort>=0.13.0; extra == 'dev'
|
55
|
+
Requires-Dist: toml-sort<0.24,>=0.23.1; extra == 'dev'
|
56
|
+
Provides-Extra: torch
|
57
|
+
Requires-Dist: torch>=2.5.1; extra == 'torch'
|
58
|
+
Description-Content-Type: text/markdown
|
59
|
+
|
60
|
+
# modelbase
|
61
|
+
|
62
|
+
|
63
|
+
## Development setup
|
64
|
+
|
65
|
+
You have two choices here, using `uv` (pypi-only) or using `pixi` (conda-forge, including assimulo)
|
66
|
+
|
67
|
+
### uv
|
68
|
+
|
69
|
+
- Install `uv` as described in [the docs](https://docs.astral.sh/uv/getting-started/installation/).
|
70
|
+
- Run `uv sync --extra dev --extra torch` to install dependencies locally
|
71
|
+
|
72
|
+
### pixi
|
73
|
+
|
74
|
+
- Install `pixi` as described in [the docs](https://pixi.sh/latest/#installation)
|
75
|
+
- Run `pixi install --frozen`
|
76
|
+
|
77
|
+
|
78
|
+
## Notes
|
79
|
+
|
80
|
+
- `uv add $package`
|
81
|
+
- `uv add --optional dev $package`
|
@@ -0,0 +1,42 @@
|
|
1
|
+
modelbase2/__init__.py,sha256=mGA_ckCmdG8Bi1i_eiES7JShez_4qwobwRVYaMBe27E,3967
|
2
|
+
modelbase2/distributions.py,sha256=sbqmkw3PTPK0vWOcIFqP3WXH_2Q3i-_pl_NmvAYCngM,7927
|
3
|
+
modelbase2/fit.py,sha256=kCuwsuUs9DSRyeQXmP6RSclGGMVL1Q7XD3KLhu073yo,8010
|
4
|
+
modelbase2/fns.py,sha256=8JtIzPk3DAnNHz3LoJ1ukLFTjPNO1rNCeZ7VnRmJY2o,4503
|
5
|
+
modelbase2/label_map.py,sha256=LUwcOHQWiGfBGV5XUmPM_SOwM9IyDVcQVJ11DPfVpAo,17774
|
6
|
+
modelbase2/linear_label_map.py,sha256=gA8CHxcehgtI6ovwZ9qNUPDvxfqbO1J1kBC_mltD4TY,10225
|
7
|
+
modelbase2/mc.py,sha256=zlDL7e_udpIMRhSjfFJo5AwkigD0B_3H2rQxyelBuzI,16285
|
8
|
+
modelbase2/mca.py,sha256=nMS2VnzR2VEujCFUaj9WL82CNd-oxTb3jCHP8IlJvxA,8845
|
9
|
+
modelbase2/model.py,sha256=SJloqNi8C5oSrIyknMkXfPFDBHPW-ybrT_F9nsbREzQ,53854
|
10
|
+
modelbase2/npe.py,sha256=fSnEyXvsS1h3S7rIbPtRW2oeJc917yt73rSw75Het3o,11199
|
11
|
+
modelbase2/parallel.py,sha256=kX4Td5YoovDwZp6kX_3cfO6QtHSS9ieJ0bMZiKs3Xv8,5002
|
12
|
+
modelbase2/parameterise.py,sha256=7VrYxrQv0visraqUthWSnWfx-cxh2evlXbszIY5031U,690
|
13
|
+
modelbase2/paths.py,sha256=uatKXDa79uniUB2Z3dr8eBJVuUPXDI-o_bf-DqPKq1Y,1039
|
14
|
+
modelbase2/plot.py,sha256=tsQRUeKFKpthWOw8JqKhqcxBTBaMscJlemJzNpENAnc,22640
|
15
|
+
modelbase2/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
16
|
+
modelbase2/scan.py,sha256=PvWZA4EgNS0JVMvm87bF72hSmhvo6O2KGg4vRzxve_8,18104
|
17
|
+
modelbase2/scope.py,sha256=4twnEh8LrTmlLE-uRvubVkE3SSWejlLvtBzTCPqG3Aw,3710
|
18
|
+
modelbase2/simulator.py,sha256=3UIAjGa6AUosd7384I4s9kVyFuY6H0bPcqIm19QpTIQ,19708
|
19
|
+
modelbase2/surrogates.py,sha256=XGXZaFwO8CZsATbFohkuK0eQdTR_hsVEUPJyzfIKpSk,9121
|
20
|
+
modelbase2/types.py,sha256=N74pWUZDcGlSMfDkjqqwHn5dkozlqgS6Wqg-58YKdvg,9904
|
21
|
+
modelbase2/experimental/__init__.py,sha256=En8_KLrfA5RulThEr_Zx2D1n0H0wv1L0Rj6EBwWz7RM,379
|
22
|
+
modelbase2/experimental/codegen.py,sha256=J_0iCtojwjmDXAfC8EqiXP0gmWaSH8MPkWvdLsZWsXU,6962
|
23
|
+
modelbase2/experimental/diff.py,sha256=e7fjD9kqxkRUNxSevbAznd5cOlEdWJ6pj0y7Kd5KKrw,8973
|
24
|
+
modelbase2/experimental/notes.md,sha256=YlM2biTzub6jSlx-aDZaBYsvQcGwb7NHyVAbbl2acGE,238
|
25
|
+
modelbase2/experimental/tex.py,sha256=M-Pdq3eQw1Huo-z1gv8EhWVO5ecJyFS8MMy9yoX81VI,13634
|
26
|
+
modelbase2/integrators/__init__.py,sha256=kqmV6a0TRyLGR_XqbyAI652AfptYnXAUpqbSFg0CpP8,450
|
27
|
+
modelbase2/integrators/int_assimulo.py,sha256=VEQIZFZcEovLPy8i_jR8H8XcxBRQoRVmNzzCYzInPc0,4611
|
28
|
+
modelbase2/integrators/int_scipy.py,sha256=-_9MS55eTc9jI7tk-3X49p-c7zrydoXaCCvDTn7Tybw,4334
|
29
|
+
modelbase2/sbml/__init__.py,sha256=FBaQsVvrVc7QbCBXuG9tZOdSzHcqmmsaRbFx80rxrac,231
|
30
|
+
modelbase2/sbml/_data.py,sha256=XwT1sSxn6KLTXYMbk4ORbEAEgZhQDBfoyrjMBDAoY_s,1135
|
31
|
+
modelbase2/sbml/_export.py,sha256=9BLD3Qz86vlfDTZXwOnNOSVWq8mHrJoQjQmKJRZL_Wo,20285
|
32
|
+
modelbase2/sbml/_import.py,sha256=uT5JpFvCKjQNBFmGPba61xYShHmjzjczqnaYflilSMI,21523
|
33
|
+
modelbase2/sbml/_mathml.py,sha256=bNk9RQ_NQFDhY1R354p-gwqqHaIiyAwZ1xLPHHhiguQ,24436
|
34
|
+
modelbase2/sbml/_name_conversion.py,sha256=XK9DEyzhrD0GBBwwjK9RA0yORrDX5c-Uvx0VtKMR5rA,1325
|
35
|
+
modelbase2/sbml/_unit_conversion.py,sha256=dW_I6_Ou09ccwnp6LIdrPriIQnQUK5lJcjzM2Fawm6U,1927
|
36
|
+
modelbase2/surrogates/__init__.py,sha256=0OH8BmdB5toHo7sXcZHZVASx3EEnpzcc7TeTP2tF5Ek,944
|
37
|
+
modelbase2/surrogates/_poly.py,sha256=zKeoj3FchMAIgbnq99VkH_RfLsdy6N5lZaV0AeG9JKs,2185
|
38
|
+
modelbase2/surrogates/_torch.py,sha256=7XHES1NyVmGTc8qmcScsfroai6rJVeV4eAGU2-oqH9A,7402
|
39
|
+
modelbase2-0.2.0.dist-info/METADATA,sha256=f3af5XY5IQ0GkvPWYqUcnFJ79EKxxDjufw8Z2yCwk3o,2853
|
40
|
+
modelbase2-0.2.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
41
|
+
modelbase2-0.2.0.dist-info/licenses/LICENSE,sha256=qvG2VolmSkrcocL34V1ieOx-Rn-fpVcUbb25gHzVgZw,35079
|
42
|
+
modelbase2-0.2.0.dist-info/RECORD,,
|
modelbase2/core/__init__.py
DELETED
@@ -1,29 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
|
3
|
-
__all__ = [
|
4
|
-
"AlgebraicModule",
|
5
|
-
"AlgebraicModuleContainer",
|
6
|
-
"Constant",
|
7
|
-
"ConstantContainer",
|
8
|
-
"DerivedConstant",
|
9
|
-
"DerivedStoichiometry",
|
10
|
-
"NameContainer",
|
11
|
-
"Reaction",
|
12
|
-
"ReactionContainer",
|
13
|
-
"Variable",
|
14
|
-
"VariableContainer",
|
15
|
-
]
|
16
|
-
|
17
|
-
from .algebraic_module_container import AlgebraicModuleContainer
|
18
|
-
from .constant_container import ConstantContainer
|
19
|
-
from .data import (
|
20
|
-
AlgebraicModule,
|
21
|
-
Constant,
|
22
|
-
DerivedConstant,
|
23
|
-
DerivedStoichiometry,
|
24
|
-
Reaction,
|
25
|
-
Variable,
|
26
|
-
)
|
27
|
-
from .name_container import NameContainer
|
28
|
-
from .reaction_container import ReactionContainer
|
29
|
-
from .variable_container import VariableContainer
|
@@ -1,130 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
|
3
|
-
import logging
|
4
|
-
from ..types import Array
|
5
|
-
from .data import AlgebraicModule, ModuleFunction
|
6
|
-
from dataclasses import dataclass, field
|
7
|
-
from queue import Empty, SimpleQueue
|
8
|
-
from typing import Iterable, Iterator, Optional, cast
|
9
|
-
|
10
|
-
logger = logging.getLogger(__name__)
|
11
|
-
|
12
|
-
|
13
|
-
@dataclass
|
14
|
-
class AlgebraicModuleContainer:
|
15
|
-
modules: dict[str, AlgebraicModule] = field(default_factory=dict)
|
16
|
-
module_order: list[str] = field(default_factory=list)
|
17
|
-
|
18
|
-
def __iter__(self) -> Iterator[AlgebraicModule]:
|
19
|
-
return iter(self.modules.values())
|
20
|
-
|
21
|
-
def _sort_algebraic_modules(
|
22
|
-
self, available_args: set[str], max_iterations: int = 10_000
|
23
|
-
) -> None:
|
24
|
-
module_order = []
|
25
|
-
modules_to_sort: SimpleQueue[tuple[str, AlgebraicModule]] = SimpleQueue()
|
26
|
-
for k, v in self.modules.items():
|
27
|
-
modules_to_sort.put((k, v))
|
28
|
-
|
29
|
-
last_name = None
|
30
|
-
i = 0
|
31
|
-
while True:
|
32
|
-
try:
|
33
|
-
name, mod = modules_to_sort.get_nowait()
|
34
|
-
except Empty:
|
35
|
-
break
|
36
|
-
if set(mod.args).issubset(available_args):
|
37
|
-
available_args.update(mod.derived_variables)
|
38
|
-
module_order.append(name)
|
39
|
-
else:
|
40
|
-
if last_name == name:
|
41
|
-
module_order.append(name)
|
42
|
-
break
|
43
|
-
modules_to_sort.put((name, mod))
|
44
|
-
last_name = name
|
45
|
-
i += 1
|
46
|
-
if i > max_iterations:
|
47
|
-
raise ValueError(
|
48
|
-
"Exceeded max iterations on algebraic module sorting. Check if there are circular references."
|
49
|
-
)
|
50
|
-
self.module_order = module_order
|
51
|
-
|
52
|
-
def get_derived_variables(self) -> list[str]:
|
53
|
-
return [
|
54
|
-
variable
|
55
|
-
for module in self.modules.values()
|
56
|
-
for variable in module.derived_variables
|
57
|
-
]
|
58
|
-
|
59
|
-
def add(
|
60
|
-
self,
|
61
|
-
module: AlgebraicModule,
|
62
|
-
available_args: set[str],
|
63
|
-
sort_modules: bool,
|
64
|
-
) -> None:
|
65
|
-
if (name := module.name) in self.modules:
|
66
|
-
raise KeyError(f"Module {name} already exists.")
|
67
|
-
logger.info(f"Adding algebraic module {name}")
|
68
|
-
self.modules[name] = module
|
69
|
-
if sort_modules:
|
70
|
-
self._sort_algebraic_modules(available_args)
|
71
|
-
|
72
|
-
def update(
|
73
|
-
self,
|
74
|
-
name: str,
|
75
|
-
function: Optional[ModuleFunction],
|
76
|
-
derived_variables: Optional[list[str]],
|
77
|
-
args: Optional[list[str]],
|
78
|
-
available_args: set[str],
|
79
|
-
) -> None:
|
80
|
-
module = self.remove(name, available_args, sort_modules=False)
|
81
|
-
if function is not None:
|
82
|
-
module.function = function
|
83
|
-
if derived_variables is not None:
|
84
|
-
module.derived_variables = derived_variables
|
85
|
-
if args is not None:
|
86
|
-
module.args = args
|
87
|
-
self.add(module, available_args, sort_modules=True)
|
88
|
-
|
89
|
-
def remove(
|
90
|
-
self,
|
91
|
-
name: str,
|
92
|
-
available_args: set[str],
|
93
|
-
sort_modules: bool,
|
94
|
-
) -> AlgebraicModule:
|
95
|
-
logger.info(f"Removing algebraic module {name}")
|
96
|
-
module = self.modules.pop(name)
|
97
|
-
if sort_modules:
|
98
|
-
self._sort_algebraic_modules(available_args)
|
99
|
-
return module
|
100
|
-
|
101
|
-
##########################################################################
|
102
|
-
# Simulation functions
|
103
|
-
##########################################################################
|
104
|
-
|
105
|
-
def get_values_float(self, args: dict[str, float]) -> dict[str, float]:
|
106
|
-
derived_variables: dict[str, float] = {}
|
107
|
-
for name in self.module_order:
|
108
|
-
module = self.modules[name]
|
109
|
-
_values = module.function(*(args[arg] for arg in module.args))
|
110
|
-
values = dict(zip(module.derived_variables, _values))
|
111
|
-
derived_variables |= values
|
112
|
-
args |= values
|
113
|
-
return derived_variables
|
114
|
-
|
115
|
-
def get_values_array(
|
116
|
-
self,
|
117
|
-
args: dict[str, Array],
|
118
|
-
) -> dict[str, Array]:
|
119
|
-
derived_variables: dict[str, Array] = {}
|
120
|
-
for name in self.module_order:
|
121
|
-
module = self.modules[name]
|
122
|
-
# values = np.array(module.function(*(args[arg] for arg in module.args)), dtype=float)
|
123
|
-
# values = values.reshape((len(module.derived_variables), -1))
|
124
|
-
_values = cast(
|
125
|
-
Iterable[Array], module.function(*(args[arg] for arg in module.args))
|
126
|
-
)
|
127
|
-
values = dict(zip(module.derived_variables, _values))
|
128
|
-
derived_variables |= values
|
129
|
-
args |= values
|
130
|
-
return derived_variables
|