Following up on discussion #2200 — minimal repro as requested.
Symptom. post_processed_outputs.q_min returns mathematically impossible negative values (q > 0 by definition) in short multi-tick episodes, then recovers to its previous physical value. In the attached repro: q_min ≈ 2.1 at t = 59 s, then −0.59 / −0.68 / −0.51 for t = 60–62 s, then clean recovery to 1.84 and a smooth decay from there. The upstream profiles evolve smoothly through the episode — nothing in the plasma state jumps.
Where. The value traces to the safety_factor_fit outputs (_minimum_location_value_in_interval). I also see the same signature independently in long flat-top runs (single-tick jumps to large negative values around t ≈ 5 200 s on a different config), so it is not specific to this setpoint history.
Repro. Pure TORAX 1.4, no external code. The bundled iterhybrid_rampup example config with three standard dict-level modifications (documented inline: Ip schedule extended past 80 s, scheduled pedestal values, two extra source handles), stepping via torax.experimental.make_step_fn / jitted_fixed_time_step at dt = 1.0 s while replaying a recorded actuator setpoint history through update_provider_from_mapping — one override per tick, as a controller would command them.
python torax_qmin_negative_repro.py
Runs ~40 s on CPU, prints q_min per tick, exits 1 when negative q_min is observed. Attached: torax_qmin_negative_repro.py + repro_setpoints.csv (150 rows).
Expected: q_min > 0 throughout.
Actual:
t = 59.0 s q_min = 2.099608
t = 60.0 s q_min = -0.587315 <-- NEGATIVE
t = 61.0 s q_min = -0.675153 <-- NEGATIVE
t = 62.0 s q_min = -0.509927 <-- NEGATIVE
t = 63.0 s q_min = 1.843... (recovered)
Environment: TORAX 1.4, CPU, default precision via torax.set_jax_precision(), Windows 11 / Python 3.13.
Happy to test candidate fixes against the longer runs where the same signature appears.
qmin_repro.zip
Following up on discussion #2200 — minimal repro as requested.
Symptom. post_processed_outputs.q_min returns mathematically impossible negative values (q > 0 by definition) in short multi-tick episodes, then recovers to its previous physical value. In the attached repro: q_min ≈ 2.1 at t = 59 s, then −0.59 / −0.68 / −0.51 for t = 60–62 s, then clean recovery to 1.84 and a smooth decay from there. The upstream profiles evolve smoothly through the episode — nothing in the plasma state jumps.
Where. The value traces to the safety_factor_fit outputs (_minimum_location_value_in_interval). I also see the same signature independently in long flat-top runs (single-tick jumps to large negative values around t ≈ 5 200 s on a different config), so it is not specific to this setpoint history.
Repro. Pure TORAX 1.4, no external code. The bundled iterhybrid_rampup example config with three standard dict-level modifications (documented inline: Ip schedule extended past 80 s, scheduled pedestal values, two extra source handles), stepping via torax.experimental.make_step_fn / jitted_fixed_time_step at dt = 1.0 s while replaying a recorded actuator setpoint history through update_provider_from_mapping — one override per tick, as a controller would command them.
python torax_qmin_negative_repro.py
Runs ~40 s on CPU, prints q_min per tick, exits 1 when negative q_min is observed. Attached: torax_qmin_negative_repro.py + repro_setpoints.csv (150 rows).
Expected: q_min > 0 throughout.
Actual:
t = 59.0 s q_min = 2.099608
t = 60.0 s q_min = -0.587315 <-- NEGATIVE
t = 61.0 s q_min = -0.675153 <-- NEGATIVE
t = 62.0 s q_min = -0.509927 <-- NEGATIVE
t = 63.0 s q_min = 1.843... (recovered)
Environment: TORAX 1.4, CPU, default precision via torax.set_jax_precision(), Windows 11 / Python 3.13.
Happy to test candidate fixes against the longer runs where the same signature appears.
qmin_repro.zip