Repository navigation
Preserve restart checkpoints and IB diagnostic history - #1960
Draft
sbryngelson wants to merge 7 commits into
Draft
sbryngelson wants to merge 7 commits into
sbryngelson wants to merge 7 commits into
Conversation
CFL mode saved when abs(mod(mytime, t_save)) < dt. A restart starts at exactly n_start*t_save, so after the first step mod(mytime, t_save) is within an ulp of dt and falls below it about half the time. The save then writes index int(mytime/t_save) = n_start and replaces the restart checkpoint with the state one step later. Save instead when int(mytime/t_save), the index s_save_data writes, moves past the last saved index (n_start at start), or at t_stop. Fresh-run saves happen at the same steps as before. The CFL restart test restarts from save indices 1-4 and checks that each restart leaves its own checkpoint byte-identical.
Lines of Code
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #1960 +/- ##
==========================================
+ Coverage 61.79% 61.80% +0.01%
==========================================
Files 86 86
Lines 22773 22775 +2
Branches 3353 3354 +1
==========================================
+ Hits 14073 14077 +4
+ Misses 6211 6208 -3
- Partials 2489 2490 +1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
sbryngelson
force-pushed
the
fix-cfl-restart-save
branch
from
October 10, 2026 16:27
503a8d5 to
a50763e
Compare
…tart The record for step N is written at the start of step N, and the time loop exits before starting its last step, so no run ever recorded the force at t_step_stop. The next run skips its first step on purpose (that force is still the one from before the run), so every restart left exactly one step missing from the history. Write the last step's record after the loop. A resumed run also deleted and recreated D/ib_forces.dat, losing the earlier history. It now writes D/ib_forces_<t_step_start>.dat (D/ib_forces_n<n_start> .dat with cfl_dt), so the per-run files concatenate into a complete history. (cherry picked from commit dadf7ee)
Only the D/ib_forces.dat line changes: the old line is kept verbatim and the new last-step row(s) are appended. Regenerated with GNU 12.3 + MPI, Release on Frontier; every pre-existing value matches the committed NVHPC goldens under each test's tolerance. All other lines and the metadata are untouched. (cherry picked from commit 8a2e038)
…ntees The final record still obeys ib_force_stride, and with cfl_dt the step counter restarts each run, so a gap-free join needs stride 1 there. (cherry picked from commit b8f3e44)
Enable ib_force_wrt in the particle-cloud restart cases. run_restart now appends the resumed run's ib_forces_<mid>.dat to the first run's ib_forces.dat, so the roundtrip checks that the first file survives and the two join into the straight run's history. Goldens gain the ib_forces.dat entry only. (cherry picked from commit 4ac4675)
Under cfl_dt the caller passes the save count and t_step_save is left at its default, so t_step/t_step_save collapsed saves 1-99 onto one slot in lustre_ib.dat. Share one f_save_index between writer and post_process reader. (cherry picked from commit 82e7652)
sbryngelson
marked this pull request as draft
October 10, 2026 20:58
This was referenced Oct 10, 2026
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.
Summary
CFL restarts could overwrite their source checkpoint, chained runs could omit the last IB-force record and overwrite earlier force history, and CFL IB-marker saves could overwrite each other. This PR combines the three existing fixes so saved checkpoints and IB diagnostics retain their intended indices and run history.
Consolidation
This existing PR retains its original commits and discussion. Changes from #1950, #1961 are added as separate commits with original authors/messages and
cherry-pick -xprovenance. The complete source PR descriptions, verification records, and limitations are reproduced below. Their original verification claims are historical records, not fresh runs on this combined head.The redundant merge of master on #1950 carried no merge-resolution changes; the combined branch merges current master directly and retains all four non-merge commits from #1950.
Verification of the combined branch
git diff --checkpasses excluding generated golden metadata; its original formatting is retained../mfc.sh precheckpasses all seven gates: formatting, spelling, toolchain lint/tests, source lint, documentation references, parameter documentation, and example case validation.This consolidation was performed with OpenAI Codex.
Contribution Policy
We do not accept pull requests generated primarily by AI without genuine understanding or real-world usage context.
All contributions are expected to demonstrate:
If these expectations are not met, we would prefer to implement the changes ourselves rather than spend time reviewing low-effort submissions.
Acknowledgement
PR template credit: junegunn
Original PR documentation
#1960: CFL restarts: don't overwrite the restart checkpoint on the first step
Source: #1960
Original head:
a50763e7cb51e04d5443287fc677e9a101bae43cComplete original PR description
Summary
In CFL mode (
cfl_adap_dt/cfl_const_dt), a restart can overwrite its own restart checkpoint with the state one step later. @thierrydaoud spotted the symptom in #1926.Mechanism
p_main.fppsaved whenabs(mod(mytime, t_save)) < dt .or. mytime >= t_stop. A restart setsmytime = t_save*n_startexactly. After the first step,mod(n_start*t_save + dt, t_save)should equaldt, but because of round-off it comes out within an ulp ofdtand falls below it about half the time. The save then fires ands_save_datawrites indexint(mytime/t_save) = n_start, so checkpointn_startis replaced by the state after one step.The cause is round-off, not a change in
dt. Thedtused in the check is the step's owndt, becauses_compute_dtruns only at the start ofs_perform_time_step.Fix
Track the last saved index, starting at
n_start. Save whenint(mytime/t_save)moves past it, or att_stop. This is the same expressions_save_datauses for the file index, so each index is written once and the restart checkpoint is never written again.k*t_save.t_stopis unchanged.int(mytime/t_save)rounds down just after a crossing, the save comes one step late with the correct index. The old check would have written the previous index in that case.post_processonly readsint(t_stop/t_save)and does not use themodpattern. No other code usesmod(mytime, ...).Reproduction (Frontier, CCE CPU,
--no-mpi)I modified
examples/1D_sodshocktube/case.pyto usecfl_adap_dt = T,t_save = 0.01,t_stop = 0.06,parallel_io = F,format = 1. I ran it fresh, then restarted it withn_start = 1..4, resettingp_allto the fresh run's output before each restart.At one overwrite, the debug output showed
mod(mytime, t_save) = 5.05147325735151587E-04 < dt = 5.05147325735151695E-04.n_startoverwrittenn_startoverwrittenp_all, master vs this PRI also emulated the old and new save logic in float64 over 50k random
dtsequences andt_save/t_stopcombinations. The new logic never skipped or repeated a non-final index and never rewroten_start. On fresh starts it saved at the same steps as the old logic. On restarts it differed only in the cases where the old logic rewroten_start.Regression test
New case
Restart Roundtrip -> 1D -> cfl_adap_dt=T(25EB3D1F). Forrestart_checkcases in CFL mode,run_restartruns the case straight, then restarts from each interior save index (1-4). After each restart it checks thatp_all/*/<n_start>/is byte-identical to what it was before.The usual comparison of restarted output with the straight run is skipped for CFL cases. A CFL restart starts from a checkpoint stamped
n_start*t_saverather than its true time, so its later states differ from the straight run.t_save = 2^-8, son_start*t_saveis exact. On master this test fails here withRestart from n_start=1 rewrote its own restart checkpoint.With the fix, the test is deterministic: no restart can write its own index. On master, whether the bug triggers depends on round-off, so a given compiler might not catch a regression. Checking four restarts makes a miss unlikely.
The golden file was generated with CCE 19 on Frontier.
Testing (Frontier login node, CCE CPU,
--no-mpi)./mfc.sh format,./mfc.sh build --no-mpi -j 8./mfc.sh test --no-mpi -j 8 -o <24 UUIDs>: everycfl_adap_dt/cfl_const_dtcase and everyrestart_checkcase. 24 passed../mfc.sh test --no-mpi -j 8 -% 20: 142 passed, 0 failed.Tested on OLCF Frontier (CCE CPU, no MPI).
Contribution Policy
We do not accept pull requests generated primarily by AI without genuine understanding or real-world usage context.
All contributions are expected to demonstrate:
If these expectations are not met, we would prefer to implement the changes ourselves rather than spend time reviewing low-effort submissions.
Acknowledgement
PR template credit: junegunn
#1950: IB force history: record each run's last step; don't overwrite on restart
Source: #1950
Original head:
4ac46752d967a0e620f27d02a7442585ce3c2870Complete original PR description
Description
Chaining a run with
ib_force_wrtacross restarts loses IB force history in two ways.s_write_ib_force_history(t_step)runs at RK stage 1 of step N and records the force left by step N-1. The time loop inp_mainexits as soon ast_step == t_step_stop, so the record fort_step_stop(the force after the run's last step) is never written. The next run deliberately skips itst_step_start, because at that point the force is still the one from before the run (the existing comment explains this). So no run ever writes that step. Our exports showed exactly one missing record at each restart step, e.g. steps 12735, 25470 and 38205 in a three-chunk run.s_open_ib_force_historydeletes and recreatesD/ib_forces.daton every run. A restarted run therefore keeps only its own rows, and every earlier chunk's history is gone unless the user renamed the file in between.Fix.
p_maincallss_write_ib_force_history(t_step)once more after the time loop, which writes the run's last step. I did not write the resumed run's first step instead, because that would record the stale (zero) force the existing skip avoids.D/ib_forces_<t_step_start>.dat(D/ib_forces_n<n_start>.datwithcfl_dt) instead of overwritingD/ib_forces.dat. A fresh run still writesD/ib_forces.dat. Within each file the documented layout is unchanged: row 0 is that run's first recorded step, there is no header, and offsets are fixed.docs/documentation/case.mddescribes the per-run files and the new last row.Why not append into one file. That needs either absolute step-based rows, or a row base inferred from the existing file. Absolute rows leave NUL-filled holes whenever a run starts from a restart without the earlier history (the existing docs and comments avoid holes on purpose). An inferred base is silently misaligned after a chunk killed past its last restart dump. Separate files avoid both, and they still concatenate into the full history.
Impact on results and goldens
The physics is unchanged. Every run with
ib_force_wrtnow has one more row per body inD/ib_forces.dat. Ten goldens contain that file (135F548B, 49893269, 4BED9896, 5A22B45F, B317404C, C8AD6271, D6794F4C, E085CC5A, E5B66084, F200F862), and they are updated only on theD/ib_forces.datline:packtol.compareat each test's tolerance (1e-10, Examples 1e-3), the regenerated values for every field, including the existingib_forcesrows, match the committed NVHPC 25.11 goldens.ib_forcesline. The old line is a string prefix of the new one, every other line and everygolden-metadata.txtis untouched, and the change is one line per golden../mfc.sh test --generate --only <those 10>reproduces them.Verification
All runs were on a Frontier CPU compute node (GNU 12.3 + Cray MPICH, Release, 2 ranks). The case is a 2D circle moving at a prescribed velocity, with
ib_force_wrt.ib_forces.dat,ib_forces_20.dat)masterOn this branch the two files concatenated match the straight run's
ib_forces.dat: the same 40 times, and a maximum absolute difference of 2e-17 over all columns.With the updated goldens, on the same node:
ib_forcestestsmasterVariable count didn't match for D/ib_forces.dat(the missing last row)simulationcompiles with CCE 19 (CPU) and GNU 12.3. Precheck passes, apart from twotest_thermochemcases that fail on the Frontier login node because they compile with the system/usr/bin/gfortran(addressed by #1943).Contribution Policy
We do not accept pull requests generated primarily by AI without genuine understanding or real-world usage context.
All contributions are expected to demonstrate:
If these expectations are not met, we would prefer to implement the changes ourselves rather than spend time reviewing low-effort submissions.
Acknowledgement
We hit this in chunked production runs on Frontier; the fix was exercised on the small cases above.
PR template credit: junegunn
#1961: IB markers: index each save by the save count under CFL time stepping
Source: #1961
Original head:
82e765240f06050cc2f2adc43d43487abfa4ae2aComplete original PR description
Summary
With CFL-based time stepping (
cfl_adap_dtorcfl_const_dt) andparallel_io = T(shared file, notfile_per_process), post_process shows the wrong immersed-boundary markers for moving IBs: every save in a block of 100 shows the markers of that block's last save.The simulation writes each save's
ib_markersintorestart_data/lustre_ib.datat an offset set by the save number, computed astime_step/t_step_save, and post_process reads it back the same way. Under CFL stepping the caller already passes the save count (save_count = int(mytime/t_save)), andt_step_savekeeps its default of −100. Sok/(-100)is 0 for saves 1–99, −1 for 100–199, and so on: saves overwrite one slot. Fixed-dt runs are unaffected.Change
f_save_index(t_step, cfl_mode, t_step_save)inm_helper_basicreturnst_stepunder CFL stepping, elset_step/t_step_save. The writer (s_write_parallel_ib_data) and the reader (s_read_ib_data_files) both use it, so the two cannot drift apart.Verification
A 2D moving cylinder, 100×100,
cfl_adap_dt = T, 8 saves,parallel_io = T, 2 ranks. For each save, the centroid of the post_processib_markersfield was compared with the IB centre inrestart_data/ib_state_<save>.dat.Found while rendering a 201-save shock–particle-curtain run with 38 moving reacting particles, where markers at save 40 sat 0.5 mm from the particles.
./mfc.sh test -o IBM: 61 passed. No regression test is added: the suite has no pattern for checking post_process output against IB state.The bug was found and verified as described above.
Acknowledgement