mxlpy 0.23.0__py3-none-any.whl → 0.25.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 +6 -6
- mxlpy/carousel.py +46 -1
- mxlpy/compare.py +13 -0
- mxlpy/experimental/diff.py +14 -0
- mxlpy/fit/__init__.py +9 -0
- mxlpy/fit/common.py +298 -0
- mxlpy/fit/global_.py +534 -0
- mxlpy/{fit.py → fit/local_.py} +105 -308
- mxlpy/identify.py +5 -4
- mxlpy/mc.py +63 -2
- mxlpy/meta/__init__.py +6 -1
- mxlpy/meta/codegen_latex.py +9 -0
- mxlpy/meta/codegen_model.py +53 -11
- mxlpy/meta/codegen_mxlpy.py +21 -0
- mxlpy/meta/source_tools.py +5 -0
- mxlpy/meta/sympy_tools.py +7 -1
- mxlpy/model.py +56 -11
- mxlpy/plot.py +44 -15
- mxlpy/sbml/_data.py +34 -0
- mxlpy/sbml/_export.py +4 -3
- mxlpy/scan.py +125 -7
- mxlpy/simulator.py +5 -0
- mxlpy/types.py +244 -2
- {mxlpy-0.23.0.dist-info → mxlpy-0.25.0.dist-info}/METADATA +12 -2
- {mxlpy-0.23.0.dist-info → mxlpy-0.25.0.dist-info}/RECORD +27 -24
- {mxlpy-0.23.0.dist-info → mxlpy-0.25.0.dist-info}/WHEEL +0 -0
- {mxlpy-0.23.0.dist-info → mxlpy-0.25.0.dist-info}/licenses/LICENSE +0 -0
mxlpy/{fit.py → fit/local_.py}
RENAMED
@@ -1,27 +1,39 @@
|
|
1
|
-
"""Parameter
|
1
|
+
"""Parameter local fitting Module for Metabolic Models.
|
2
2
|
|
3
|
-
This module provides functions
|
4
|
-
including both steadyd-state and time-series data fitting capabilities.
|
5
|
-
|
6
|
-
Functions:
|
7
|
-
fit_steady_state: Fits parameters to steady-state experimental data
|
8
|
-
fit_time_course: Fits parameters to time-series experimental data
|
3
|
+
This module provides functions for fitting model parameters to experimental data,
|
4
|
+
including both steadyd-state and time-series data fitting capabilities.
|
9
5
|
"""
|
10
6
|
|
11
7
|
from __future__ import annotations
|
12
8
|
|
13
9
|
import logging
|
10
|
+
from collections.abc import Callable
|
14
11
|
from copy import deepcopy
|
15
12
|
from dataclasses import dataclass
|
16
13
|
from functools import partial
|
17
|
-
from typing import TYPE_CHECKING,
|
14
|
+
from typing import TYPE_CHECKING, Literal
|
18
15
|
|
19
|
-
import numpy as np
|
20
16
|
from scipy.optimize import minimize
|
21
17
|
|
22
18
|
from mxlpy import parallel
|
23
|
-
from mxlpy.
|
24
|
-
|
19
|
+
from mxlpy.types import IntegratorType, cast
|
20
|
+
|
21
|
+
from .common import (
|
22
|
+
Bounds,
|
23
|
+
CarouselFit,
|
24
|
+
FitResult,
|
25
|
+
InitialGuess,
|
26
|
+
LossFn,
|
27
|
+
MinResult,
|
28
|
+
ProtocolResidualFn,
|
29
|
+
ResidualFn,
|
30
|
+
SteadyStateResidualFn,
|
31
|
+
TimeSeriesResidualFn,
|
32
|
+
_protocol_time_course_residual,
|
33
|
+
_steady_state_residual,
|
34
|
+
_time_course_residual,
|
35
|
+
rmse,
|
36
|
+
)
|
25
37
|
|
26
38
|
if TYPE_CHECKING:
|
27
39
|
import pandas as pd
|
@@ -32,60 +44,19 @@ if TYPE_CHECKING:
|
|
32
44
|
LOGGER = logging.getLogger(__name__)
|
33
45
|
|
34
46
|
__all__ = [
|
35
|
-
"Bounds",
|
36
|
-
"CarouselFit",
|
37
|
-
"FitResult",
|
38
|
-
"InitialGuess",
|
39
47
|
"LOGGER",
|
40
|
-
"
|
41
|
-
"
|
42
|
-
"MinimizeFn",
|
43
|
-
"ProtocolResidualFn",
|
44
|
-
"ResidualFn",
|
45
|
-
"SteadyStateResidualFn",
|
46
|
-
"TimeSeriesResidualFn",
|
48
|
+
"Minimizer",
|
49
|
+
"ScipyMinimizer",
|
47
50
|
"carousel_protocol_time_course",
|
48
51
|
"carousel_steady_state",
|
49
52
|
"carousel_time_course",
|
50
53
|
"protocol_time_course",
|
51
|
-
"rmse",
|
52
54
|
"steady_state",
|
53
55
|
"time_course",
|
54
56
|
]
|
55
57
|
|
56
58
|
|
57
|
-
|
58
|
-
class MinResult:
|
59
|
-
"""Result of a minimization operation."""
|
60
|
-
|
61
|
-
parameters: dict[str, float]
|
62
|
-
residual: float
|
63
|
-
|
64
|
-
|
65
|
-
@dataclass
|
66
|
-
class FitResult:
|
67
|
-
"""Result of a fit operation."""
|
68
|
-
|
69
|
-
model: Model
|
70
|
-
best_pars: dict[str, float]
|
71
|
-
loss: float
|
72
|
-
|
73
|
-
|
74
|
-
@dataclass
|
75
|
-
class CarouselFit:
|
76
|
-
"""Result of a carousel fit operation."""
|
77
|
-
|
78
|
-
fits: list[FitResult]
|
79
|
-
|
80
|
-
def get_best_fit(self) -> FitResult:
|
81
|
-
"""Get the best fit from the carousel."""
|
82
|
-
return min(self.fits, key=lambda x: x.loss)
|
83
|
-
|
84
|
-
|
85
|
-
type InitialGuess = dict[str, float]
|
86
|
-
type ResidualFn = Callable[[Array], float]
|
87
|
-
type Bounds = dict[str, tuple[float | None, float | None]]
|
88
|
-
type MinimizeFn = Callable[
|
59
|
+
type Minimizer = Callable[
|
89
60
|
[
|
90
61
|
ResidualFn,
|
91
62
|
InitialGuess,
|
@@ -93,248 +64,68 @@ type MinimizeFn = Callable[
|
|
93
64
|
],
|
94
65
|
MinResult | None,
|
95
66
|
]
|
96
|
-
type LossFn = Callable[
|
97
|
-
[
|
98
|
-
pd.DataFrame | pd.Series,
|
99
|
-
pd.DataFrame | pd.Series,
|
100
|
-
],
|
101
|
-
float,
|
102
|
-
]
|
103
|
-
|
104
67
|
|
105
|
-
def rmse(
|
106
|
-
y_pred: pd.DataFrame | pd.Series,
|
107
|
-
y_true: pd.DataFrame | pd.Series,
|
108
|
-
) -> float:
|
109
|
-
"""Calculate root mean square error between model and data."""
|
110
|
-
return cast(float, np.sqrt(np.mean(np.square(y_pred - y_true))))
|
111
68
|
|
69
|
+
@dataclass
|
70
|
+
class ScipyMinimizer:
|
71
|
+
"""Local multivariate minimization using scipy.optimize.
|
112
72
|
|
113
|
-
|
114
|
-
|
73
|
+
See Also
|
74
|
+
--------
|
75
|
+
https://docs.scipy.org/doc/scipy/reference/optimize.html#local-multivariate-optimization
|
115
76
|
|
116
|
-
|
117
|
-
self,
|
118
|
-
par_values: Array,
|
119
|
-
# This will be filled out by partial
|
120
|
-
par_names: list[str],
|
121
|
-
data: pd.Series,
|
122
|
-
model: Model,
|
123
|
-
y0: dict[str, float] | None,
|
124
|
-
integrator: IntegratorType,
|
125
|
-
loss_fn: LossFn,
|
126
|
-
) -> float:
|
127
|
-
"""Calculate residual error between model steady state and experimental data."""
|
128
|
-
...
|
129
|
-
|
130
|
-
|
131
|
-
class TimeSeriesResidualFn(Protocol):
|
132
|
-
"""Protocol for time series residual functions."""
|
77
|
+
"""
|
133
78
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
""
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
79
|
+
tol: float = 1e-6
|
80
|
+
method: Literal[
|
81
|
+
"Nelder-Mead",
|
82
|
+
"Powell",
|
83
|
+
"CG",
|
84
|
+
"BFGS",
|
85
|
+
"Newton-CG",
|
86
|
+
"L-BFGS-B",
|
87
|
+
"TNC",
|
88
|
+
"COBYLA",
|
89
|
+
"COBYQA",
|
90
|
+
"SLSQP",
|
91
|
+
"trust-constr",
|
92
|
+
"dogleg",
|
93
|
+
"trust-ncg",
|
94
|
+
"trust-exact",
|
95
|
+
"trust-krylov",
|
96
|
+
] = "L-BFGS-B"
|
151
97
|
|
152
98
|
def __call__(
|
153
99
|
self,
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
...
|
166
|
-
|
167
|
-
|
168
|
-
def _default_minimize_fn(
|
169
|
-
residual_fn: ResidualFn,
|
170
|
-
p0: dict[str, float],
|
171
|
-
bounds: Bounds,
|
172
|
-
) -> MinResult | None:
|
173
|
-
res = minimize(
|
174
|
-
residual_fn,
|
175
|
-
x0=list(p0.values()),
|
176
|
-
bounds=[bounds.get(name, (1e-6, 1e6)) for name in p0],
|
177
|
-
method="L-BFGS-B",
|
178
|
-
)
|
179
|
-
if res.success:
|
180
|
-
return MinResult(
|
181
|
-
parameters=dict(
|
182
|
-
zip(
|
183
|
-
p0,
|
184
|
-
res.x,
|
185
|
-
strict=True,
|
186
|
-
),
|
187
|
-
),
|
188
|
-
residual=res.fun,
|
100
|
+
residual_fn: ResidualFn,
|
101
|
+
p0: dict[str, float],
|
102
|
+
bounds: Bounds,
|
103
|
+
) -> MinResult | None:
|
104
|
+
"""Call minimzer."""
|
105
|
+
res = minimize(
|
106
|
+
residual_fn,
|
107
|
+
x0=list(p0.values()),
|
108
|
+
bounds=[bounds.get(name, (1e-6, 1e6)) for name in p0],
|
109
|
+
method=self.method,
|
110
|
+
tol=self.tol,
|
189
111
|
)
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
def _steady_state_residual(
|
196
|
-
par_values: Array,
|
197
|
-
# This will be filled out by partial
|
198
|
-
par_names: list[str],
|
199
|
-
data: pd.Series,
|
200
|
-
model: Model,
|
201
|
-
y0: dict[str, float] | None,
|
202
|
-
integrator: IntegratorType,
|
203
|
-
loss_fn: LossFn,
|
204
|
-
) -> float:
|
205
|
-
"""Calculate residual error between model steady state and experimental data.
|
206
|
-
|
207
|
-
Args:
|
208
|
-
par_values: Parameter values to test
|
209
|
-
data: Experimental steady state data
|
210
|
-
model: Model instance to simulate
|
211
|
-
y0: Initial conditions
|
212
|
-
par_names: Names of parameters being fit
|
213
|
-
integrator: ODE integrator class to use
|
214
|
-
loss_fn: Loss function to use for residual calculation
|
215
|
-
|
216
|
-
Returns:
|
217
|
-
float: Root mean square error between model and data
|
218
|
-
|
219
|
-
"""
|
220
|
-
res = (
|
221
|
-
Simulator(
|
222
|
-
model.update_parameters(
|
223
|
-
dict(
|
112
|
+
if res.success:
|
113
|
+
return MinResult(
|
114
|
+
parameters=dict(
|
224
115
|
zip(
|
225
|
-
|
226
|
-
|
116
|
+
p0,
|
117
|
+
res.x,
|
227
118
|
strict=True,
|
228
|
-
)
|
229
|
-
)
|
230
|
-
|
231
|
-
|
232
|
-
integrator=integrator,
|
233
|
-
)
|
234
|
-
.simulate_to_steady_state()
|
235
|
-
.get_result()
|
236
|
-
)
|
237
|
-
if res is None:
|
238
|
-
return cast(float, np.inf)
|
239
|
-
|
240
|
-
return loss_fn(
|
241
|
-
res.get_combined().loc[:, cast(list, data.index)],
|
242
|
-
data,
|
243
|
-
)
|
244
|
-
|
245
|
-
|
246
|
-
def _time_course_residual(
|
247
|
-
par_values: ArrayLike,
|
248
|
-
# This will be filled out by partial
|
249
|
-
par_names: list[str],
|
250
|
-
data: pd.DataFrame,
|
251
|
-
model: Model,
|
252
|
-
y0: dict[str, float] | None,
|
253
|
-
integrator: IntegratorType,
|
254
|
-
loss_fn: LossFn,
|
255
|
-
) -> float:
|
256
|
-
"""Calculate residual error between model time course and experimental data.
|
257
|
-
|
258
|
-
Args:
|
259
|
-
par_values: Parameter values to test
|
260
|
-
data: Experimental time course data
|
261
|
-
model: Model instance to simulate
|
262
|
-
y0: Initial conditions
|
263
|
-
par_names: Names of parameters being fit
|
264
|
-
integrator: ODE integrator class to use
|
265
|
-
loss_fn: Loss function to use for residual calculation
|
266
|
-
|
267
|
-
Returns:
|
268
|
-
float: Root mean square error between model and data
|
269
|
-
|
270
|
-
"""
|
271
|
-
res = (
|
272
|
-
Simulator(
|
273
|
-
model.update_parameters(dict(zip(par_names, par_values, strict=True))),
|
274
|
-
y0=y0,
|
275
|
-
integrator=integrator,
|
276
|
-
)
|
277
|
-
.simulate_time_course(cast(list, data.index))
|
278
|
-
.get_result()
|
279
|
-
)
|
280
|
-
if res is None:
|
281
|
-
return cast(float, np.inf)
|
282
|
-
results_ss = res.get_combined()
|
283
|
-
|
284
|
-
return loss_fn(
|
285
|
-
results_ss.loc[:, cast(list, data.columns)],
|
286
|
-
data,
|
287
|
-
)
|
288
|
-
|
289
|
-
|
290
|
-
def _protocol_time_course_residual(
|
291
|
-
par_values: ArrayLike,
|
292
|
-
# This will be filled out by partial
|
293
|
-
par_names: list[str],
|
294
|
-
data: pd.DataFrame,
|
295
|
-
model: Model,
|
296
|
-
y0: dict[str, float] | None,
|
297
|
-
integrator: IntegratorType,
|
298
|
-
loss_fn: LossFn,
|
299
|
-
protocol: pd.DataFrame,
|
300
|
-
) -> float:
|
301
|
-
"""Calculate residual error between model time course and experimental data.
|
302
|
-
|
303
|
-
Args:
|
304
|
-
par_values: Parameter values to test
|
305
|
-
data: Experimental time course data
|
306
|
-
model: Model instance to simulate
|
307
|
-
y0: Initial conditions
|
308
|
-
par_names: Names of parameters being fit
|
309
|
-
integrator: ODE integrator class to use
|
310
|
-
loss_fn: Loss function to use for residual calculation
|
311
|
-
protocol: Experimental protocol
|
312
|
-
time_points_per_step: Number of time points per step in the protocol
|
119
|
+
),
|
120
|
+
),
|
121
|
+
residual=res.fun,
|
122
|
+
)
|
313
123
|
|
314
|
-
|
315
|
-
|
124
|
+
LOGGER.warning("Minimisation failed due to %s", res.message)
|
125
|
+
return None
|
316
126
|
|
317
|
-
"""
|
318
|
-
res = (
|
319
|
-
Simulator(
|
320
|
-
model.update_parameters(dict(zip(par_names, par_values, strict=True))),
|
321
|
-
y0=y0,
|
322
|
-
integrator=integrator,
|
323
|
-
)
|
324
|
-
.simulate_protocol_time_course(
|
325
|
-
protocol=protocol,
|
326
|
-
time_points=data.index,
|
327
|
-
)
|
328
|
-
.get_result()
|
329
|
-
)
|
330
|
-
if res is None:
|
331
|
-
return cast(float, np.inf)
|
332
|
-
results_ss = res.get_combined()
|
333
127
|
|
334
|
-
|
335
|
-
results_ss.loc[:, cast(list, data.columns)],
|
336
|
-
data,
|
337
|
-
)
|
128
|
+
_default_minimizer = ScipyMinimizer()
|
338
129
|
|
339
130
|
|
340
131
|
def _carousel_steady_state_worker(
|
@@ -344,7 +135,7 @@ def _carousel_steady_state_worker(
|
|
344
135
|
y0: dict[str, float] | None,
|
345
136
|
integrator: IntegratorType | None,
|
346
137
|
loss_fn: LossFn,
|
347
|
-
|
138
|
+
minimizer: Minimizer,
|
348
139
|
residual_fn: SteadyStateResidualFn,
|
349
140
|
bounds: Bounds | None,
|
350
141
|
) -> FitResult | None:
|
@@ -355,7 +146,7 @@ def _carousel_steady_state_worker(
|
|
355
146
|
p0={k: v for k, v in p0.items() if k in model_pars},
|
356
147
|
y0=y0,
|
357
148
|
data=data,
|
358
|
-
|
149
|
+
minimizer=minimizer,
|
359
150
|
residual_fn=residual_fn,
|
360
151
|
integrator=integrator,
|
361
152
|
loss_fn=loss_fn,
|
@@ -370,7 +161,7 @@ def _carousel_time_course_worker(
|
|
370
161
|
y0: dict[str, float] | None,
|
371
162
|
integrator: IntegratorType | None,
|
372
163
|
loss_fn: LossFn,
|
373
|
-
|
164
|
+
minimizer: Minimizer,
|
374
165
|
residual_fn: TimeSeriesResidualFn,
|
375
166
|
bounds: Bounds | None,
|
376
167
|
) -> FitResult | None:
|
@@ -380,7 +171,7 @@ def _carousel_time_course_worker(
|
|
380
171
|
p0={k: v for k, v in p0.items() if k in model_pars},
|
381
172
|
y0=y0,
|
382
173
|
data=data,
|
383
|
-
|
174
|
+
minimizer=minimizer,
|
384
175
|
residual_fn=residual_fn,
|
385
176
|
integrator=integrator,
|
386
177
|
loss_fn=loss_fn,
|
@@ -396,7 +187,7 @@ def _carousel_protocol_worker(
|
|
396
187
|
y0: dict[str, float] | None,
|
397
188
|
integrator: IntegratorType | None,
|
398
189
|
loss_fn: LossFn,
|
399
|
-
|
190
|
+
minimizer: Minimizer,
|
400
191
|
residual_fn: ProtocolResidualFn,
|
401
192
|
bounds: Bounds | None,
|
402
193
|
) -> FitResult | None:
|
@@ -407,7 +198,7 @@ def _carousel_protocol_worker(
|
|
407
198
|
y0=y0,
|
408
199
|
protocol=protocol,
|
409
200
|
data=data,
|
410
|
-
|
201
|
+
minimizer=minimizer,
|
411
202
|
residual_fn=residual_fn,
|
412
203
|
integrator=integrator,
|
413
204
|
loss_fn=loss_fn,
|
@@ -421,7 +212,7 @@ def steady_state(
|
|
421
212
|
p0: dict[str, float],
|
422
213
|
data: pd.Series,
|
423
214
|
y0: dict[str, float] | None = None,
|
424
|
-
|
215
|
+
minimizer: Minimizer = _default_minimizer,
|
425
216
|
residual_fn: SteadyStateResidualFn = _steady_state_residual,
|
426
217
|
integrator: IntegratorType | None = None,
|
427
218
|
loss_fn: LossFn = rmse,
|
@@ -438,7 +229,7 @@ def steady_state(
|
|
438
229
|
data: Experimental steady state data as pandas Series
|
439
230
|
p0: Initial parameter guesses as {parameter_name: value}
|
440
231
|
y0: Initial conditions as {species_name: value}
|
441
|
-
|
232
|
+
minimizer: Function to minimize fitting error
|
442
233
|
residual_fn: Function to calculate fitting error
|
443
234
|
integrator: ODE integrator class
|
444
235
|
loss_fn: Loss function to use for residual calculation
|
@@ -468,7 +259,7 @@ def steady_state(
|
|
468
259
|
loss_fn=loss_fn,
|
469
260
|
),
|
470
261
|
)
|
471
|
-
min_result =
|
262
|
+
min_result = minimizer(fn, p0, {} if bounds is None else bounds)
|
472
263
|
# Restore original model
|
473
264
|
model.update_parameters(p_orig)
|
474
265
|
if min_result is None:
|
@@ -487,7 +278,7 @@ def time_course(
|
|
487
278
|
p0: dict[str, float],
|
488
279
|
data: pd.DataFrame,
|
489
280
|
y0: dict[str, float] | None = None,
|
490
|
-
|
281
|
+
minimizer: Minimizer = _default_minimizer,
|
491
282
|
residual_fn: TimeSeriesResidualFn = _time_course_residual,
|
492
283
|
integrator: IntegratorType | None = None,
|
493
284
|
loss_fn: LossFn = rmse,
|
@@ -504,7 +295,7 @@ def time_course(
|
|
504
295
|
data: Experimental time course data
|
505
296
|
p0: Initial parameter guesses as {parameter_name: value}
|
506
297
|
y0: Initial conditions as {species_name: value}
|
507
|
-
|
298
|
+
minimizer: Function to minimize fitting error
|
508
299
|
residual_fn: Function to calculate fitting error
|
509
300
|
integrator: ODE integrator class
|
510
301
|
loss_fn: Loss function to use for residual calculation
|
@@ -533,7 +324,7 @@ def time_course(
|
|
533
324
|
),
|
534
325
|
)
|
535
326
|
|
536
|
-
min_result =
|
327
|
+
min_result = minimizer(fn, p0, {} if bounds is None else bounds)
|
537
328
|
# Restore original model
|
538
329
|
model.update_parameters(p_orig)
|
539
330
|
if min_result is None:
|
@@ -553,7 +344,7 @@ def protocol_time_course(
|
|
553
344
|
data: pd.DataFrame,
|
554
345
|
protocol: pd.DataFrame,
|
555
346
|
y0: dict[str, float] | None = None,
|
556
|
-
|
347
|
+
minimizer: Minimizer = _default_minimizer,
|
557
348
|
residual_fn: ProtocolResidualFn = _protocol_time_course_residual,
|
558
349
|
integrator: IntegratorType | None = None,
|
559
350
|
loss_fn: LossFn = rmse,
|
@@ -561,6 +352,8 @@ def protocol_time_course(
|
|
561
352
|
) -> FitResult | None:
|
562
353
|
"""Fit model parameters to time course of experimental data.
|
563
354
|
|
355
|
+
Time points of protocol time course are taken from the data.
|
356
|
+
|
564
357
|
Examples:
|
565
358
|
>>> time_course(model, p0, data)
|
566
359
|
{'k1': 0.1, 'k2': 0.2}
|
@@ -571,7 +364,7 @@ def protocol_time_course(
|
|
571
364
|
data: Experimental time course data
|
572
365
|
protocol: Experimental protocol
|
573
366
|
y0: Initial conditions as {species_name: value}
|
574
|
-
|
367
|
+
minimizer: Function to minimize fitting error
|
575
368
|
residual_fn: Function to calculate fitting error
|
576
369
|
integrator: ODE integrator class
|
577
370
|
loss_fn: Loss function to use for residual calculation
|
@@ -602,7 +395,7 @@ def protocol_time_course(
|
|
602
395
|
),
|
603
396
|
)
|
604
397
|
|
605
|
-
min_result =
|
398
|
+
min_result = minimizer(fn, p0, {} if bounds is None else bounds)
|
606
399
|
# Restore original model
|
607
400
|
model.update_parameters(p_orig)
|
608
401
|
if min_result is None:
|
@@ -621,7 +414,7 @@ def carousel_steady_state(
|
|
621
414
|
p0: dict[str, float],
|
622
415
|
data: pd.Series,
|
623
416
|
y0: dict[str, float] | None = None,
|
624
|
-
|
417
|
+
minimizer: Minimizer = _default_minimizer,
|
625
418
|
residual_fn: SteadyStateResidualFn = _steady_state_residual,
|
626
419
|
integrator: IntegratorType | None = None,
|
627
420
|
loss_fn: LossFn = rmse,
|
@@ -638,7 +431,7 @@ def carousel_steady_state(
|
|
638
431
|
data: Experimental time course data
|
639
432
|
protocol: Experimental protocol
|
640
433
|
y0: Initial conditions as {species_name: value}
|
641
|
-
|
434
|
+
minimizer: Function to minimize fitting error
|
642
435
|
residual_fn: Function to calculate fitting error
|
643
436
|
integrator: ODE integrator class
|
644
437
|
loss_fn: Loss function to use for residual calculation
|
@@ -663,7 +456,7 @@ def carousel_steady_state(
|
|
663
456
|
y0=y0,
|
664
457
|
integrator=integrator,
|
665
458
|
loss_fn=loss_fn,
|
666
|
-
|
459
|
+
minimizer=minimizer,
|
667
460
|
residual_fn=residual_fn,
|
668
461
|
bounds=bounds,
|
669
462
|
),
|
@@ -680,7 +473,7 @@ def carousel_time_course(
|
|
680
473
|
p0: dict[str, float],
|
681
474
|
data: pd.DataFrame,
|
682
475
|
y0: dict[str, float] | None = None,
|
683
|
-
|
476
|
+
minimizer: Minimizer = _default_minimizer,
|
684
477
|
residual_fn: TimeSeriesResidualFn = _time_course_residual,
|
685
478
|
integrator: IntegratorType | None = None,
|
686
479
|
loss_fn: LossFn = rmse,
|
@@ -688,8 +481,10 @@ def carousel_time_course(
|
|
688
481
|
) -> CarouselFit:
|
689
482
|
"""Fit model parameters to time course of experimental data over a carousel.
|
690
483
|
|
484
|
+
Time points are taken from the data.
|
485
|
+
|
691
486
|
Examples:
|
692
|
-
>>>
|
487
|
+
>>> carousel_time_course(carousel, p0=p0, data=data)
|
693
488
|
|
694
489
|
Args:
|
695
490
|
carousel: Model carousel to fit
|
@@ -697,7 +492,7 @@ def carousel_time_course(
|
|
697
492
|
data: Experimental time course data
|
698
493
|
protocol: Experimental protocol
|
699
494
|
y0: Initial conditions as {species_name: value}
|
700
|
-
|
495
|
+
minimizer: Function to minimize fitting error
|
701
496
|
residual_fn: Function to calculate fitting error
|
702
497
|
integrator: ODE integrator class
|
703
498
|
loss_fn: Loss function to use for residual calculation
|
@@ -722,7 +517,7 @@ def carousel_time_course(
|
|
722
517
|
y0=y0,
|
723
518
|
integrator=integrator,
|
724
519
|
loss_fn=loss_fn,
|
725
|
-
|
520
|
+
minimizer=minimizer,
|
726
521
|
residual_fn=residual_fn,
|
727
522
|
bounds=bounds,
|
728
523
|
),
|
@@ -740,7 +535,7 @@ def carousel_protocol_time_course(
|
|
740
535
|
data: pd.DataFrame,
|
741
536
|
protocol: pd.DataFrame,
|
742
537
|
y0: dict[str, float] | None = None,
|
743
|
-
|
538
|
+
minimizer: Minimizer = _default_minimizer,
|
744
539
|
residual_fn: ProtocolResidualFn = _protocol_time_course_residual,
|
745
540
|
integrator: IntegratorType | None = None,
|
746
541
|
loss_fn: LossFn = rmse,
|
@@ -748,6 +543,8 @@ def carousel_protocol_time_course(
|
|
748
543
|
) -> CarouselFit:
|
749
544
|
"""Fit model parameters to time course of experimental data over a protocol.
|
750
545
|
|
546
|
+
Time points of protocol time course are taken from the data.
|
547
|
+
|
751
548
|
Examples:
|
752
549
|
>>> carousel_steady_state(carousel, p0=p0, data=data)
|
753
550
|
|
@@ -757,7 +554,7 @@ def carousel_protocol_time_course(
|
|
757
554
|
data: Experimental time course data
|
758
555
|
protocol: Experimental protocol
|
759
556
|
y0: Initial conditions as {species_name: value}
|
760
|
-
|
557
|
+
minimizer: Function to minimize fitting error
|
761
558
|
residual_fn: Function to calculate fitting error
|
762
559
|
integrator: ODE integrator class
|
763
560
|
loss_fn: Loss function to use for residual calculation
|
@@ -783,7 +580,7 @@ def carousel_protocol_time_course(
|
|
783
580
|
y0=y0,
|
784
581
|
integrator=integrator,
|
785
582
|
loss_fn=loss_fn,
|
786
|
-
|
583
|
+
minimizer=minimizer,
|
787
584
|
residual_fn=residual_fn,
|
788
585
|
bounds=bounds,
|
789
586
|
),
|
mxlpy/identify.py
CHANGED
@@ -9,8 +9,9 @@ import numpy as np
|
|
9
9
|
import pandas as pd
|
10
10
|
from tqdm import tqdm
|
11
11
|
|
12
|
-
from mxlpy import
|
12
|
+
from mxlpy import fit_local
|
13
13
|
from mxlpy.distributions import LogNormal, sample
|
14
|
+
from mxlpy.fit.common import LossFn, rmse
|
14
15
|
from mxlpy.parallel import parallelise
|
15
16
|
|
16
17
|
if TYPE_CHECKING:
|
@@ -26,9 +27,9 @@ def _mc_fit_time_course_worker(
|
|
26
27
|
p0: pd.Series,
|
27
28
|
model: Model,
|
28
29
|
data: pd.DataFrame,
|
29
|
-
loss_fn:
|
30
|
+
loss_fn: fit_local.LossFn,
|
30
31
|
) -> float:
|
31
|
-
fit_result =
|
32
|
+
fit_result = fit_local.time_course(
|
32
33
|
model=model,
|
33
34
|
p0=p0.to_dict(),
|
34
35
|
data=data,
|
@@ -45,7 +46,7 @@ def profile_likelihood(
|
|
45
46
|
parameter_name: str,
|
46
47
|
parameter_values: Array,
|
47
48
|
n_random: int = 10,
|
48
|
-
loss_fn:
|
49
|
+
loss_fn: LossFn = rmse,
|
49
50
|
) -> pd.Series:
|
50
51
|
"""Estimate the profile likelihood of model parameters given data.
|
51
52
|
|