Skip to content

Commit 64bbd80

Browse files
authored
Merge pull request #2648 from dweindl/release_0.30.1
Prepare release 0.30.1
2 parents 2d58f54 + 06d42d2 commit 64bbd80

File tree

10 files changed

+262
-20
lines changed

10 files changed

+262
-20
lines changed

CHANGELOG.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,27 @@ See also our [versioning policy](https://amici.readthedocs.io/en/latest/versioni
44

55
## v0.X Series
66

7+
### v0.30.1 (2025-02-18)
8+
9+
Bugfix-only release.
10+
11+
* Removed `eqx.debug.nan`, fixes #2629
12+
by @FFroehlich in https://github.com/AMICI-dev/AMICI/pull/2630
13+
* Fixes an SBML import issue that led to incorrect results for models with
14+
species-dependent initial assignments (fixes #2642)
15+
by @FFroehlich in https://github.com/AMICI-dev/AMICI/pull/2643
16+
* Fixed `CVodeGetSensDky` error message
17+
by @dweindl in https://github.com/AMICI-dev/AMICI/pull/2644
18+
* Disabled `CvodeF` checkpointing to prevent certain rare crashes when forward
19+
integration takes exactly `maxsteps` integration steps, plus some additional
20+
yet unclear condition.
21+
by @dweindl in https://github.com/AMICI-dev/AMICI/pull/2645
22+
* Fixed rare crashes due to uncaught exceptions in `~FinalStateStorer`
23+
by @dweindl in https://github.com/AMICI-dev/AMICI/pull/2647
24+
25+
**Full Changelog**: https://github.com/AMICI-dev/AMICI/compare/v0.30.0...v0.30.1
26+
27+
728
### v0.30.0 (2024-12-10)
829

930
*Please note that the amici JAX model generation introduced in v0.29.0 is

include/amici/forwardproblem.h

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -441,19 +441,37 @@ class FinalStateStorer : public ContextManager {
441441
/**
442442
* @brief destructor, stores simulation state
443443
*/
444-
~FinalStateStorer() {
444+
~FinalStateStorer() noexcept(false) {
445445
if (fwd_) {
446-
fwd_->final_state_ = fwd_->getSimulationState();
447-
// if there is an associated output timepoint, also store it in
448-
// timepoint_states if it's not present there.
449-
// this may happen if there is an error just at
450-
// (or indistinguishably before) an output timepoint
451-
auto final_time = fwd_->getFinalTime();
452-
auto const timepoints = fwd_->model->getTimepoints();
453-
if (!fwd_->timepoint_states_.count(final_time)
454-
&& std::find(timepoints.cbegin(), timepoints.cend(), final_time)
455-
!= timepoints.cend()) {
456-
fwd_->timepoint_states_[final_time] = fwd_->final_state_;
446+
try {
447+
// This may throw in `CVodeSolver::getSens`
448+
// due to https://github.com/LLNL/sundials/issues/82.
449+
// Therefore, this dtor must be `noexcept(false)` to avoid
450+
// programm termination.
451+
fwd_->final_state_ = fwd_->getSimulationState();
452+
// if there is an associated output timepoint, also store it in
453+
// timepoint_states if it's not present there.
454+
// this may happen if there is an error just at
455+
// (or indistinguishably before) an output timepoint
456+
auto final_time = fwd_->getFinalTime();
457+
auto const timepoints = fwd_->model->getTimepoints();
458+
if (!fwd_->timepoint_states_.count(final_time)
459+
&& std::find(timepoints.cbegin(), timepoints.cend(), final_time)
460+
!= timepoints.cend()) {
461+
fwd_->timepoint_states_[final_time] = fwd_->final_state_;
462+
}
463+
} catch (std::exception const&) {
464+
// We must not throw in case we are already in the stack
465+
// unwinding phase due to some other active exception, otherwise
466+
// this will also lead to termination.
467+
//
468+
// In case there is another active exception,
469+
// `fwd_->{final_state_,timepoint_states_}` won't be set,
470+
// and we assume that they are either not accessed anymore, or
471+
// that there is appropriate error handling in place.
472+
if(!std::uncaught_exceptions()) {
473+
throw;
474+
}
457475
}
458476
}
459477
}

python/sdist/amici/jax/petab.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,7 @@ def run_simulation(
500500
simulation_condition[0], p
501501
)
502502
return self.model.simulate_condition(
503-
p=eqx.debug.backward_nan(p),
503+
p=p,
504504
ts_init=jax.lax.stop_gradient(jnp.array(ts_preeq)),
505505
ts_dyn=jax.lax.stop_gradient(jnp.array(ts_dyn)),
506506
ts_posteq=jax.lax.stop_gradient(jnp.array(ts_posteq)),

python/sdist/amici/sbml_import.py

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2292,9 +2292,29 @@ def _make_initial(
22922292

22932293
sym_math, rateof_to_dummy = _rateof_to_dummy(sym_math)
22942294

2295-
for species_id, species in self.symbols[SymbolId.SPECIES].items():
2296-
if "init" in species:
2297-
sym_math = smart_subs(sym_math, species_id, species["init"])
2295+
# we can't rely on anything else being properly initialized at this point, so we need to
2296+
# compute all initial values from scratch, recursively
2297+
for var in sym_math.free_symbols:
2298+
element_id = str(var)
2299+
# already recursive since _get_element_initial_assignment calls _make_initial
2300+
if (
2301+
ia := self._get_element_initial_assignment(element_id)
2302+
) is not None:
2303+
sym_math = sym_math.subs(var, ia)
2304+
elif (species := self.sbml.getSpecies(element_id)) is not None:
2305+
# recursive!
2306+
init = self._make_initial(get_species_initial(species))
2307+
sym_math = sym_math.subs(var, init)
2308+
elif var in self.symbols[SymbolId.SPECIES]:
2309+
sym_math = sym_math.subs(
2310+
var, self.symbols[SymbolId.SPECIES][var]["init"]
2311+
)
2312+
elif (
2313+
element := self.sbml.getElementBySId(element_id)
2314+
) and self.is_rate_rule_target(element):
2315+
# no need to recurse here, as value is numeric
2316+
init = sp.Float(element.getValue())
2317+
sym_math = sym_math.subs(var, init)
22982318

22992319
sym_math = smart_subs(sym_math, sbml_time_symbol, sp.Float(0))
23002320

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<sbml xmlns="http://www.sbml.org/sbml/level3/version2/core" level="3" version="2">
3+
<model metaid="debug" id="debug" substanceUnits="substance" timeUnits="time_unit" volumeUnits="volume" areaUnits="area" lengthUnits="length">
4+
<listOfUnitDefinitions>
5+
<unitDefinition id="length">
6+
<listOfUnits>
7+
<unit kind="metre" exponent="1" scale="0" multiplier="1"/>
8+
</listOfUnits>
9+
</unitDefinition>
10+
<unitDefinition id="area">
11+
<listOfUnits>
12+
<unit kind="metre" exponent="2" scale="0" multiplier="1"/>
13+
</listOfUnits>
14+
</unitDefinition>
15+
<unitDefinition id="volume">
16+
<listOfUnits>
17+
<unit kind="litre" exponent="1" scale="0" multiplier="1"/>
18+
</listOfUnits>
19+
</unitDefinition>
20+
<unitDefinition id="time_unit" name="time">
21+
<listOfUnits>
22+
<unit kind="second" exponent="1" scale="1" multiplier="6"/>
23+
</listOfUnits>
24+
</unitDefinition>
25+
<unitDefinition id="substance">
26+
<listOfUnits>
27+
<unit kind="mole" exponent="1" scale="-9" multiplier="1"/>
28+
</listOfUnits>
29+
</unitDefinition>
30+
</listOfUnitDefinitions>
31+
<listOfCompartments>
32+
<compartment id="cytosol" spatialDimensions="3" size="0.0005" constant="true"/>
33+
</listOfCompartments>
34+
<listOfSpecies>
35+
<species id="MR_i" compartment="cytosol" hasOnlySubstanceUnits="false" boundaryCondition="false" constant="false"/>
36+
<species id="MR_m" compartment="cytosol" hasOnlySubstanceUnits="false" boundaryCondition="false" constant="false"/>
37+
</listOfSpecies>
38+
<listOfParameters>
39+
<parameter id="synthesis_MR" constant="true"/>
40+
<parameter id="recycling" value="0.0000045" constant="true"/>
41+
<parameter id="binding" constant="true"/>
42+
<parameter id="MR_i_t0" value="1400000" constant="true"/>
43+
<parameter id="MR_m_t0" value="600000" constant="true"/>
44+
</listOfParameters>
45+
<listOfInitialAssignments>
46+
<initialAssignment symbol="MR_i">
47+
<math xmlns="http://www.w3.org/1998/Math/MathML">
48+
<ci> MR_i_t0 </ci>
49+
</math>
50+
</initialAssignment>
51+
<initialAssignment symbol="MR_m">
52+
<math xmlns="http://www.w3.org/1998/Math/MathML">
53+
<ci> MR_m_t0 </ci>
54+
</math>
55+
</initialAssignment>
56+
<initialAssignment symbol="synthesis_MR">
57+
<math xmlns="http://www.w3.org/1998/Math/MathML">
58+
<apply>
59+
<divide/>
60+
<cn> 0.00585177319092733 </cn>
61+
<cn> 0.00606 </cn>
62+
</apply>
63+
</math>
64+
</initialAssignment>
65+
<initialAssignment symbol="binding">
66+
<math xmlns="http://www.w3.org/1998/Math/MathML">
67+
<apply>
68+
<divide/>
69+
<apply>
70+
<minus/>
71+
<apply>
72+
<times/>
73+
<ci> recycling </ci>
74+
<ci> MR_i </ci>
75+
</apply>
76+
<ci> synthesis_MR </ci>
77+
</apply>
78+
<ci> MR_m </ci>
79+
</apply>
80+
</math>
81+
</initialAssignment>
82+
</listOfInitialAssignments>
83+
<listOfReactions>
84+
<reaction id="_J0" reversible="true">
85+
<listOfProducts>
86+
<speciesReference species="MR_i" stoichiometry="1" constant="true"/>
87+
</listOfProducts>
88+
<kineticLaw>
89+
<math xmlns="http://www.w3.org/1998/Math/MathML">
90+
<ci> synthesis_MR </ci>
91+
</math>
92+
</kineticLaw>
93+
</reaction>
94+
<reaction id="_J1" reversible="true">
95+
<listOfReactants>
96+
<speciesReference species="MR_i" stoichiometry="1" constant="true"/>
97+
</listOfReactants>
98+
<listOfProducts>
99+
<speciesReference species="MR_m" stoichiometry="1" constant="true"/>
100+
</listOfProducts>
101+
<kineticLaw>
102+
<math xmlns="http://www.w3.org/1998/Math/MathML">
103+
<apply>
104+
<times/>
105+
<ci> recycling </ci>
106+
<ci> MR_i </ci>
107+
</apply>
108+
</math>
109+
</kineticLaw>
110+
</reaction>
111+
<reaction id="_J2" reversible="true">
112+
<listOfReactants>
113+
<speciesReference species="MR_m" stoichiometry="1" constant="true"/>
114+
</listOfReactants>
115+
<listOfProducts>
116+
<speciesReference species="MR_i" stoichiometry="1" constant="true"/>
117+
</listOfProducts>
118+
<kineticLaw>
119+
<math xmlns="http://www.w3.org/1998/Math/MathML">
120+
<apply>
121+
<times/>
122+
<ci> binding </ci>
123+
<ci> MR_m </ci>
124+
</apply>
125+
</math>
126+
</kineticLaw>
127+
</reaction>
128+
</listOfReactions>
129+
</model>
130+
</sbml>

python/tests/test_sbml_import.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -852,3 +852,26 @@ def test_import_same_model_name():
852852

853853
assert model_module_1c.get_model().getParameters()[0] == 1.0
854854
assert model_module_1c.get_model().module is model_module_1c
855+
856+
857+
@skip_on_valgrind
858+
def test_regression_2642():
859+
sbml_file = Path(__file__).parent / "sbml_models" / "regression_2642.xml"
860+
sbml_importer = amici.SbmlImporter(sbml_file)
861+
model_name = "regression_2642"
862+
with TemporaryDirectory(prefix="regression_2642") as outdir:
863+
sbml_importer.sbml2amici(
864+
model_name=model_name,
865+
output_dir=outdir,
866+
)
867+
module = amici.import_model_module(
868+
module_name=model_name, module_path=outdir
869+
)
870+
model = module.getModel()
871+
solver = model.getSolver()
872+
model.setTimepoints(np.linspace(0, 1, 3))
873+
r = amici.runAmiciSimulation(model, solver)
874+
assert (
875+
len(np.unique(r.w[:, model.getExpressionIds().index("binding")]))
876+
== 1
877+
)

python/tests/valgrind-python.supp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1006,3 +1006,33 @@
10061006
fun:_ZN4rpds*
10071007
...
10081008
}
1009+
1010+
{
1011+
Python
1012+
Memcheck:Leak
1013+
match-leak-kinds: definite
1014+
fun:realloc
1015+
fun:_PyUnicodeWriter_Finish
1016+
obj:/usr/bin/python3.*
1017+
...
1018+
}
1019+
1020+
{
1021+
Something matplotlib. Cannot reproduce.
1022+
Memcheck:Leak
1023+
match-leak-kinds: definite
1024+
fun:_Znwm
1025+
fun:_ZL14PyFT2Font_initN8pybind116objectElSt8optionalISt6vectorIP9PyFT2FontSaIS4_EEEi.lto_priv.0
1026+
fun:_ZZN8pybind1112cpp_function10initializeIZNOS_6detail8initimpl7factoryIPFP9PyFT2FontNS_6objectElSt8optionalISt6vectorIS6_SaIS6_EEEiEPFNS2_9void_typeEvESD_SG_E7executeINS_6class_IS5_JEEEJNS_3argENS_5arg_vENS_7kw_onlyESN_SN_PKcEEEvRT_DpRKT0_EUlRNS2_16value_and_holderES7_lSC_iE_vJSY_S7_lSC_iEJNS_4nameENS_9is_methodENS_7siblingENS2_24is_new_style_constructorESM_SN_SO_SN_SN_SQ_EEEvOSR_PFT0_DpT1_EDpRKT2_ENUlRNS2_13function_callEE1_4_FUNES1F_
1027+
fun:_ZN8pybind1112cpp_function10dispatcherEP7_objectS2_S2_
1028+
fun:cfunction_call
1029+
fun:_PyObject_MakeTpCall
1030+
fun:_PyObject_VectorcallTstate
1031+
fun:_PyObject_VectorcallTstate
1032+
fun:method_vectorcall
1033+
fun:slot_tp_init
1034+
fun:type_call
1035+
fun:pybind11_meta_call
1036+
fun:_PyObject_MakeTpCall
1037+
fun:_PyEval_EvalFrameDefault
1038+
}

scripts/run-valgrind-py.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ if [ $# -eq 0 ]
2323
# for <class 'numpy.longdouble'> does not match any known type: falling back to type probe function.
2424
else
2525
# Run whatever was passed as arguments
26-
command=($@)
26+
command=("$@")
2727
fi
2828

2929

src/solver_cvodes.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -667,7 +667,7 @@ void CVodeSolver::getSensDky(realtype const t, int const k) const {
667667
int status
668668
= CVodeGetSensDky(solver_memory_.get(), t, k, sx_.getNVectorArray());
669669
if (status != CV_SUCCESS)
670-
throw CvodeException(status, "CVodeGetSens");
670+
throw CvodeException(status, "CVodeGetSensDky");
671671
}
672672

673673
void CVodeSolver::getDkyB(realtype const t, int const k, int const which)
@@ -716,7 +716,7 @@ void CVodeSolver::adjInit() const {
716716
status = CVodeAdjReInit(solver_memory_.get());
717717
} else {
718718
status = CVodeAdjInit(
719-
solver_memory_.get(), static_cast<int>(maxsteps_),
719+
solver_memory_.get(), static_cast<int>(maxsteps_ + 1),
720720
static_cast<int>(interp_type_)
721721
);
722722
setAdjInitDone();

version.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.30.0
1+
0.30.1

0 commit comments

Comments
 (0)