PyAntiGen 2.1.4__tar.gz → 2.1.6__tar.gz
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.
- {pyantigen-2.1.4 → pyantigen-2.1.6}/PKG-INFO +1 -1
- {pyantigen-2.1.4 → pyantigen-2.1.6}/PyAntiGen.egg-info/PKG-INFO +1 -1
- {pyantigen-2.1.4 → pyantigen-2.1.6}/PyAntiGen.egg-info/scm_file_list.json +1 -0
- pyantigen-2.1.6/PyAntiGen.egg-info/scm_version.json +8 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/_version.py +3 -3
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/engine/Optimize.py +5 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/engine/Segmented.py +2 -2
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/engine/Simulate.py +193 -2
- pyantigen-2.1.4/PyAntiGen.egg-info/scm_version.json +0 -8
- {pyantigen-2.1.4 → pyantigen-2.1.6}/.github/workflows/publish.yml +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/.github/workflows/tests.yml +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/.gitignore +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/.vscode/launch.json +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/LICENSE +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/MANIFEST.in +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/PyAntiGen.egg-info/SOURCES.txt +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/PyAntiGen.egg-info/dependency_links.txt +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/PyAntiGen.egg-info/entry_points.txt +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/PyAntiGen.egg-info/requires.txt +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/PyAntiGen.egg-info/top_level.txt +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/README.md +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/docs/ANALYTIC_GRADIENT.md +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/docs/MULTISTART.md +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/docs/PROTOCOL_LAYER.md +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/docs/V2_DESIGN.md +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/.agents/skills/module_generation/SKILL.md +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/.agents/skills/ode_conversion_antimony/SKILL.md +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/.agents/skills/ode_extraction_pipeline/SKILL.md +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/.gitignore +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/__init__.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/cli.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/engine/Analytic_gradient.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/engine/Anchor_cache.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/engine/Deadline.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/engine/Differential_evolution.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/engine/Evaluator.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/engine/Event_times.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/engine/Fast_profile.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/engine/Fit_cache.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/engine/Identifiability.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/engine/Model_cache.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/engine/Model_optimize.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/engine/Model_simulate.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/engine/Multistart.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/engine/Nelder_mead.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/engine/Noise_floor.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/engine/Petab_export.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/engine/Preequil_cache.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/engine/Profile_checkpoint.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/engine/Profile_plan.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/engine/README.md +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/engine/Results.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/engine/Scaled_amici.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/engine/Sensitivity_analysis.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/engine/Stop_rules.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/engine/__init__.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/generate/AntimonyGen.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/generate/RxnDict_to_antimony.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/generate/TelluriumGen.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/generate/__init__.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/generate/antimony_utils.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/generate/data_interpolation.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/generate/input_schedule.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/generate/isotopomer_tools.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/generate/model_generation.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/generate/models.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/generate/module_base.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/generate/pyantigen.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/generate/rate_laws.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/generate/reaction_creation.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/generate/scaled_time.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/study/__init__.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/study/assay.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/study/describe.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/study/design.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/study/lower_v1.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/study/optimization.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/study/params.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/study/quantity.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/study/reagent.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/study/refs.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/study/remarks.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/study/serialize.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/study/validate.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/template/Example/AntiGen_paths.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/template/Example/Flipflop_reference.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/template/Example/Model_generate.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/template/Example/Model_run.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/template/Example/Modules/Data.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/template/Example/Modules/Events.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/template/Example/Modules/Experiment.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/template/Example/Modules/Loss_config.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/template/Example/Modules/Observed_species.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/template/Example/Modules/Optimizer_settings.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/template/Example/Modules/Plots.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/template/Example/Modules/Solver_settings.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/template/Example/Modules/Update_opt_parameters.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/template/Example/Modules/Update_parameters.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/template/Example/optimizations/Example1_ADneg.json +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/template/Example/optimizations/Example1_ADpos.json +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/template/Example/optimizations/Example3_joint.json +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/template/Example/optimizations/Example4_flipflop.json +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/template/Example/optimizations/example.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/template/Example/studies/example.json +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/template/Example/studies/example.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/template/Example/studies/flipflop.json +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/template/data/ADneg.csv +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/template/data/ADpos.csv +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/template/data/Flipflop.csv +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/template/data/make_flipflop_data.py +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/pyproject.toml +0 -0
- {pyantigen-2.1.4 → pyantigen-2.1.6}/setup.cfg +0 -0
|
@@ -143,6 +143,7 @@
|
|
|
143
143
|
"tests/engine/test_solver_fingerprint.py",
|
|
144
144
|
"tests/engine/test_stop_rules.py",
|
|
145
145
|
"tests/engine/test_tolerance_floor.py",
|
|
146
|
+
"tests/engine/test_tolerance_pinning.py",
|
|
146
147
|
"tests/engine/test_wald_units.py",
|
|
147
148
|
"tests/generate/test_gen_antimony_utils.py",
|
|
148
149
|
"tests/generate/test_gen_data_interpolation.py",
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '2.1.
|
|
22
|
-
__version_tuple__ = version_tuple = (2, 1,
|
|
21
|
+
__version__ = version = '2.1.6'
|
|
22
|
+
__version_tuple__ = version_tuple = (2, 1, 6)
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'g917168907'
|
|
@@ -8279,6 +8279,11 @@ def predict_concentrations(params, observable_data, model, param_names, observab
|
|
|
8279
8279
|
model.setIntegrator('cvode')
|
|
8280
8280
|
model.integrator.absolute_tolerance = 1e-8
|
|
8281
8281
|
_model_cache.put(model, "_scalar_abs_tol", 1e-8)
|
|
8282
|
+
# This helper takes no solver settings, so it cannot ask for pinning.
|
|
8283
|
+
# Drop any policy an earlier configure_integrator left on the model, or
|
|
8284
|
+
# its reference scale -- taken for a different parameter vector -- would
|
|
8285
|
+
# keep pinning here.
|
|
8286
|
+
_model_cache.put(model, "_tolerance_policy", None)
|
|
8282
8287
|
model.integrator.relative_tolerance = 1e-8
|
|
8283
8288
|
model.integrator.setValue('stiff', True)
|
|
8284
8289
|
model.integrator.variable_step_size = True
|
|
@@ -44,7 +44,7 @@ caches separately must not contain a switch: ``switches_before`` says whether it
|
|
|
44
44
|
"""
|
|
45
45
|
import numpy as np
|
|
46
46
|
|
|
47
|
-
from pyantigen.engine.Simulate import StackedResult,
|
|
47
|
+
from pyantigen.engine.Simulate import StackedResult, apply_tolerance_vector, safe_simulate
|
|
48
48
|
from pyantigen.generate.input_schedule import ScheduleError
|
|
49
49
|
|
|
50
50
|
|
|
@@ -154,7 +154,7 @@ class SegmentRunner:
|
|
|
154
154
|
between = mine[(mine > u + eu) & (mine < v - ev)]
|
|
155
155
|
times = [u] + between.tolist() + [v]
|
|
156
156
|
|
|
157
|
-
|
|
157
|
+
apply_tolerance_vector(self.r)
|
|
158
158
|
res, _meta = safe_simulate(
|
|
159
159
|
self.r, {"times": times, "variable_step_size": False},
|
|
160
160
|
observed_species, label=label)
|
|
@@ -233,6 +233,181 @@ def floor_tolerance_vector(r, floor=_MIN_ABSOLUTE_TOLERANCE):
|
|
|
233
233
|
return n
|
|
234
234
|
|
|
235
235
|
|
|
236
|
+
# ---------------------------------------------------------------------------
|
|
237
|
+
# Pinning the vector, not only flooring it
|
|
238
|
+
# ---------------------------------------------------------------------------
|
|
239
|
+
# floor_tolerance_vector raises what has fallen below the floor and leaves
|
|
240
|
+
# everything else as RoadRunner has it. That is enough for a vector that has
|
|
241
|
+
# drifted DOWN, which is what the floor was written for. It does nothing about
|
|
242
|
+
# two other things:
|
|
243
|
+
#
|
|
244
|
+
# * The retry ladder sets the scalar before every attempt, and setting the
|
|
245
|
+
# scalar re-derives the whole vector from the amounts the model holds
|
|
246
|
+
# *at that moment* -- the failing state, not the initial one. Measured on
|
|
247
|
+
# Aducanumab 60 mg/kg: between the segment-start vector and the vector of
|
|
248
|
+
# attempt 2, 176 entries were more than 10x larger and 62 more than 10x
|
|
249
|
+
# smaller (ratios 1.7e-11 .. 2.9e+07). The floor raised 3 of them. So the
|
|
250
|
+
# loosened retries do not run at "the same tolerances, looser"; they run at
|
|
251
|
+
# tolerances derived from wherever the integration died.
|
|
252
|
+
#
|
|
253
|
+
# * RoadRunner's initial-derived scale is atol_i = scalar * amount_i, or
|
|
254
|
+
# scalar * volume_i for a species that starts at 0 (see the note above
|
|
255
|
+
# _MIN_ABSOLUTE_TOLERANCE). Every species that starts empty therefore gets
|
|
256
|
+
# one number, scalar * its compartment volume -- 6.7e-11 at scalar 1e-9 for
|
|
257
|
+
# the 0.067-volume endosome -- however small it later runs. After the FcRn
|
|
258
|
+
# saturation front of a 60 mg/kg dose the endosomal antibody species sit at
|
|
259
|
+
# 1.6e-9 .. 1.3e-8, so that budget is 0.5-4% of their value, and CVODE fails
|
|
260
|
+
# (CV_ILL_INPUT / CV_TOO_MUCH_ACC) ~200 h after the dose. Lowering the scalar
|
|
261
|
+
# 10x, pinning those five species at 1e-15, or capping every entry at 1e-12
|
|
262
|
+
# each took the displaced-parameter failures from 6/40 to 0/40.
|
|
263
|
+
#
|
|
264
|
+
# Pinning keeps ONE reference -- the per-state scale RoadRunner derives at
|
|
265
|
+
# configure_integrator when the model is at its initial time -- and from it
|
|
266
|
+
# sets every entry explicitly before each block, each segment and each ladder
|
|
267
|
+
# attempt:
|
|
268
|
+
#
|
|
269
|
+
# atol_i = clip( scalar * scale_i , floor , cap_ratio * scalar )
|
|
270
|
+
#
|
|
271
|
+
# *scalar* is the configured one, or the ladder's current (loosened) one, so a
|
|
272
|
+
# retry scales the same vector instead of re-deriving it. The cap is relative
|
|
273
|
+
# to the scalar for the same reason: an absolute cap would undo the ladder's
|
|
274
|
+
# loosening. cap_ratio is optional; without it pinning only restores the
|
|
275
|
+
# initial-derived vector.
|
|
276
|
+
#
|
|
277
|
+
# Opt in per replicate through the solver settings:
|
|
278
|
+
#
|
|
279
|
+
# "tolerance_pinning": True, # default TOLERANCE_PINNING (False)
|
|
280
|
+
# "tolerance_cap_ratio": 1e-3, # default TOLERANCE_CAP_RATIO (None)
|
|
281
|
+
#
|
|
282
|
+
# Both are plain values in the settings dict, so Profile_checkpoint's solver
|
|
283
|
+
# fingerprint already covers them: switching them on starts a new checkpoint
|
|
284
|
+
# directory rather than mixing two objectives. Left off, apply_tolerance_vector
|
|
285
|
+
# is floor_tolerance_vector and nothing changes.
|
|
286
|
+
TOLERANCE_PINNING = False
|
|
287
|
+
TOLERANCE_CAP_RATIO = None
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def tolerance_policy(solver_settings):
|
|
291
|
+
"""``{"pin": bool, "cap_ratio": float | None}`` from *solver_settings*.
|
|
292
|
+
|
|
293
|
+
``tolerance_pinning`` must be a real bool: ``bool("false")`` is True, so a
|
|
294
|
+
string from a config file would switch pinning on while reading as off.
|
|
295
|
+
"""
|
|
296
|
+
pin = solver_settings.get("tolerance_pinning", TOLERANCE_PINNING)
|
|
297
|
+
if not isinstance(pin, (bool, np.bool_)):
|
|
298
|
+
raise TypeError(f"tolerance_pinning must be True or False, got {pin!r}")
|
|
299
|
+
pin = bool(pin)
|
|
300
|
+
cap = solver_settings.get("tolerance_cap_ratio", TOLERANCE_CAP_RATIO)
|
|
301
|
+
if cap is not None:
|
|
302
|
+
if isinstance(cap, (bool, np.bool_, str)):
|
|
303
|
+
raise TypeError(f"tolerance_cap_ratio must be a number, got {cap!r}")
|
|
304
|
+
cap = float(cap)
|
|
305
|
+
if not cap > 0:
|
|
306
|
+
raise ValueError(f"tolerance_cap_ratio must be positive, got {cap}")
|
|
307
|
+
if not pin:
|
|
308
|
+
raise ValueError("tolerance_cap_ratio needs tolerance_pinning: a cap is "
|
|
309
|
+
"applied to the pinned vector")
|
|
310
|
+
return {"pin": pin, "cap_ratio": cap}
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
def _remember_tolerance_policy(r, solver_settings, scalar):
|
|
314
|
+
"""Cache the policy on *r* and, at the model's initial time, the reference scale.
|
|
315
|
+
|
|
316
|
+
Called by configure_integrator right after the scalar is set, when RoadRunner
|
|
317
|
+
has just derived the vector. The scale is only taken at time 0: a second
|
|
318
|
+
configure on a state restored from the pre-dose cache would derive it from
|
|
319
|
+
amounts that have already decayed, which is the drift this exists to undo.
|
|
320
|
+
"""
|
|
321
|
+
policy = tolerance_policy(solver_settings)
|
|
322
|
+
if not policy["pin"]:
|
|
323
|
+
_model_cache.put(r, "_tolerance_policy", None)
|
|
324
|
+
return
|
|
325
|
+
# The model clock is the test for "still at the initial state": reset() and
|
|
326
|
+
# resetAll() return it to exactly 0.0 whatever was simulated before (a model
|
|
327
|
+
# has no other start time), and save/restore_model_state carry 'time' with
|
|
328
|
+
# the amounts, so a restored state brings its clock back with it. A clock
|
|
329
|
+
# that is not 0 means the model has been integrated, whatever its start.
|
|
330
|
+
try:
|
|
331
|
+
at_start = float(r.getCurrentTime()) == 0.0
|
|
332
|
+
except Exception:
|
|
333
|
+
at_start = False
|
|
334
|
+
if at_start:
|
|
335
|
+
# At the initial time the reference is re-derived every time, and a
|
|
336
|
+
# failure to do so drops the old one: it belongs to an earlier parameter
|
|
337
|
+
# vector, and pinning to it would silently use the wrong scales. (Away
|
|
338
|
+
# from t=0 the stored reference is kept on purpose -- see above.)
|
|
339
|
+
reference = None
|
|
340
|
+
try:
|
|
341
|
+
vec = np.asarray(r.integrator.getAbsoluteToleranceVector(), float)
|
|
342
|
+
ids = state_vector_ids(r)
|
|
343
|
+
n = min(len(ids), len(vec))
|
|
344
|
+
if float(scalar) > 0 and n:
|
|
345
|
+
reference = (list(ids[:n]), vec[:n] / float(scalar))
|
|
346
|
+
except Exception:
|
|
347
|
+
pass
|
|
348
|
+
_model_cache.put(r, "_atol_reference", reference)
|
|
349
|
+
if _model_cache.get(r, "_atol_reference") is None:
|
|
350
|
+
# Never saw the initial state, so there is no initial scale to pin to.
|
|
351
|
+
import warnings
|
|
352
|
+
warnings.warn("tolerance_pinning requested but the model was first configured "
|
|
353
|
+
"away from its initial time; falling back to the floor",
|
|
354
|
+
RuntimeWarning, stacklevel=3)
|
|
355
|
+
_model_cache.put(r, "_tolerance_policy", None)
|
|
356
|
+
return
|
|
357
|
+
_model_cache.put(r, "_tolerance_policy", policy)
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
def apply_tolerance_vector(r, scalar=None, floor=_MIN_ABSOLUTE_TOLERANCE):
|
|
361
|
+
"""Set the per-state absolute tolerances for the next integration.
|
|
362
|
+
|
|
363
|
+
Pinning off (the default): exactly :func:`floor_tolerance_vector`. Pinning
|
|
364
|
+
on: every entry is set to ``clip(scalar * scale_i, floor, cap_ratio * scalar)``
|
|
365
|
+
from the reference scale. *scalar* defaults to the configured absolute
|
|
366
|
+
tolerance; the retry ladder passes its current, loosened one. Returns the
|
|
367
|
+
number of entries set.
|
|
368
|
+
"""
|
|
369
|
+
policy = _model_cache.get(r, "_tolerance_policy")
|
|
370
|
+
ref = _model_cache.get(r, "_atol_reference") if policy else None
|
|
371
|
+
if ref is None:
|
|
372
|
+
return floor_tolerance_vector(r, floor)
|
|
373
|
+
if scalar is None:
|
|
374
|
+
scalar = _model_cache.get(r, "_scalar_abs_tol")
|
|
375
|
+
if scalar is None:
|
|
376
|
+
return floor_tolerance_vector(r, floor)
|
|
377
|
+
ids, scale = ref
|
|
378
|
+
try:
|
|
379
|
+
current = np.asarray(r.integrator.getAbsoluteToleranceVector(), float)
|
|
380
|
+
except Exception:
|
|
381
|
+
# A vector that cannot be read cannot be floored either (the floor reads
|
|
382
|
+
# it first), so there is nothing to fall back to.
|
|
383
|
+
return 0
|
|
384
|
+
if len(current) < len(ids):
|
|
385
|
+
return floor_tolerance_vector(r, floor)
|
|
386
|
+
scalar = float(scalar)
|
|
387
|
+
want = scalar * scale
|
|
388
|
+
if policy["cap_ratio"] is not None:
|
|
389
|
+
want = np.minimum(want, policy["cap_ratio"] * scalar)
|
|
390
|
+
want = np.maximum(want, floor)
|
|
391
|
+
n = 0
|
|
392
|
+
failed = []
|
|
393
|
+
for i in np.flatnonzero(~np.isclose(current[:len(ids)], want, rtol=1e-9, atol=0.0)):
|
|
394
|
+
try:
|
|
395
|
+
r.integrator.setIndividualTolerance(ids[i], float(want[i]))
|
|
396
|
+
n += 1
|
|
397
|
+
except Exception:
|
|
398
|
+
failed.append(ids[i])
|
|
399
|
+
if failed and not _model_cache.get(r, "_tolerance_set_warned"):
|
|
400
|
+
# Once per model: a state left at its drifted tolerance is what pinning
|
|
401
|
+
# exists to prevent, so it must not be silent, but this runs before
|
|
402
|
+
# every block and would otherwise repeat for the whole fit.
|
|
403
|
+
import warnings
|
|
404
|
+
_model_cache.put(r, "_tolerance_set_warned", True)
|
|
405
|
+
warnings.warn(f"tolerance_pinning could not set the absolute tolerance of "
|
|
406
|
+
f"{len(failed)} state(s) (first: {failed[0]!r}); they keep "
|
|
407
|
+
f"RoadRunner's derived value", RuntimeWarning, stacklevel=2)
|
|
408
|
+
return n
|
|
409
|
+
|
|
410
|
+
|
|
236
411
|
class StackedResult(np.ndarray):
|
|
237
412
|
def __new__(cls, input_array, colnames):
|
|
238
413
|
obj = np.asarray(input_array).view(cls)
|
|
@@ -584,6 +759,15 @@ def safe_simulate(r, solver_settings, observed_species, depth=0, label=None):
|
|
|
584
759
|
# corrupted/advanced state that cannot be reverted without this snapshot.
|
|
585
760
|
saved_state = save_model_state(r)
|
|
586
761
|
|
|
762
|
+
# A sub-call of a subdivision begins wherever the previous one left the
|
|
763
|
+
# vector: re-derived from the decayed state after a restore, or loosened by
|
|
764
|
+
# a ladder. The top-level call is pinned by its caller (_run_blocks,
|
|
765
|
+
# SegmentRunner); the halves are not, so pin them here, from the configured
|
|
766
|
+
# scalar. Each half then tries the configured accuracy and runs its own
|
|
767
|
+
# ladder if that fails.
|
|
768
|
+
if depth > 0:
|
|
769
|
+
apply_tolerance_vector(r)
|
|
770
|
+
|
|
587
771
|
# Fast path: try once with whatever settings the model already has.
|
|
588
772
|
try:
|
|
589
773
|
res = _run(r, start, end, points, times, observed_species)
|
|
@@ -653,7 +837,7 @@ def safe_simulate(r, solver_settings, observed_species, depth=0, label=None):
|
|
|
653
837
|
# state and discards any individual settings, so the floor has to be
|
|
654
838
|
# re-applied here or every retry would run without it -- including the
|
|
655
839
|
# retries provoked by its absence.
|
|
656
|
-
|
|
840
|
+
apply_tolerance_vector(r, scalar=cur_abs_tol)
|
|
657
841
|
if cur_initial_step is not None:
|
|
658
842
|
try:
|
|
659
843
|
r.integrator.initial_time_step = cur_initial_step
|
|
@@ -670,6 +854,7 @@ def safe_simulate(r, solver_settings, observed_species, depth=0, label=None):
|
|
|
670
854
|
|
|
671
855
|
# Restore original integrator settings on success
|
|
672
856
|
r.integrator.absolute_tolerance = orig_abs_tol
|
|
857
|
+
apply_tolerance_vector(r, scalar=orig_abs_tol)
|
|
673
858
|
r.integrator.relative_tolerance = orig_rel_tol
|
|
674
859
|
r.integrator.maximum_num_steps = orig_max_steps
|
|
675
860
|
try:
|
|
@@ -748,6 +933,7 @@ def safe_simulate(r, solver_settings, observed_species, depth=0, label=None):
|
|
|
748
933
|
|
|
749
934
|
# Restore original integrator settings before returning
|
|
750
935
|
r.integrator.absolute_tolerance = orig_abs_tol
|
|
936
|
+
apply_tolerance_vector(r, scalar=orig_abs_tol)
|
|
751
937
|
r.integrator.relative_tolerance = orig_rel_tol
|
|
752
938
|
r.integrator.maximum_num_steps = orig_max_steps
|
|
753
939
|
try:
|
|
@@ -766,6 +952,7 @@ def safe_simulate(r, solver_settings, observed_species, depth=0, label=None):
|
|
|
766
952
|
|
|
767
953
|
# If all else fails, restore original settings and raise exception
|
|
768
954
|
r.integrator.absolute_tolerance = orig_abs_tol
|
|
955
|
+
apply_tolerance_vector(r, scalar=orig_abs_tol)
|
|
769
956
|
r.integrator.relative_tolerance = orig_rel_tol
|
|
770
957
|
r.integrator.maximum_num_steps = orig_max_steps
|
|
771
958
|
try:
|
|
@@ -797,6 +984,9 @@ def configure_integrator(r, solver_settings):
|
|
|
797
984
|
Mutates *solver_settings* with the defaults, as the original inline version
|
|
798
985
|
did, so callers that read the values back afterwards still see them.
|
|
799
986
|
"""
|
|
987
|
+
# Before anything is touched: a bad pinning setting is a configuration
|
|
988
|
+
# error, and should not leave the integrator half set up.
|
|
989
|
+
tolerance_policy(solver_settings)
|
|
800
990
|
solver_settings["integrator"] = solver_settings.get("integrator", "cvode")
|
|
801
991
|
solver_settings["absolute_tolerance"] = solver_settings.get("absolute_tolerance", 1e-8)
|
|
802
992
|
solver_settings["relative_tolerance"] = solver_settings.get("relative_tolerance", 1e-8)
|
|
@@ -822,6 +1012,7 @@ def configure_integrator(r, solver_settings):
|
|
|
822
1012
|
r.integrator.variable_step_size = solver_settings["variable_step_size"]
|
|
823
1013
|
# r.integrator.setValue('initial_time_step', solver_settings["initial_time_step"])
|
|
824
1014
|
r.integrator.setValue('maximum_num_steps', solver_settings["maximum_num_steps"])
|
|
1015
|
+
_remember_tolerance_policy(r, solver_settings, atol)
|
|
825
1016
|
return solver_settings
|
|
826
1017
|
|
|
827
1018
|
|
|
@@ -891,7 +1082,7 @@ def _run_blocks(r, block_list, last_tracked_idx, observed_species, label, runner
|
|
|
891
1082
|
# tolerance vector is derived from the current state, so it is healthy
|
|
892
1083
|
# here at t=0 and underflows as the trajectory decays. See
|
|
893
1084
|
# _MIN_ABSOLUTE_TOLERANCE.
|
|
894
|
-
|
|
1085
|
+
apply_tolerance_vector(r)
|
|
895
1086
|
|
|
896
1087
|
try:
|
|
897
1088
|
if runner is not None:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/.agents/skills/ode_conversion_antimony/SKILL.md
RENAMED
|
File without changes
|
{pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/.agents/skills/ode_extraction_pipeline/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/template/Example/Modules/Optimizer_settings.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/template/Example/Modules/Update_opt_parameters.py
RENAMED
|
File without changes
|
|
File without changes
|
{pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/template/Example/optimizations/Example1_ADneg.json
RENAMED
|
File without changes
|
{pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/template/Example/optimizations/Example1_ADpos.json
RENAMED
|
File without changes
|
{pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/template/Example/optimizations/Example3_joint.json
RENAMED
|
File without changes
|
{pyantigen-2.1.4 → pyantigen-2.1.6}/pyantigen/template/Example/optimizations/Example4_flipflop.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|