Skip to content

Commit 0ec0c6f

Browse files
committed
...
1 parent 947aba7 commit 0ec0c6f

File tree

7 files changed

+76
-1
lines changed

7 files changed

+76
-1
lines changed

include/amici/model.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1362,6 +1362,14 @@ class Model : public AbstractModel, public ModelDimensions {
13621362
*/
13631363
void updateHeaviside(std::vector<int> const& rootsfound);
13641364

1365+
/**
1366+
* @brief Disable the event with index `ie` because it just triggered.
1367+
*
1368+
* Not to be called by user code.
1369+
*
1370+
* @param ie Event index.
1371+
*/
1372+
void disable_event(int const ie) { state_.root_enabled.at(ie) = false; }
13651373
/**
13661374
* @brief Check if the given array has only finite elements.
13671375
*

include/amici/model_state.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ struct ModelState {
2929
stotal_cl.resize((dim.nx_rdata - dim.nx_solver) * dim.np, 0.0);
3030
unscaledParameters.resize(dim.np);
3131
fixedParameters.resize(dim.nk);
32+
root_enabled.resize(dim.ne, true);
3233
}
3334

3435
/**
@@ -56,14 +57,20 @@ struct ModelState {
5657
* (dimension: nplist)
5758
*/
5859
std::vector<int> plist;
60+
61+
/**
62+
* Flags indicating whether a root function element is enabled
63+
* (dimension: `ne`)
64+
*/
65+
std::vector<bool> root_enabled;
5966
};
6067

6168
inline bool operator==(ModelState const& a, ModelState const& b) {
6269
return is_equal(a.h, b.h) && is_equal(a.total_cl, b.total_cl)
6370
&& is_equal(a.stotal_cl, b.stotal_cl)
6471
&& is_equal(a.unscaledParameters, b.unscaledParameters)
6572
&& is_equal(a.fixedParameters, b.fixedParameters)
66-
&& a.plist == b.plist;
73+
&& a.plist == b.plist && a.root_enabled == b.root_enabled;
6774
}
6875

6976
/**

include/amici/serialization.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ void serialize(Archive& ar, amici::Model& m, unsigned int const /*version*/) {
145145
ar & m.state_.unscaledParameters;
146146
ar & m.state_.fixedParameters;
147147
ar & m.state_.plist;
148+
ar & m.state_.root_enabled;
148149
ar & m.x0data_;
149150
ar & m.sx0data_;
150151
ar & m.nmaxevent_;

python/tests/test_events.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1072,3 +1072,47 @@ def test_event_uses_values_from_trigger_time(tempdir):
10721072
)
10731073

10741074
# TODO: test ASA after https://github.com/AMICI-dev/AMICI/pull/1539
1075+
1076+
1077+
def test_simultaneous_events(tempdir):
1078+
"""Test simultaneously firing events with different trigger functions."""
1079+
from amici.antimony_import import antimony2amici
1080+
1081+
model_name = "test_simultaneous_events"
1082+
antimony2amici(
1083+
r"""
1084+
target1_0 = 1
1085+
target1 = target1_0
1086+
one = 1
1087+
target1' = one
1088+
two = 2
1089+
target2_0 = two
1090+
target2 = target2_0
1091+
target2' = 1
1092+
some_time = time
1093+
some_time' = 1
1094+
trigger_time = 1000
1095+
1096+
E1: at some_time >= trigger_time, priority=10, fromTrigger=false:
1097+
target1 = target1 + 10;
1098+
E2: at time >= trigger_time, priority=20, fromTrigger=false:
1099+
target2 = target2 + 10;
1100+
""",
1101+
model_name=model_name,
1102+
output_dir=tempdir,
1103+
)
1104+
1105+
model_module = import_model_module(model_name, tempdir)
1106+
1107+
model = model_module.get_model()
1108+
model.setTimepoints([0, 2])
1109+
solver = model.getSolver()
1110+
solver.setRelativeTolerance(1e-6)
1111+
solver.setAbsoluteTolerance(1e-6)
1112+
solver.setSensitivityOrder(SensitivityOrder.first)
1113+
solver.setSensitivityMethod(SensitivityMethod.forward)
1114+
1115+
rdata = amici.runAmiciSimulation(model, solver)
1116+
assert rdata.status == amici.AMICI_SUCCESS
1117+
assert_allclose(rdata.by_id("target1"), [1.0, 13.0])
1118+
assert_allclose(rdata.by_id("target2"), [2.0, 14.0])

src/forwardproblem.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,7 @@ void EventHandlingSimulator::handle_event(
359359
? std::optional<SimulationState>(get_simulation_state())
360360
: std::nullopt)}
361361
);
362+
model_->disable_event(ie);
362363
}
363364
}
364365

src/model.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,7 @@ void Model::initEvents(
437437
roots_found.at(ie) = 1;
438438
}
439439
}
440+
state_.root_enabled[ie] = rootvals.at(ie) < 0;
440441
}
441442
}
442443

src/model_ode.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,19 @@ void Model_ODE::froot(realtype t, const_N_Vector x, gsl::span<realtype> root) {
9797
state_.unscaledParameters.data(), state_.fixedParameters.data(),
9898
state_.h.data(), state_.total_cl.data()
9999
);
100+
101+
for (int ie = 0; ie < ne; ++ie) {
102+
if (!state_.root_enabled[ie]) {
103+
if (root[ie] < 0.0) {
104+
// If the disabled root function becomes negative,
105+
// re-enable it.
106+
state_.root_enabled[ie] = true;
107+
} else {
108+
// If the root function is disabled, mask it
109+
root[ie] = 1.0;
110+
}
111+
}
112+
}
100113
}
101114

102115
void Model_ODE::fxdot(

0 commit comments

Comments
 (0)