Repository navigation
BC I/O: refuse per-rank boundary files written for another decomposition - #1947
sbryngelson wants to merge 1 commit into
Conversation
pre_process writes restart_data/boundary_conditions/bc_<rank>.dat per rank, and simulation reads them by its own rank index. Run on a different rank count, each rank silently reads another rank's boundary slab, and a Dirichlet (-17) inflow then blows up within a few steps. pre_process now records the decomposition in decomposition.dat. Simulation aborts with a clear message when it differs; post_process, which only uses the data for boundary ghost cells, warns. Files from before this change are not checked. The per-rank MPI_File_open calls are now checked as well. Co-Authored-By: Claude <noreply@anthropic.com>
Lines of Code
|
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Copilot review overview
3 open findings
What changed in this PR
Adds a lightweight decomposition guard for per-rank boundary-condition restart files so runs don’t silently read the wrong slabs when restarted with a different MPI decomposition.
Changes:
- Write
restart_data/boundary_conditions/decomposition.datfrom rank 0 when generating per-rank BC files. - Check decomposition on read (abort by default; optionally warn-only via
strict=.false.). - Route per-rank
MPI_File_openthroughs_check_mpi_file_openand adjust post_process to use warn-only mode.
| File | Description |
|---|---|
src/post_process/m_data_input.f90 |
Post-process now calls BC read with strict=.false. (warn instead of abort on mismatch). |
src/common/m_boundary_io.fpp |
Writes decomposition metadata; validates it on read; adds MPI file-open error checking. |
🧠 Review effort: Lite
Give feedback about Copilot approvals in this survey to enter a drawing for a $150 gift card.
| ! The files below are per rank, so record the decomposition they were written for | ||
| open (1, FILE=trim(file_loc) // '/decomposition.dat', STATUS='replace') | ||
| write (1, '(4(I0,1X))') num_procs, num_procs_x, num_procs_y, num_procs_z | ||
| close (1) |
|
|
||
| inquire (FILE=trim(file_loc) // '/decomposition.dat', EXIST=file_exist) | ||
| if (.not. file_exist) return | ||
|
|
||
| open (1, FILE=trim(file_loc) // '/decomposition.dat', STATUS='old', ACTION='read') | ||
| read (1, *) decomp | ||
| close (1) | ||
|
|
| end if | ||
| print '(A)', & | ||
| & 'WARNING: ' // trim(file_loc) // ' was written for ' // trim(written) & | ||
| & // ' but this run uses ' // trim(running) & | ||
| & // '; boundary ghost values will be wrong. Use the pre_process rank count.' | ||
| end if |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #1947 +/- ##
==========================================
+ Coverage 62.64% 62.66% +0.01%
==========================================
Files 86 86
Lines 22425 22456 +31
Branches 3325 3329 +4
==========================================
+ Hits 14048 14071 +23
- Misses 6119 6125 +6
- Partials 2258 2260 +2 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|


Description
Restarting (or just running
simulation) on a different rank count frompre_processsilently corrupts Dirichlet (-17) inflow and boundary-patch data.Root cause. When
bc_iois on (any-17boundary ornum_bc_patches > 0),pre_processwrites the boundary types and buffers per rank, torestart_data/boundary_conditions/bc_<rank>.dat(s_write_parallel_boundary_condition_files).simulationandpost_processopenbc_<proc_rank>.datby their own rank index and read it unchecked (s_read_parallel_boundary_condition_files). The restart file itself is in a global layout and reads on any rank count, so the only thing tying a run to the pre_process decomposition is this directory, and nothing checks it. On another rank count each rank gets another rank's boundary slab, with the wrong position and possibly the wrong size. The per-rankMPI_File_openwas not checked either, so a missing file went unnoticed too.Fix (minimal).
pre_processrank 0 also writesrestart_data/boundary_conditions/decomposition.dat, containingnum_procs num_procs_x num_procs_y num_procs_z.simulationaborts on a mismatch, with a message that names both decompositions.post_processonly uses the data for boundary ghost cells, so it warns instead of aborting (new optionalstrictargument). Workflows that post-process on a different rank count keep working, but are told that boundary ghost values are wrong.decomposition.datand are read as before, unchecked.MPI_File_opencalls now go throughs_check_mpi_file_open.Not done here: the full fix. The full fix would write and read these arrays in a global parallel-I/O layout, like the restart file, so that any rank count works. I did not do it in this PR because it is not contained:
-buff_size:m+buff_sizehalos, which overlap between ranks and include corner cells, andbuff_sizecan differ between targets;Verification
Production (OLCF Frontier, CCE 19, OpenACC).
pre_processran on 192 ranks and the restart ran on 64 ranks at step 15714. The inflow cellj = 0reached ICFL 1.015 at step 15723. In a second run (360 ranks, then 240), p = -4e47 appeared at the inflow face at step 2. Runs that kept the rank count were unaffected.This branch. I ran these on a Frontier CPU compute node (GNU 12.3 + Cray MPICH, Release). The case is a 2D uniform channel, 50x40, with
bc_x%beg = -17.decomposition.dat=2 2 1 1./restart_data/boundary_conditions was written for 2 ranks (2x1x1) but this run uses 1 ranks (1x1x1). These per-rank boundary files only work on the decomposition that wrote them: run on that rank count, or rerun pre_process on this one.mastermastermaster(nodecomposition.dat)Builds:
pre_process,simulationandpost_processcompile with CCE 19 on CPU, andpre_processandsimulationwith GNU 12.3. The post_process warning path was compiled but not run. 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).No regression test is added. The test harness compares goldens and has no way to expect an abort, and a test that restarts on a different rank count would need harness support.
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
This PR was prepared with the assistance of an AI tool (Claude Code). The bug was found in production runs on Frontier; the fix was exercised on the small cases above.
PR template credit: junegunn