Repository navigation
Conversation
Every other differential check runs a fresh model, by design; callers reuse one, and "the solver leaves scratch state in the user's Model, or drops state it should carry" is a family of its own (lanl#786; lanl#748, lanl#705, lanl#693). Three checks, each against the base run with Base.compare: * restart: run_until to the middle sample and on to the end, on one Simulator (which carries the events' trigger state across the stop, lanl#693); and, for a model without events, a fresh model given the middle's saved state. Joined, each is the base. * reuse: a second run() on one Simulator, and a first run on a second Simulator over one Model, each after the first is undone with snapshot()/restore() (species, parameters and event carry state; Model.reset() restores species only, so an event that writes a parameter would leave it written). * batch: run_batch on 4 threads against the same four points one at a time (the first sensitivity parameter at x1, 1.1, 0.9, 1.05), and the x1 point against the base. A point that does not integrate one at a time is the model's, not the batch's: SKIP, named. Base keeps its run's species names (the same lines as lanl#1305's PR). Over the corpus (1,353 models each): restart 1,260 PASS, 92 SKIP, 1 EXCEPTION; reuse 1,260 PASS, 93 SKIP; batch 1,259 PASS, 94 SKIP. No DIFF. The exception, BIOMD0000000827, is no leak: stopped anywhere (t = 50, 100, 150) and continued, by run_until or by a fresh Simulator from the saved state (which equals run()'s), it fails at the next NaN in a rate law where the straight run, robust at 0.5x to 2x its tolerance, steps around it. Controls, each mutating the model where a leak would: a parameter doubled between run_until's legs, after set_state in the fresh restart, inside restore(), and for one threaded batch point; each reads DIFF, on a .net and on an SBML model with an event. A point failing both ways is SKIP; one failing only on threads is still a finding. Mutations caught: restart without its run_until comparison, reuse without restore, batch against itself, a combiner that passes everything, the serial failure uncaught.
# Conflicts: # python/tests/test_differential_shapes.py
This was referenced Oct 27, 2026
…leaks restart, reuse and batch run after every check main runs, each run and run_batch with what is left of the model's cap; run_until takes no timeout, and a kill at the cap still leaves the model's other rows.
… fix/1307-state-leaks
… fix/1307-state-leaks # Conflicts: # python/tests/test_differential_shapes.py
wshlavacek
pushed a commit
that referenced
this pull request
Oct 27, 2026
…inished The pool kills a model's worker at its cap (900 s on the nightly), and every row of the model with it. MODEL1006230049, 0053 and 0077 take 716-751 s of that on main, so any check a pull request added to every model turned all their rows TIMEOUT: #1315, #1318 and #1319 each read 27-36 regressions, none of them a finding. check_all now takes a deadline, 0.9 of the cap. Every run has until it (run(timeout=)), no run or check starts past it, and a check that does not finish is its own TIMEOUT, said why. Each verdict is written as it is reached, so a worker the pool still kills (one compiling C past the deadline, which no run's timeout bounds) leaves the runner every row it finished; only the rest are TIMEOUT.
…lanl#1307) _worst returned the first verdict that was not a PASS, where its docstring said a DIFF if any is. In check_batch, point 0 is judged against the base and reads SKIP where the base moves past UNJUDGEABLE_DRIFT; a threaded point that ran on another parameter then read DIFF and the row said SKIP. The first DIFF wins now, then the first other non-PASS.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1307.
What it adds
Three checks. Every other differential check runs a fresh model, by design, so none exercises reuse. Callers reuse models, though, and "the solver leaves scratch state in the user's Model, or drops state it should carry" is a family of its own (#786; #748, #705, #693). Each check is judged against #1291's base run with
Base.compare.restartrun_untilthe middle sample, thenrun_untilthe end, on one Simulator (which carries the events' trigger state and pending delays across the stop, #693). For a model without events, also a fresh Simulator given the middle's saved statereuserun()on one Simulator, and a first run on a second Simulator over one Model, each after the first run is undone withsnapshot()/restore()batchrun_batchon 4 threads against the same four points one at a time (the first sensitivity parameter ×1, 1.1, 0.9, 1.05), and the ×1 point against the baseThree design decisions, each to avoid a false finding:
restore(), notModel.reset(), undoes the first run.reset()restores species only, by its own documentation, so a model whose event writes a parameter would read as a leak.Basekeeps its run's species names, so columns are compared by name. It's the same addition #1316 makes, with the same lines.Over the corpus
1,353 models each: the 53
.netjobs and the BioModels, run locally.The SKIPs are #1291's own: models whose base does not load or run, or has no reference. The exception is
batch's, for four models (BIOMD0000000763, BIOMD0000001043, MODEL1112110002, MODEL2009230001), whose perturbed point fails one at a time as well as on threads.The exception, triaged: BIOMD0000000827 under
restart. It is no leak:EGFR_EGFR_formation).run_untilor by a fresh Simulator from the saved state.run_until's state at the stop equalsrun()'s exactly.So the state is carried correctly. Restarting the integrator from it takes the run into a region the continuous run steps around. That is a model at the edge of its domain, #1297's and #1298's class.
Tests (
python/tests/test_differential_shapes.py, appended).net(equality-dwell) and on an SBML model with an event (event-at-a-sample):run_untillegs;set_statein the fresh-model restart (on the event-free.net);restore(), which reuse rests on;Mutations, each caught:
run_untilcomparison;restorebetween runs (the shapes' own reuse rows then read DIFF);Suites:
test_differential_shapes.pyandparity_checks/tests/test_differential_run.pygive 222 passed, 1 xfailed (#1291's #1254 xfail). ruff 0.14.0 is clean. The branch merges cleanly with the current lanlmain.Cost
Per model:
Locally, the batch check alone took 240 s over the corpus on 8 workers.
Baseline
parity_checks/nightly/baselines/differential.jsonwill be re-recorded from this PR's own nightly run, as #1307 asks, in a follow-up commit here (as for #1315).Changes (this PR's commit, less the tests)
No changelog fragment: this changes
parity_checks/and tests only.