Repository navigation
Conversation
…o batches (lanl#1277) An event on the clock at a fixed time and one on a state a requested column moves cross on one instant and fire as two batches, a root's slack apart. lanl#49's refusal of two events on one instant whose times move differently was asked of one batch, so it saw neither with the other: S(3) went from 3.75 to 4.25 across k = 1, and the run returned dS/dk = 1.25, one side's slope. Before a fire is recorded, it is now asked against each earlier fire in event_fires: one moved and the other not, within 2·kEventRootSlack· kSwitchInstantUlps·ε·max(|t|,1), and the run is refused, naming both.
|
Thanks. I checked this at 3237402 against our #1326 (#947, head 0e791e3), which also changes how events on one instant are drained. The two don't conflict. There's one thing in the new message, below, that is independent of #1326. Measured on macOS arm64, with three builds: this PR alone, #1326 alone, and the two merged with No conflict with #1326#1326 holds a strict trigger, On the merged build:
1. The refusal names the batch's first event, not the one that movesThis is #1277's model with a strict event beside With
A fix: ask #49's condition before the new block: |
Closes #1277.
What was wrong
An event on the clock and an event on the state that cross on one instant fire as two batches, a root's slack apart, when the first is at a fixed time and a requested column moves the second. #49's refusal, of two events on one instant whose times move differently (
fixed_event >= 0 && tau_event >= 0inapply_event_sensitivity_jump), is asked of one batch. It never saw the two together.#1277's model:
S' = 1,q' = k;E0: at (time >= 2.5): S = S + 1;E1: at (q >= 2.5): S = S/2.On main 9a26f5b:
sensitivity_params=["k"]at k = 1 returned dS/dk(3) = 1.25 with no error. That is one side's slope at a jump, not a derivative.The fix
src/cvode_simulator.cpp,apply_event_sensitivity_jump. Before a fire is recorded inevent_fires, it is asked against every earlier fire kept there. If exactly one of the two is moved by a requested column (EventFire::movesagainst this fire'sfire_moves), and the two are within2·kEventRootSlack·kSwitchInstantUlps·ε·max(|t|, 1)of each other, the run is refused. That is the same reachclock_crossings_atgives an event root beside a switch, 2.8e-13 at t = 2.5. The message names both events and which one moves:This is #1277's proposal:
event_firesalready holds each earlier fire and whether it moves.The check matches #49's refusal within one batch: it does not test whether the two events commute.
Tests (
test_event_batch_order_sensitivity.py)test_a_fixed_fire_and_a_moving_one_in_two_batches_are_refused, with the trigger at 2.5 − 1e-13 (E1 first), at 2.5, and at 2.5 + 1e-13 (E0 first). Probing showed 2.5 − 1e-14 lands in one batch, where Forward sensitivity w.r.t. a switch time encoded as an SBML event (event-time sensitivity dt*/dp != 0) #49's own refusal already applies, so the "E1 first" case sits at −1e-13 to reach the two-batch path.test_the_pair_a_millionth_apart_runs, with the trigger at 2.5 ± 1e-6. The order holds across k, and the run matches the closed form dS/dk = trigger/2.test_the_pair_on_one_instant_runs_where_no_column_moves_either. Withsensitivity_params=["a"]on the coincident pair, dS(3)/da = 1.75, the same in either order.Mutations, each caught:
E1 firstcaseonandE0 firstE1 firstandE0 first(1e-13 apart)Measured
fd_sens: the nightly sweep (106 jobs on 53.netmodels, sensitivities against central differences), run on main's core and on this one. Both give 106 PASS, with identical verdicts and no new refusal.