Skip to content

refactor: unify equation/range indices into sys_idx; clean BC globals#1365

Open
sbryngelson wants to merge 12 commits intoMFlowCode:masterfrom
sbryngelson:eqn-idx-refactor
Open

refactor: unify equation/range indices into sys_idx; clean BC globals#1365
sbryngelson wants to merge 12 commits intoMFlowCode:masterfrom
sbryngelson:eqn-idx-refactor

Conversation

@sbryngelson
Copy link
Copy Markdown
Member

@sbryngelson sbryngelson commented Apr 9, 2026

Closes #828.

Summary

BC scalars (bc_xyz_info)

  • Added bc_xyz_info derived type grouping bc_x/y/z as bc%x/y/z
  • s_populate_capillary_buffers now takes an explicit bc argument instead of implicit globals
  • Removed dead module-level scalars bcxb/bcxe/bcyb/bcye/bczb/bcze from m_cbc.fpp
  • Replaced Fypp templates bc${XYZ}$b/bc${XYZ}$e with bc_${XYZ}$%beg/bc_${XYZ}$%end
  • Added GPU_UPDATE for bc_x/y/z%beg/end so CBC device kernels see correct values

Unified equation index type (eqn_idx)

  • Added eqn_idx_info derived type in m_derived_types.fpp consolidating all equation indices:
    • Range indices (int_bounds_info): cont, mom, adv, bub, stress, xi, B, int_en, species
    • Scalar indices (integer): E, n, alf, gamma, pi_inf, c, damage, psi
  • Replaced ~11 scattered module-level index variables (cont_idx, mom_idx, adv_idx, bub_idx, stress_idx, xi_idx, B_idx, internalEnergies_idx, species_idx) with a single eqn_idx in all three targets
  • GPU DECLARE/UPDATE consolidated: eqn_idx instead of 6+ separate scalars and ranges
  • eqn_idx contains no allocatable members — safe for GPU_DECLARE as a single struct in all cases

QBMM index split (qbmm_idx)

  • Removed allocatable arrays (rs, vs, ps, ms, moms, fullmom) from bub_bounds_info, leaving it with just beg/end (now int_bounds_info)
  • Added qbmm_idx_info type and qbmm_idx module variable for QBMM moment index mappings with its own @:ALLOCATE/@:DEALLOCATE lifecycle in all three targets
  • GPU_DECLARE removed for qbmm_idx — members are always accessed via host-side local copies before GPU use, so no device struct needed

indices.dat improvements (pre_process)

  • Replaced hardcoded unit 1 with newunit=iu
  • Replaced degenerate do i = E, E loop with a guarded write
  • Rewrote summary block using eqn_idx fields directly via a write_range internal helper
  • Added previously missing entries: xi, B, and color function

Test plan

  • ./mfc.sh precheck -j 8 — all 6 checks pass
  • ./mfc.sh build -j 8 --no-gpu — all 3 targets build
  • ./mfc.sh build -j 8 --gpu acc — all 3 targets build with nvfortran OpenACC

…remove dead bcxb/bcxe module vars

- Add bc_xyz_info type to m_derived_types.fpp grouping bc x/y/z info
- s_populate_capillary_buffers now takes explicit bc argument instead
  of implicitly depending on bc_x/bc_y/bc_z module globals
- Access pattern is now bc%x%beg, bc%x%end etc. (was implicit global)
- Remove unused bcxb/bcxe/bcyb/bcye/bczb/bcze scalars from m_cbc.fpp
  (declared and GPU-declared but never read)
- Add eqn_idx_info type to m_derived_types.fpp with members E, n, alf,
  gamma, pi_inf, c
- Replace 6 standalone integer globals (E_idx, alf_idx, c_idx, n_idx,
  gamma_idx, pi_inf_idx) with type(eqn_idx_info) :: eqn_idx in all
  three targets' m_global_parameters.fpp
- Update GPU_DECLARE and GPU_UPDATE in simulation to use eqn_idx struct
- ~672 use-sites updated to eqn_idx%E, eqn_idx%alf, etc.
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 9, 2026

Claude Code Review

Head SHA: 28b88d0

Files changed:

  • 37 files
  • src/common/m_derived_types.fpp
  • src/common/m_boundary_common.fpp
  • src/simulation/m_cbc.fpp
  • src/simulation/m_ibm.fpp
  • src/simulation/m_global_parameters.fpp
  • src/simulation/m_rhs.fpp
  • src/simulation/m_variables_conversion.fpp
  • src/simulation/m_start_up.fpp
  • src/pre_process/m_global_parameters.fpp
  • src/post_process/m_global_parameters.fpp

Findings

GPU correctness: bc_x/bc_y/bc_z no longer device-resident in m_cbc.fpp

src/simulation/m_cbc.fpp

The PR removes the module-level device-resident scalars bcxb, bcxe, bcyb, bcye, bczb, bcze along with their GPU_DECLARE and GPU_UPDATE boilerplate:

-    integer :: bcxb, bcxe, bcyb, bcye, bczb, bcze
-    $:GPU_DECLARE(create='[dj, bcxb, bcxe, bcyb, bcye, bczb, bcze]')

and the initialization code:

-        bcxb = bc_x%beg
-        bcxe = bc_x%end
-        $:GPU_UPDATE(device='[bcxb, bcxe]')
-        ...

The replacement accesses bc_x%beg, bc_x%end, bc_y%beg, bc_y%end, bc_z%beg, bc_z%end directly inside s_apply_cbc, which is a GPU device routine:

+                        if ((cbc_loc == -1 .and. bc_${XYZ}$%beg == BC_CHAR_SLIP_WALL) &
+                            & .or. (cbc_loc == 1 .and. bc_${XYZ}$%end == BC_CHAR_SLIP_WALL)) then

The explicit extraction pattern (bcxb = bc_x%beg + GPU_UPDATE) is the canonical codebase pattern for making host-only module variables accessible inside GPU kernels. No GPU_DECLARE or GPU_UPDATE for bc_x, bc_y, bc_z appears anywhere in the changed files (including m_global_parameters.fpp). If these variables remain host-only, GPU builds will silently read stale or incorrect values for all BC_CHAR_* checks inside s_apply_cbc, breaking all characteristic boundary conditions (slip wall, NR inflow/outflow, supersonic in/outflow, etc.) in GPU runs.

Mitigation: either add GPU_DECLARE(create='[bc_x, bc_y, bc_z]') and a corresponding GPU_UPDATE(device='[bc_x, bc_y, bc_z]') in m_global_parameters.fpp, or restore the scalar extraction approach.


Potential compiler issue: struct member in copyin clause (m_ibm.fpp)

src/simulation/m_ibm.fpp

-        $:GPU_PARALLEL_LOOP(private='[i, j, k, patch_id, rho]', copyin='[E_idx, momxb]', collapse=3)
+        $:GPU_PARALLEL_LOOP(private='[i, j, k, patch_id, rho]', copyin='[eqn_idx%E, momxb]', collapse=3)

eqn_idx is a derived-type module variable now declared with $:GPU_DECLARE(create='[sys_size, eqn_idx, bub_idx]') in m_global_parameters.fpp, making the full struct device-resident. Specifying a struct member (eqn_idx%E) in the copyin clause of a parallel loop while the parent struct is already declare created may cause a compile error or diagnostic on some of the four CI-gated compilers (nvfortran, Cray ftn, Intel ifx, gfortran). Since eqn_idx is already present on the device, the copyin clause is redundant and could be removed or replaced with copyin='[eqn_idx, momxb]'.

@sbryngelson sbryngelson changed the title refactor: replace implicit BC/equation-index globals with derived types refactor: unify equation/range indices into sys_idx; clean BC globals Apr 10, 2026
…ences

In m_rhs.fpp, replace 'sys_size - 1' with 'eqn_idx%c - 1' when
surface_tension is active and remove the comment noting the fragile
assumption (eqn_idx%c makes the intent explicit).

In m_start_up.fpp, remove misleading '! eqn_idx%adv%end' comments on
restart loops that correctly iterate over all sys_size variables.
@sbryngelson sbryngelson marked this pull request as ready for review April 10, 2026 01:03
@qodo-code-review
Copy link
Copy Markdown
Contributor

qodo-code-review bot commented Apr 10, 2026

Code Review by Qodo

🐞 Bugs (6)   📘 Rule violations (10)   📎 Requirement gaps (0)   🎨 UX Issues (0)
🐞\ ☼ Reliability (5) ⚙ Maintainability (1)
📘\ ☼ Reliability (9) ⚙ Maintainability (1)

Grey Divider


Action required

1. qbmm_idx allocations not freed 📘
Description
qbmm_idx%rs/vs/ps/ms (and sometimes qbmm_idx%moms) are allocated via @:ALLOCATE but are never
deallocated in s_finalize_global_parameters_module, risking memory leaks and non-deterministic
resource cleanup. This violates the required @:ALLOCATE/@:DEALLOCATE pairing policy.
Code

src/simulation/m_global_parameters.fpp[R922-929]

+                    @:ALLOCATE(qbmm_idx%rs(nb), qbmm_idx%vs(nb))
+                    @:ALLOCATE(qbmm_idx%ps(nb), qbmm_idx%ms(nb))
                gam = bub_pp%gam_g
                if (qbmm) then
-                        @:ALLOCATE(bub_idx%moms(nb, nmom))
+                        @:ALLOCATE(qbmm_idx%moms(nb, nmom))
                    do i = 1, nb
Evidence
PR Compliance ID 8 requires every @:ALLOCATE(...) to have a matching @:DEALLOCATE(...). The PR
allocates several qbmm_idx allocatables, but s_finalize_global_parameters_module does not
deallocate any qbmm_idx members.

CLAUDE.md
src/simulation/m_global_parameters.fpp[922-929]
src/simulation/m_global_parameters.fpp[995-996]
src/simulation/m_global_parameters.fpp[1299-1340]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`qbmm_idx` members are allocated with `@:ALLOCATE` in `s_initialize_global_parameters_module` but are never freed in `s_finalize_global_parameters_module`.
## Issue Context
This PR replaced `bub_idx` allocatables with `qbmm_idx` allocatables; the finalization path must be updated to deallocate the new allocations (including `qbmm_idx%moms` when `qbmm` is enabled).
## Fix Focus Areas
- src/simulation/m_global_parameters.fpp[922-929]
- src/simulation/m_global_parameters.fpp[995-996]
- src/simulation/m_global_parameters.fpp[1299-1340]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. BC beg/end missing on GPU🐞
Description
OpenACC device code in m_cbc now branches on bc_x/bc_y/bc_z%beg/%end, but those members are not
included in the OpenACC GPU_DECLARE list and are never GPU_UPDATE’d, so kernels can read undefined
values and apply incorrect characteristic boundary conditions.
Code

src/simulation/m_cbc.fpp[R727-736]

+                        if ((cbc_loc == -1 .and. bc_${XYZ}$%beg == BC_CHAR_SLIP_WALL) &
+                            & .or. (cbc_loc == 1 .and. bc_${XYZ}$%end == BC_CHAR_SLIP_WALL)) then
                        call s_compute_slip_wall_L(lambda, L, rho, c, dpres_ds, dvel_ds)
-                        else if ((cbc_loc == -1 .and. bc${XYZ}$b == BC_CHAR_NR_SUB_BUFFER) &
-                                 & .or. (cbc_loc == 1 .and. bc${XYZ}$e == BC_CHAR_NR_SUB_BUFFER)) then
+                        else if ((cbc_loc == -1 .and. bc_${XYZ}$%beg == BC_CHAR_NR_SUB_BUFFER) &
+                                 & .or. (cbc_loc == 1 .and. bc_${XYZ}$%end == BC_CHAR_NR_SUB_BUFFER)) then
                        call s_compute_nonreflecting_subsonic_buffer_L(lambda, L, rho, c, mf, dalpha_rho_ds, dpres_ds, &
                            & dvel_ds, dadv_ds, dYs_ds)
-                        else if ((cbc_loc == -1 .and. bc${XYZ}$b == BC_CHAR_NR_SUB_INFLOW) &
-                                 & .or. (cbc_loc == 1 .and. bc${XYZ}$e == BC_CHAR_NR_SUB_INFLOW)) then
+                        else if ((cbc_loc == -1 .and. bc_${XYZ}$%beg == BC_CHAR_NR_SUB_INFLOW) &
+                                 & .or. (cbc_loc == 1 .and. bc_${XYZ}$%end == BC_CHAR_NR_SUB_INFLOW)) then
                        call s_compute_nonreflecting_subsonic_inflow_L(lambda, L, rho, c, dpres_ds, dvel_ds)
Evidence
m_cbc uses bc_${XYZ}$%beg/%end inside GPU loops to select the BC formulation, but simulation global
parameters only declare vb*/ve* components of bc_x/bc_y/bc_z for OpenACC (not beg/end), and GPU
initialization only updates vb*/ve* and grcbc flags to the device. Therefore, bc_*%beg/%end are not
device-resident/synchronized when referenced in device code.

src/simulation/m_cbc.fpp[725-786]
src/simulation/m_global_parameters.fpp[211-223]
src/simulation/m_start_up.fpp[1035-1061]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
CBC OpenACC kernels now read `bc_x%beg/%end` (and y/z) on-device, but these fields are not part of the OpenACC `GPU_DECLARE` set and are not copied to the device during GPU initialization. This can make boundary-condition selection nondeterministic/wrong in GPU runs.
### Issue Context
- `m_cbc` uses `bc_${XYZ}$%beg/%end` inside device loops to choose the CBC formulation.
- Under OpenACC, `m_global_parameters` only declares `bc_*%vb*`/`%ve*` on the device.
- `s_initialize_gpu_vars` updates `bc_*%vb*`/`%ve*` and `bc_*%grcbc_*` but not `bc_*%beg/%end`.
### Fix Focus Areas
- src/simulation/m_global_parameters.fpp[211-223]
- src/simulation/m_start_up.fpp[1035-1061]
- src/simulation/m_cbc.fpp[725-786]
### Expected fix
- Add `bc_x%beg, bc_x%end, bc_y%beg, bc_y%end, bc_z%beg, bc_z%end` to the OpenACC `GPU_DECLARE(create=...)` list (or declare the full `bc_x/bc_y/bc_z` structs for OpenACC).
- Add a matching `GPU_UPDATE(device='[...]')` for those beg/end members in `s_initialize_gpu_vars` after they are finalized on the host.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. qbmm_idx allocations not deallocated 📘
Description
qbmm_idx allocatables are allocated via @:ALLOCATE(...) but there is no corresponding
@:DEALLOCATE(...) for these members, which breaks the project’s required allocation/deallocation
pairing and risks leaks across repeated init/finalize cycles. Add matching deallocations in the
module finalization path (and any early-return/error paths if applicable).
Code

src/simulation/m_global_parameters.fpp[R922-928]

+                    @:ALLOCATE(qbmm_idx%rs(nb), qbmm_idx%vs(nb))
+                    @:ALLOCATE(qbmm_idx%ps(nb), qbmm_idx%ms(nb))
                gam = bub_pp%gam_g
                if (qbmm) then
-                        @:ALLOCATE(bub_idx%moms(nb, nmom))
+                        @:ALLOCATE(qbmm_idx%moms(nb, nmom))
Evidence
PR Compliance ID 8 requires every @:ALLOCATE(...) to have a matching @:DEALLOCATE(...). The PR
introduces @:ALLOCATE calls for qbmm_idx%rs/vs/ps/ms/moms but no @:DEALLOCATE for these
members exists in the codebase finalization path.

CLAUDE.md
src/simulation/m_global_parameters.fpp[922-928]
src/simulation/m_global_parameters.fpp[995-996]
src/simulation/m_global_parameters.fpp[1299-1340]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`qbmm_idx` allocatable members are allocated with `@:ALLOCATE(...)` but are never freed with `@:DEALLOCATE(...)`, violating the required pairing and risking leaks when initialization/finalization occurs more than once.
## Issue Context
Allocations occur in `s_initialize_global_parameters_module` (or equivalent init logic) for `qbmm_idx%rs`, `qbmm_idx%vs`, `qbmm_idx%ps`, `qbmm_idx%ms`, and (when `qbmm`) `qbmm_idx%moms`. The module already has a `s_finalize_global_parameters_module` where other `@:DEALLOCATE(...)` calls are performed, but it does not currently deallocate `qbmm_idx` members.
## Fix Focus Areas
- src/simulation/m_global_parameters.fpp[922-952]
- src/simulation/m_global_parameters.fpp[995-1012]
- src/simulation/m_global_parameters.fpp[1299-1340]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (18)
4. CBC BC codes missing🐞
Description
In OpenACC builds, m_cbc selects CBC boundary logic using bc_x/y/z%beg/%end inside GPU kernels, but
those fields are not declared/updated on device after the refactor removed the mirrored bcxb/bcxe
scalars. This can lead to wrong boundary-condition branch selection (undefined values on device) and
incorrect/unstable CBC behavior on GPU runs.
Code

src/simulation/m_cbc.fpp[R69-75]

$:GPU_DECLARE(create='[is1, is2, is3]')
integer :: dj
-    integer :: bcxb, bcxe, bcyb, bcye, bczb, bcze
integer :: cbc_dir, cbc_loc
integer :: flux_cbc_index
-    $:GPU_DECLARE(create='[dj, bcxb, bcxe, bcyb, bcye, bczb, bcze]')
+    $:GPU_DECLARE(create='[dj]')
$:GPU_DECLARE(create='[cbc_dir, cbc_loc, flux_cbc_index]')
Evidence
CBC kernel code branches on bc_*%beg/%end and grcbc_* inside an OpenACC parallel loop, requiring
those members to be present on device. However, the OpenACC declare/update path only manages
bc_*%vb*/%ve* and grcbc flags, not beg/end, and the PR removed the dedicated device-updated
bcxb/bcxe scalars that previously carried those values.

src/simulation/m_cbc.fpp[598-787]
src/simulation/m_global_parameters.fpp[211-223]
src/simulation/m_start_up.fpp[1054-1061]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
OpenACC device data management does not include `bc_x%beg`, `bc_x%end` (and same for y/z), but `m_cbc` reads these inside GPU kernels after the refactor removed the mirrored `bcxb/bcxe/...` scalars.
### Issue Context
- `m_cbc` branches on `bc_${XYZ}$%beg/%end` and uses `bc_${XYZ}$%grcbc_*` inside `$:GPU_PARALLEL_LOOP`.
- `m_global_parameters` OpenACC declarations only create `bc_*%vb*`/`bc_*%ve*` (and startup updates those plus `grcbc_*`), leaving `%beg/%end` undefined on device.
### Fix Focus Areas
- src/simulation/m_global_parameters.fpp[211-223]
- src/simulation/m_start_up.fpp[1054-1061]
- src/simulation/m_cbc.fpp[598-787]
### What to change
1. In the OpenACC branch of `m_global_parameters`, add `bc_x%beg, bc_x%end` (and y/z) to `GPU_DECLARE(create=...)` (or declare `bc_x, bc_y, bc_z` fully if supported).
2. In `s_initialize_gpu_vars` (or wherever BC GPU updates are centralized), add `GPU_UPDATE(device='[bc_x%beg, bc_x%end]')` (and y/z) after those values are finalized.
3. Keep existing updates for `grcbc_*` flags; ensure beg/end updates occur before any CBC kernels run.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Uninitialized eqn_idx fields read 🐞
Description
eqn_idx sub-fields like stress/xi/B/species are only assigned under feature flags, but multiple
targets read them unconditionally (e.g., copying to strxb/xibeg or writing indices.dat ranges). When
a feature is disabled, this is a read of undefined values and can produce incorrect indices.dat
output or propagate garbage indices into downstream logic.
Code

src/simulation/m_global_parameters.fpp[R1187-1202]

+        momxb = eqn_idx%mom%beg
+        momxe = eqn_idx%mom%end
+        advxb = eqn_idx%adv%beg
+        advxe = eqn_idx%adv%end
+        contxb = eqn_idx%cont%beg
+        contxe = eqn_idx%cont%end
+        bubxb = eqn_idx%bub%beg
+        bubxe = eqn_idx%bub%end
+        strxb = eqn_idx%stress%beg
+        strxe = eqn_idx%stress%end
+        intxb = eqn_idx%int_en%beg
+        intxe = eqn_idx%int_en%end
+        xibeg = eqn_idx%xi%beg
+        xiend = eqn_idx%xi%end
+        chemxb = eqn_idx%species%beg
+        chemxe = eqn_idx%species%end
Evidence
Both simulation and pre_process compute optional ranges (e.g., eqn_idx%stress%beg/end) only inside
if (hypoelasticity .or. hyperelasticity) / if (hyperelasticity) blocks, but later
unconditionally read these fields into global index scalars (strxb/strxe/xibeg/xiend) and
unconditionally pass them to write_range when generating indices.dat. This means configurations
with those features off will still read undefined derived-type members.

src/simulation/m_global_parameters.fpp[1050-1105]
src/simulation/m_global_parameters.fpp[1187-1206]
src/pre_process/m_global_parameters.fpp[730-806]
src/pre_process/m_data_output.fpp[641-652]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Several `eqn_idx` members (e.g., `stress`, `xi`, `B`, `int_en`, `species`, and scalars like `c`, `damage`, `psi`) are conditionally assigned, but are read unconditionally later (copied into `strxb/strxe/...` and written to `indices.dat`). This reads undefined values when the related feature is disabled.
### Issue Context
- In `m_global_parameters` (simulation/pre_process/post_process), optional ranges are only set in feature-gated blocks.
- Later code unconditionally does `strxb = eqn_idx%stress%beg` etc.
- `m_data_output` (pre_process) unconditionally calls `write_range(eqn_idx%stress%beg, ...)`, `write_range(eqn_idx%xi%beg, ...)`, etc.
### Fix Focus Areas
- src/simulation/m_global_parameters.fpp[1050-1105]
- src/simulation/m_global_parameters.fpp[1187-1206]
- src/pre_process/m_global_parameters.fpp[730-806]
- src/pre_process/m_data_output.fpp[641-652]
### What to change
1. At the start of the equation-index construction routine in each target’s `m_global_parameters`, explicitly initialize all `eqn_idx` members to a known inactive state:
- Set every `int_bounds_info` range’s `%beg`/`%end` to `0`.
- Set scalar indices like `E`, `n`, `gamma`, `pi_inf`, `c`, `damage`, `psi` to `0` (or the established sentinel if the codebase uses one consistently).
2. Only then compute/overwrite the active indices under feature flags.
3. Optionally encapsulate this in a small helper like `call s_reset_eqn_idx(eqn_idx)` to avoid duplicated initialization across targets.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. qbmm_idx allocations not freed 📘
Description
qbmm_idx%rs/vs/ps/ms (and sometimes qbmm_idx%moms) are allocated via @:ALLOCATE but are never
deallocated in s_finalize_global_parameters_module, risking memory leaks and non-deterministic
resource cleanup. This violates the required @:ALLOCATE/@:DEALLOCATE pairing policy.
Code

src/simulation/m_global_parameters.fpp[R922-929]

+                    @:ALLOCATE(qbmm_idx%rs(nb), qbmm_idx%vs(nb))
+                    @:ALLOCATE(qbmm_idx%ps(nb), qbmm_idx%ms(nb))
               gam = bub_pp%gam_g
               if (qbmm) then
-                        @:ALLOCATE(bub_idx%moms(nb, nmom))
+                        @:ALLOCATE(qbmm_idx%moms(nb, nmom))
                   do i = 1, nb
Evidence
PR Compliance ID 8 requires every @:ALLOCATE(...) to have a matching @:DEALLOCATE(...). The PR
allocates several qbmm_idx allocatables, but s_finalize_global_parameters_module does not
deallocate any qbmm_idx members.

CLAUDE.md
src/simulation/m_global_parameters.fpp[922-929]
src/simulation/m_global_parameters.fpp[995-996]
src/simulation/m_global_parameters.fpp[1299-1340]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`qbmm_idx` members are allocated with `@:ALLOCATE` in `s_initialize_global_parameters_module` but are never freed in `s_finalize_global_parameters_module`.
## Issue Context
This PR replaced `bub_idx` allocatables with `qbmm_idx` allocatables; the finalization path must be updated to deallocate the new allocations (including `qbmm_idx%moms` when `qbmm` is enabled).
## Fix Focus Areas
- src/simulation/m_global_parameters.fpp[922-929]
- src/simulation/m_global_parameters.fpp[995-996]
- src/simulation/m_global_parameters.fpp[1299-1340]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


7. BC beg/end missing on GPU🐞
Description
OpenACC device code in m_cbc now branches on bc_x/bc_y/bc_z%beg/%end, but those members are not
included in the OpenACC GPU_DECLARE list and are never GPU_UPDATE’d, so kernels can read undefined
values and apply incorrect characteristic boundary conditions.
Code

src/simulation/m_cbc.fpp[R727-736]

+                        if ((cbc_loc == -1 .and. bc_${XYZ}$%beg == BC_CHAR_SLIP_WALL) &
+                            & .or. (cbc_loc == 1 .and. bc_${XYZ}$%end == BC_CHAR_SLIP_WALL)) then
                       call s_compute_slip_wall_L(lambda, L, rho, c, dpres_ds, dvel_ds)
-                        else if ((cbc_loc == -1 .and. bc${XYZ}$b == BC_CHAR_NR_SUB_BUFFER) &
-                                 & .or. (cbc_loc == 1 .and. bc${XYZ}$e == BC_CHAR_NR_SUB_BUFFER)) then
+                        else if ((cbc_loc == -1 .and. bc_${XYZ}$%beg == BC_CHAR_NR_SUB_BUFFER) &
+                                 & .or. (cbc_loc == 1 .and. bc_${XYZ}$%end == BC_CHAR_NR_SUB_BUFFER)) then
                       call s_compute_nonreflecting_subsonic_buffer_L(lambda, L, rho, c, mf, dalpha_rho_ds, dpres_ds, &
                           & dvel_ds, dadv_ds, dYs_ds)
-                        else if ((cbc_loc == -1 .and. bc${XYZ}$b == BC_CHAR_NR_SUB_INFLOW) &
-                                 & .or. (cbc_loc == 1 .and. bc${XYZ}$e == BC_CHAR_NR_SUB_INFLOW)) then
+                        else if ((cbc_loc == -1 .and. bc_${XYZ}$%beg == BC_CHAR_NR_SUB_INFLOW) &
+                                 & .or. (cbc_loc == 1 .and. bc_${XYZ}$%end == BC_CHAR_NR_SUB_INFLOW)) then
                       call s_compute_nonreflecting_subsonic_inflow_L(lambda, L, rho, c, dpres_ds, dvel_ds)
Evidence
m_cbc uses bc_${XYZ}$%beg/%end inside GPU loops to select the BC formulation, but simulation global
parameters only declare vb*/ve* components of bc_x/bc_y/bc_z for OpenACC (not beg/end), and GPU
initialization only updates vb*/ve* and grcbc flags to the device. Therefore, bc_*%beg/%end are not
device-resident/synchronized when referenced in device code.

src/simulation/m_cbc.fpp[725-786]
src/simulation/m_global_parameters.fpp[211-223]
src/simulation/m_start_up.fpp[1035-1061]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
CBC OpenACC kernels now read `bc_x%beg/%end` (and y/z) on-device, but these fields are not part of the OpenACC `GPU_DECLARE` set and are not copied to the device during GPU initialization. This can make boundary-condition selection nondeterministic/wrong in GPU runs.
### Issue Context
- `m_cbc` uses `bc_${XYZ}$%beg/%end` inside device loops to choose the CBC formulation.
- Under OpenACC, `m_global_parameters` only declares `bc_*%vb*`/`%ve*` on the device.
- `s_initialize_gpu_vars` updates `bc_*%vb*`/`%ve*` and `bc_*%grcbc_*` but not `bc_*%beg/%end`.
### Fix Focus Areas
- src/simulation/m_global_parameters.fpp[211-223]
- src/simulation/m_start_up.fpp[1035-1061]
- src/simulation/m_cbc.fpp[725-786]
### Expected fix
- Add `bc_x%beg, bc_x%end, bc_y%beg, bc_y%end, bc_z%beg, bc_z%end` to the OpenACC `GPU_DECLARE(create=...)` list (or declare the full `bc_x/bc_y/bc_z` structs for OpenACC).
- Add a matching `GPU_UPDATE(device='[...]')` for those beg/end members in `s_initialize_gpu_vars` after they are finalized on the host.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


8. qbmm_idx allocations not deallocated 📘
Description
qbmm_idx allocatables are allocated via @:ALLOCATE(...) but there is no corresponding
@:DEALLOCATE(...) for these members, which breaks the project’s required allocation/deallocation
pairing and risks leaks across repeated init/finalize cycles. Add matching deallocations in the
module finalization path (and any early-return/error paths if applicable).
Code

src/simulation/m_global_parameters.fpp[R922-928]

+                    @:ALLOCATE(qbmm_idx%rs(nb), qbmm_idx%vs(nb))
+                    @:ALLOCATE(qbmm_idx%ps(nb), qbmm_idx%ms(nb))
                 gam = bub_pp%gam_g
                 if (qbmm) then
-                        @:ALLOCATE(bub_idx%moms(nb, nmom))
+                        @:ALLOCATE(qbmm_idx%moms(nb, nmom))
Evidence
PR Compliance ID 8 requires every @:ALLOCATE(...) to have a matching @:DEALLOCATE(...). The PR
introduces @:ALLOCATE calls for qbmm_idx%rs/vs/ps/ms/moms but no @:DEALLOCATE for these
members exists in the codebase finalization path.

CLAUDE.md
src/simulation/m_global_parameters.fpp[922-928]
src/simulation/m_global_parameters.fpp[995-996]
src/simulation/m_global_parameters.fpp[1299-1340]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`qbmm_idx` allocatable members are allocated with `@:ALLOCATE(...)` but are never freed with `@:DEALLOCATE(...)`, violating the required pairing and risking leaks when initialization/finalization occurs more than once.
## Issue Context
Allocations occur in `s_initialize_global_parameters_module` (or equivalent init logic) for `qbmm_idx%rs`, `qbmm_idx%vs`, `qbmm_idx%ps`, `qbmm_idx%ms`, and (when `qbmm`) `qbmm_idx%moms`. The module already has a `s_finalize_global_parameters_module` where other `@:DEALLOCATE(...)` calls are performed, but it does not currently deallocate `qbmm_idx` members.
## Fix Focus Areas
- src/simulation/m_global_parameters.fpp[922-952]
- src/simulation/m_global_parameters.fpp[995-1012]
- src/simulation/m_global_parameters.fpp[1299-1340]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


9. CBC BC codes missing🐞
Description
In OpenACC builds, m_cbc selects CBC boundary logic using bc_x/y/z%beg/%end inside GPU kernels, but
those fields are not declared/updated on device after the refactor removed the mirrored bcxb/bcxe
scalars. This can lead to wrong boundary-condition branch selection (undefined values on device) and
incorrect/unstable CBC behavior on GPU runs.
Code

src/simulation/m_cbc.fpp[R69-75]

 $:GPU_DECLARE(create='[is1, is2, is3]')
 integer :: dj
-    integer :: bcxb, bcxe, bcyb, bcye, bczb, bcze
 integer :: cbc_dir, cbc_loc
 integer :: flux_cbc_index
-    $:GPU_DECLARE(create='[dj, bcxb, bcxe, bcyb, bcye, bczb, bcze]')
+    $:GPU_DECLARE(create='[dj]')
 $:GPU_DECLARE(create='[cbc_dir, cbc_loc, flux_cbc_index]')
Evidence
CBC kernel code branches on bc_*%beg/%end and grcbc_* inside an OpenACC parallel loop, requiring
those members to be present on device. However, the OpenACC declare/update path only manages
bc_*%vb*/%ve* and grcbc flags, not beg/end, and the PR removed the dedicated device-updated
bcxb/bcxe scalars that previously carried those values.

src/simulation/m_cbc.fpp[598-787]
src/simulation/m_global_parameters.fpp[211-223]
src/simulation/m_start_up.fpp[1054-1061]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
OpenACC device data management does not include `bc_x%beg`, `bc_x%end` (and same for y/z), but `m_cbc` reads these inside GPU kernels after the refactor removed the mirrored `bcxb/bcxe/...` scalars.
### Issue Context
- `m_cbc` branches on `bc_${XYZ}$%beg/%end` and uses `bc_${XYZ}$%grcbc_*` inside `$:GPU_PARALLEL_LOOP`.
- `m_global_parameters` OpenACC declarations only create `bc_*%vb*`/`bc_*%ve*` (and startup updates those plus `grcbc_*`), leaving `%beg/%end` undefined on device.
### Fix Focus Areas
- src/simulation/m_global_parameters.fpp[211-223]
- src/simulation/m_start_up.fpp[1054-1061]
- src/simulation/m_cbc.fpp[598-787]
### What to change
1. In the OpenACC branch of `m_global_parameters`, add `bc_x%beg, bc_x%end` (and y/z) to `GPU_DECLARE(create=...)` (or declare `bc_x, bc_y, bc_z` fully if supported).
2. In `s_initialize_gpu_vars` (or wherever BC GPU updates are centralized), add `GPU_UPDATE(device='[bc_x%beg, bc_x%end]')` (and y/z) after those values are finalized.
3. Keep existing updates for `grcbc_*` flags; ensure beg/end updates occur before any CBC kernels run.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


10. Uninitialized eqn_idx fields read 🐞
Description
eqn_idx sub-fields like stress/xi/B/species are only assigned under feature flags, but multiple
targets read them unconditionally (e.g., copying to strxb/xibeg or writing indices.dat ranges). When
a feature is disabled, this is a read of undefined values and can produce incorrect indices.dat
output or propagate garbage indices into downstream logic.
Code

src/simulation/m_global_parameters.fpp[R1187-1202]

+        momxb = eqn_idx%mom%beg
+        momxe = eqn_idx%mom%end
+        advxb = eqn_idx%adv%beg
+        advxe = eqn_idx%adv%end
+        contxb = eqn_idx%cont%beg
+        contxe = eqn_idx%cont%end
+        bubxb = eqn_idx%bub%beg
+        bubxe = eqn_idx%bub%end
+        strxb = eqn_idx%stress%beg
+        strxe = eqn_idx%stress%end
+        intxb = eqn_idx%int_en%beg
+        intxe = eqn_idx%int_en%end
+        xibeg = eqn_idx%xi%beg
+        xiend = eqn_idx%xi%end
+        chemxb = eqn_idx%species%beg
+        chemxe = eqn_idx%species%end
Evidence
Both simulation and pre_process compute optional ranges (e.g., eqn_idx%stress%beg/end) only inside
if (hypoelasticity .or. hyperelasticity) / if (hyperelasticity) blocks, but later
unconditionally read these fields into global index scalars (strxb/strxe/xibeg/xiend) and
unconditionally pass them to write_range when generating indices.dat. This means configurations
with those features off will still read undefined derived-type members.

src/simulation/m_global_parameters.fpp[1050-1105]
src/simulation/m_global_parameters.fpp[1187-1206]
src/pre_process/m_global_parameters.fpp[730-806]
src/pre_process/m_data_output.fpp[641-652]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Several `eqn_idx` members (e.g., `stress`, `xi`, `B`, `int_en`, `species`, and scalars like `c`, `damage`, `psi`) are conditionally assigned, but are read unconditionally later (copied into `strxb/strxe/...` and written to `indices.dat`). This reads undefined values when the related feature is disabled.
### Issue Context
- In `m_global_parameters` (simulation/pre_process/post_process), optional ranges are only set in feature-gated blocks.
- Later code unconditionally does `strxb = eqn_idx%stress%beg` etc.
- `m_data_output` (pre_process) unconditionally calls `write_range(eqn_idx%stress%beg, ...)`, `write_range(eqn_idx%xi%beg, ...)`, etc.
### Fix Focus Areas
- src/simulation/m_global_parameters.fpp[1050-1105]
- src/simulation/m_global_parameters.fpp[1187-1206]
- src/pre_process/m_global_parameters.fpp[730-806]
- src/pre_process/m_data_output.fpp[641-652]
### What to change
1. At the start of the equation-index construction routine in each target’s `m_global_parameters`, explicitly initialize all `eqn_idx` members to a known inactive state:
- Set every `int_bounds_info` range’s `%beg`/`%end` to `0`.
- Set scalar indices like `E`, `n`, `gamma`, `pi_inf`, `c`, `damage`, `psi` to `0` (or the established sentinel if the codebase uses one consistently).
2. Only then compute/overwrite the active indices under feature flags.
3. Optionally encapsulate this in a small helper like `call s_reset_eqn_idx(eqn_idx)` to avoid duplicated initialization across targets.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


11. qbmm_idx allocations not freed 📘
Description
qbmm_idx%rs/vs/ps/ms (and sometimes qbmm_idx%moms) are allocated via @:ALLOCATE but are never
deallocated in s_finalize_global_parameters_module, risking memory leaks and non-deterministic
resource cleanup. This violates the required @:ALLOCATE/@:DEALLOCATE pairing policy.
Code

src/simulation/m_global_parameters.fpp[R922-929]

+                    @:ALLOCATE(qbmm_idx%rs(nb), qbmm_idx%vs(nb))
+                    @:ALLOCATE(qbmm_idx%ps(nb), qbmm_idx%ms(nb))
                gam = bub_pp%gam_g
                if (qbmm) then
-                        @:ALLOCATE(bub_idx%moms(nb, nmom))
+                        @:ALLOCATE(qbmm_idx%moms(nb, nmom))
                    do i = 1, nb
Evidence
PR Compliance ID 8 requires every @:ALLOCATE(...) to have a matching @:DEALLOCATE(...). The PR
allocates several qbmm_idx allocatables, but s_finalize_global_parameters_module does not
deallocate any qbmm_idx members.

CLAUDE.md
src/simulation/m_global_parameters.fpp[922-929]
src/simulation/m_global_parameters.fpp[995-996]
src/simulation/m_global_parameters.fpp[1299-1340]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`qbmm_idx` members are allocated with `@:ALLOCATE` in `s_initialize_global_parameters_module` but are never freed in `s_finalize_global_parameters_module`.
## Issue Context
This PR replaced `bub_idx` allocatables with `qbmm_idx` allocatables; the finalization path must be updated to deallocate the new allocations (including `qbmm_idx%moms` when `qbmm` is enabled).
## Fix Focus Areas
- src/simulation/m_global_parameters.fpp[922-929]
- src/simulation/m_global_parameters.fpp[995-996]
- src/simulation/m_global_parameters.fpp[1299-1340]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


12. BC beg/end missing on GPU🐞
Description
OpenACC device code in m_cbc now branches on bc_x/bc_y/bc_z%beg/%end, but those members are not
included in the OpenACC GPU_DECLARE list and are never GPU_UPDATE’d, so kernels can read undefined
values and apply incorrect characteristic boundary conditions.
Code

src/simulation/m_cbc.fpp[R727-736]

+                        if ((cbc_loc == -1 .and. bc_${XYZ}$%beg == BC_CHAR_SLIP_WALL) &
+                            & .or. (cbc_loc == 1 .and. bc_${XYZ}$%end == BC_CHAR_SLIP_WALL)) then
                        call s_compute_slip_wall_L(lambda, L, rho, c, dpres_ds, dvel_ds)
-                        else if ((cbc_loc == -1 .and. bc${XYZ}$b == BC_CHAR_NR_SUB_BUFFER) &
-                                 & .or. (cbc_loc == 1 .and. bc${XYZ}$e == BC_CHAR_NR_SUB_BUFFER)) then
+                        else if ((cbc_loc == -1 .and. bc_${XYZ}$%beg == BC_CHAR_NR_SUB_BUFFER) &
+                                 & .or. (cbc_loc == 1 .and. bc_${XYZ}$%end == BC_CHAR_NR_SUB_BUFFER)) then
                        call s_compute_nonreflecting_subsonic_buffer_L(lambda, L, rho, c, mf, dalpha_rho_ds, dpres_ds, &
                            & dvel_ds, dadv_ds, dYs_ds)
-                        else if ((cbc_loc == -1 .and. bc${XYZ}$b == BC_CHAR_NR_SUB_INFLOW) &
-                                 & .or. (cbc_loc == 1 .and. bc${XYZ}$e == BC_CHAR_NR_SUB_INFLOW)) then
+                        else if ((cbc_loc == -1 .and. bc_${XYZ}$%beg == BC_CHAR_NR_SUB_INFLOW) &
+                                 & .or. (cbc_loc == 1 .and. bc_${XYZ}$%end == BC_CHAR_NR_SUB_INFLOW)) then
                        call s_compute_nonreflecting_subsonic_inflow_L(lambda, L, rho, c, dpres_ds, dvel_ds)
Evidence
m_cbc uses bc_${XYZ}$%beg/%end inside GPU loops to select the BC formulation, but simulation global
parameters only declare vb*/ve* components of bc_x/bc_y/bc_z for OpenACC (not beg/end), and GPU
initialization only updates vb*/ve* and grcbc flags to the device. Therefore, bc_*%beg/%end are not
device-resident/synchronized when referenced in device code.

src/simulation/m_cbc.fpp[725-786]
src/simulation/m_global_parameters.fpp[211-223]
src/simulation/m_start_up.fpp[1035-1061]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
CBC OpenACC kernels now read `bc_x%beg/%end` (and y/z) on-device, but these fields are not part of the OpenACC `GPU_DECLARE` set and are not copied to the device during GPU initialization. This can make boundary-condition selection nondeterministic/wrong in GPU runs.
### Issue Context
- `m_cbc` uses `bc_${XYZ}$%beg/%end` inside device loops to choose the CBC formulation.
- Under OpenACC, `m_global_parameters` only declares `bc_*%vb*`/`%ve*` on the device.
- `s_initialize_gpu_vars` updates `bc_*%vb*`/`%ve*` and `bc_*%grcbc_*` but not `bc_*%beg/%end`.
### Fix Focus Areas
- src/simulation/m_global_parameters.fpp[211-223]
- src/simulation/m_start_up.fpp[1035-1061]
- src/simulation/m_cbc.fpp[725-786]
### Expected fix
- Add `bc_x%beg, bc_x%end, bc_y%beg, bc_y%end, bc_z%beg, bc_z%end` to the OpenACC `GPU_DECLARE(create=...)` list (or declare the full `bc_x/bc_y/bc_z` structs for OpenACC).
- Add a matching `GPU_UPDATE(device='[...]')` for those beg/end members in `s_initialize_gpu_vars` after they are finalized on the host.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


13. qbmm_idx allocations not deallocated 📘
Description
qbmm_idx allocatables are allocated via @:ALLOCATE(...) but there is no corresponding
@:DEALLOCATE(...) for these members, which breaks the project’s required allocation/deallocation
pairing and risks leaks across repeated init/finalize cycles. Add matching deallocations in the
module finalization path (and any early-return/error paths if applicable).
Code

src/simulation/m_global_parameters.fpp[R922-928]

+                    @:ALLOCATE(qbmm_idx%rs(nb), qbmm_idx%vs(nb))
+                    @:ALLOCATE(qbmm_idx%ps(nb), qbmm_idx%ms(nb))
                  gam = bub_pp%gam_g
                  if (qbmm) then
-                        @:ALLOCATE(bub_idx%moms(nb, nmom))
+                        @:ALLOCATE(qbmm_idx%moms(nb, nmom))
Evidence
PR Compliance ID 8 requires every @:ALLOCATE(...) to have a matching @:DEALLOCATE(...). The PR
introduces @:ALLOCATE calls for qbmm_idx%rs/vs/ps/ms/moms but no @:DEALLOCATE for these
members exists in the codebase finalization path.

CLAUDE.md
src/simulation/m_global_parameters.fpp[922-928]
src/simulation/m_global_parameters.fpp[995-996]
src/simulation/m_global_parameters.fpp[1299-1340]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`qbmm_idx` allocatable members are allocated with `@:ALLOCATE(...)` but are never freed with `@:DEALLOCATE(...)`, violating the required pairing and risking leaks when initialization/finalization occurs more than once.
## Issue Context
Allocations occur in `s_initialize_global_parameters_module` (or equivalent init logic) for `qbmm_idx%rs`, `qbmm_idx%vs`, `qbmm_idx%ps`, `qbmm_idx%ms`, and (when `qbmm`) `qbmm_idx%moms`. The module already has a `s_finalize_global_parameters_module` where other `@:DEALLOCATE(...)` calls are performed, but it does not currently deallocate `qbmm_idx` members.
## Fix Focus Areas
- src/simulation/m_global_parameters.fpp[922-952]
- src/simulation/m_global_parameters.fpp[995-1012]
- src/simulation/m_global_parameters.fpp[1299-1340]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


14. CBC BC codes missing🐞
Description
In OpenACC builds, m_cbc selects CBC boundary logic using bc_x/y/z%beg/%end inside GPU kernels, but
those fields are not declared/updated on device after the refactor removed the mirrored bcxb/bcxe
scalars. This can lead to wrong boundary-condition branch selection (undefined values on device) and
incorrect/unstable CBC behavior on GPU runs.
Code

src/simulation/m_cbc.fpp[R69-75]

  $:GPU_DECLARE(create='[is1, is2, is3]')
  integer :: dj
-    integer :: bcxb, bcxe, bcyb, bcye, bczb, bcze
  integer :: cbc_dir, cbc_loc
  integer :: flux_cbc_index
-    $:GPU_DECLARE(create='[dj, bcxb, bcxe, bcyb, bcye, bczb, bcze]')
+    $:GPU_DECLARE(create='[dj]')
  $:GPU_DECLARE(create='[cbc_dir, cbc_loc, flux_cbc_index]')
Evidence
CBC kernel code branches on bc_*%beg/%end and grcbc_* inside an OpenACC parallel loop, requiring
those members to be present on device. However, the OpenACC declare/update path only manages
bc_*%vb*/%ve* and grcbc flags, not beg/end, and the PR removed the dedicated device-updated
bcxb/bcxe scalars that previously carried those values.

src/simulation/m_cbc.fpp[598-787]
src/simulation/m_global_parameters.fpp[211-223]
src/simulation/m_start_up.fpp[1054-1061]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
OpenACC device data management does not include `bc_x%beg`, `bc_x%end` (and same for y/z), but `m_cbc` reads these inside GPU kernels after the refactor removed the mirrored `bcxb/bcxe/...` scalars.
### Issue Context
- `m_cbc` branches on `bc_${XYZ}$%beg/%end` and uses `bc_${XYZ}$%grcbc_*` inside `$:GPU_PARALLEL_LOOP`.
- `m_global_parameters` OpenACC declarations only create `bc_*%vb*`/`bc_*%ve*` (and startup updates those plus `grcbc_*`), leaving `%beg/%end` undefined on device.
### Fix Focus Areas
- src/simulation/m_global_parameters.fpp[211-223]
- src/simulation/m_start_up.fpp[1054-1061]
- src/simulation/m_cbc.fpp[598-787]
### What to change
1. In the OpenACC branch of `m_global_parameters`, add `bc_x%beg, bc_x%end` (and y/z) to `GPU_DECLARE(create=...)` (or declare `bc_x, bc_y, bc_z` fully if supported).
2. In `s_initialize_gpu_vars` (or wherever BC GPU updates are centralized), add `GPU_UPDATE(device='[bc_x%beg, bc_x%end]')` (and y/z) after those values are finalized.
3. Keep existing updates for `grcbc_*` flags; ensure beg/end updates occur before any CBC kernels run.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


15. Uninitialized eqn_idx fields read 🐞
Description
eqn_idx sub-fields like stress/xi/B/species are only assigned under feature flags, but multiple
targets read them unconditionally (e.g., copying to strxb/xibeg or writing indices.dat ranges). When
a feature is disabled, this is a read of undefined values and can produce incorrect indices.dat
output or propagate garbage indices into downstream logic.
Code

src/simulation/m_global_parameters.fpp[R1187-1202]

+        momxb = eqn_idx%mom%beg
+        momxe = eqn_idx%mom%end
+        advxb = eqn_idx%adv%beg
+        advxe = eqn_idx%adv%end
+        contxb = eqn_idx%cont%beg
+        contxe = eqn_idx%cont%end
+        bubxb = eqn_idx%bub%beg
+        bubxe = eqn_idx%bub%end
+        strxb = eqn_idx%stress%beg
+        strxe = eqn_idx%stress%end
+        intxb = eqn_idx%int_en%beg
+        intxe = eqn_idx%int_en%end
+        xibeg = eqn_idx%xi%beg
+        xiend = eqn_idx%xi%end
+        chemxb = eqn_idx%species%beg
+        chemxe = eqn_idx%species%end
Evidence
Both simulation and pre_process compute optional ranges (e.g., eqn_idx%stress%beg/end) only inside
if (hypoelasticity .or. hyperelasticity) / if (hyperelasticity) blocks, but later
unconditionally read these fields into global index scalars (strxb/strxe/xibeg/xiend) and
unconditionally pass them to write_range when generating indices.dat. This means configurations
with those features off will still read undefined derived-type members.

src/simulation/m_global_parameters.fpp[1050-1105]
src/simulation/m_global_parameters.fpp[1187-1206]
src/pre_process/m_global_parameters.fpp[730-806]
src/pre_process/m_data_output.fpp[641-652]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Several `eqn_idx` members (e.g., `stress`, `xi`, `B`, `int_en`, `species`, and scalars like `c`, `damage`, `psi`) are conditionally assigned, but are read unconditionally later (copied into `strxb/strxe/...` and written to `indices.dat`). This reads undefined values when the related feature is disabled.
### Issue Context
- In `m_global_parameters` (simulation/pre_process/post_process), optional ranges are only set in feature-gated blocks.
- Later code unconditionally does `strxb = eqn_idx%stress%beg` etc.
- `m_data_output` (pre_process) unconditionally calls `write_range(eqn_idx%stress%beg, ...)`, `write_range(eqn_idx%xi%beg, ...)`, etc.
### Fix Focus Areas
- src/simulation/m_global_parameters.fpp[1050-1105]
- src/simulation/m_global_parameters.fpp[1187-1206]
- src/pre_process/m_global_parameters.fpp[730-806]
- src/pre_process/m_data_output.fpp[641-652]
### What to change
1. At the start of the equation-index construction routine in each target’s `m_global_parameters`, explicitly initialize all `eqn_idx` members to a known inactive state:
- Set every `int_bounds_info` range’s `%beg`/`%end` to `0`.
- Set scalar indices like `E`, `n`, `gamma`, `pi_inf`, `c`, `damage`, `psi` to `0` (or the established sentinel if the codebase uses one consistently).
2. Only then compute/overwrite the active indices under feature flags.
3. Optionally encapsulate this in a small helper like `call s_reset_eqn_idx(eqn_idx)` to avoid duplicated initialization across targets.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


16. qbmm_idx allocations not freed 📘
Description
qbmm_idx%rs/vs/ps/ms (and sometimes qbmm_idx%moms) are allocated via @:ALLOCATE but are never
deallocated in s_finalize_global_parameters_module, risking memory leaks and non-deterministic
resource cleanup. This violates the required @:ALLOCATE/@:DEALLOCATE pairing policy.
Code

src/simulation/m_global_parameters.fpp[R922-929]

+                    @:ALLOCATE(qbmm_idx%rs(nb), qbmm_idx%vs(nb))
+                    @:ALLOCATE(qbmm_idx%ps(nb), qbmm_idx%ms(nb))
                 gam = bub_pp%gam_g
                 if (qbmm) then
-                        @:ALLOCATE(bub_idx%moms(nb, nmom))
+                        @:ALLOCATE(qbmm_idx%moms(nb, nmom))
                     do i = 1, nb
Evidence
PR Compliance ID 8 requires every @:ALLOCATE(...) to have a matching @:DEALLOCATE(...). The PR
allocates several qbmm_idx allocatables, but s_finalize_global_parameters_module does not
deallocate any qbmm_idx members.

CLAUDE.md
src/simulation/m_global_parameters.fpp[922-929]
src/simulation/m_global_parameters.fpp[995-996]
src/simulation/m_global_parameters.fpp[1299-1340]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`qbmm_idx` members are allocated with `@:ALLOCATE` in `s_initialize_global_parameters_module` but are never freed in `s_finalize_global_parameters_module`.
## Issue Context
This PR replaced `bub_idx` allocatables with `qbmm_idx` allocatables; the finalization path must be updated to deallocate the new allocations (including `qbmm_idx%moms` when `qbmm` is enabled).
## Fix Focus Areas
- src/simulation/m_global_parameters.fpp[922-929]
- src/simulation/m_global_parameters.fpp[995-996]
- src/simulation/m_global_parameters.fpp[1299-1340]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


17. qbmm_idx allocations not deallocated 📘
Description
qbmm_idx allocatables are allocated via @:ALLOCATE(...) but there is no corresponding
@:DEALLOCATE(...) for these members, which breaks the project’s required allocation/deallocation
pairing and risks leaks across repeated init/finalize cycles. Add matching deallocations in the
module finalization path (and any early-return/error paths if applicable).
Code

src/simulation/m_global_parameters.fpp[R922-928]

+                    @:ALLOCATE(qbmm_idx%rs(nb), qbmm_idx%vs(nb))
+                    @:ALLOCATE(qbmm_idx%ps(nb), qbmm_idx%ms(nb))

                   gam = bub_pp%gam_g

                   if (qbmm) then
-                        @:ALLOCATE(bub_idx%moms(nb, nmom))
+                        @:ALLOCATE(qbmm_idx%moms(nb, nmom))
Evidence
PR Compliance ID 8 requires every @:ALLOCATE(...) to have a matching @:DEALLOCATE(...). The PR
introduces @:ALLOCATE calls for qbmm_idx%rs/vs/ps/ms/moms but no @:DEALLOCATE for these
members exists in the codebase finalization path.

CLAUDE.md
src/simulation/m_global_parameters.fpp[922-928]
src/simulation/m_global_parameters.fpp[995-996]
src/simulation/m_global_parameters.fpp[1299-1340]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`qbmm_idx` allocatable members are allocated with `@:ALLOCATE(...)` but are never freed with `@:DEALLOCATE(...)`, violating the required pairing and risking leaks when initialization/finalization occurs more than once.
## Issue Context
Allocations occur in `s_initialize_global_parameters_module` (or equivalent init logic) for `qbmm_idx%rs`, `qbmm_idx%vs`, `qbmm_idx%ps`, `qbmm_idx%ms`, and (when `qbmm`) `qbmm_idx%moms`. The module already has a `s_finalize_global_parameters_module` where other `@:DEALLOCATE(...)` calls are performed, but it does not currently deallocate `qbmm_idx` members.
## Fix Focus Areas
- src/simulation/m_global_parameters.fpp[922-952]
- src/simulation/m_global_parameters.fpp[995-1012]
- src/simulation/m_global_parameters.fpp[1299-1340]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


18. CBC BC codes missing🐞
Description
In OpenACC builds, m_cbc selects CBC boundary logic using bc_x/y/z%beg/%end inside GPU kernels, but
those fields are not declared/updated on device after the refactor removed the mirrored bcxb/bcxe
scalars. This can lead to wrong boundary-condition branch selection (undefined values on device) and
incorrect/unstable CBC behavior on GPU runs.
Code

...

Comment on lines +922 to 929
@:ALLOCATE(qbmm_idx%rs(nb), qbmm_idx%vs(nb))
@:ALLOCATE(qbmm_idx%ps(nb), qbmm_idx%ms(nb))

gam = bub_pp%gam_g

if (qbmm) then
@:ALLOCATE(bub_idx%moms(nb, nmom))
@:ALLOCATE(qbmm_idx%moms(nb, nmom))
do i = 1, nb
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. qbmm_idx allocations not freed 📘 Rule violation ☼ Reliability

qbmm_idx%rs/vs/ps/ms (and sometimes qbmm_idx%moms) are allocated via @:ALLOCATE but are never
deallocated in s_finalize_global_parameters_module, risking memory leaks and non-deterministic
resource cleanup. This violates the required @:ALLOCATE/@:DEALLOCATE pairing policy.
Agent Prompt
## Issue description
`qbmm_idx` members are allocated with `@:ALLOCATE` in `s_initialize_global_parameters_module` but are never freed in `s_finalize_global_parameters_module`.

## Issue Context
This PR replaced `bub_idx` allocatables with `qbmm_idx` allocatables; the finalization path must be updated to deallocate the new allocations (including `qbmm_idx%moms` when `qbmm` is enabled).

## Fix Focus Areas
- src/simulation/m_global_parameters.fpp[922-929]
- src/simulation/m_global_parameters.fpp[995-996]
- src/simulation/m_global_parameters.fpp[1299-1340]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +727 to 736
if ((cbc_loc == -1 .and. bc_${XYZ}$%beg == BC_CHAR_SLIP_WALL) &
& .or. (cbc_loc == 1 .and. bc_${XYZ}$%end == BC_CHAR_SLIP_WALL)) then
call s_compute_slip_wall_L(lambda, L, rho, c, dpres_ds, dvel_ds)
else if ((cbc_loc == -1 .and. bc${XYZ}$b == BC_CHAR_NR_SUB_BUFFER) &
& .or. (cbc_loc == 1 .and. bc${XYZ}$e == BC_CHAR_NR_SUB_BUFFER)) then
else if ((cbc_loc == -1 .and. bc_${XYZ}$%beg == BC_CHAR_NR_SUB_BUFFER) &
& .or. (cbc_loc == 1 .and. bc_${XYZ}$%end == BC_CHAR_NR_SUB_BUFFER)) then
call s_compute_nonreflecting_subsonic_buffer_L(lambda, L, rho, c, mf, dalpha_rho_ds, dpres_ds, &
& dvel_ds, dadv_ds, dYs_ds)
else if ((cbc_loc == -1 .and. bc${XYZ}$b == BC_CHAR_NR_SUB_INFLOW) &
& .or. (cbc_loc == 1 .and. bc${XYZ}$e == BC_CHAR_NR_SUB_INFLOW)) then
else if ((cbc_loc == -1 .and. bc_${XYZ}$%beg == BC_CHAR_NR_SUB_INFLOW) &
& .or. (cbc_loc == 1 .and. bc_${XYZ}$%end == BC_CHAR_NR_SUB_INFLOW)) then
call s_compute_nonreflecting_subsonic_inflow_L(lambda, L, rho, c, dpres_ds, dvel_ds)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. Bc beg/end missing on gpu 🐞 Bug ≡ Correctness

OpenACC device code in m_cbc now branches on bc_x/bc_y/bc_z%beg/%end, but those members are not
included in the OpenACC GPU_DECLARE list and are never GPU_UPDATE’d, so kernels can read undefined
values and apply incorrect characteristic boundary conditions.
Agent Prompt
### Issue description
CBC OpenACC kernels now read `bc_x%beg/%end` (and y/z) on-device, but these fields are not part of the OpenACC `GPU_DECLARE` set and are not copied to the device during GPU initialization. This can make boundary-condition selection nondeterministic/wrong in GPU runs.

### Issue Context
- `m_cbc` uses `bc_${XYZ}$%beg/%end` inside device loops to choose the CBC formulation.
- Under OpenACC, `m_global_parameters` only declares `bc_*%vb*`/`%ve*` on the device.
- `s_initialize_gpu_vars` updates `bc_*%vb*`/`%ve*` and `bc_*%grcbc_*` but not `bc_*%beg/%end`.

### Fix Focus Areas
- src/simulation/m_global_parameters.fpp[211-223]
- src/simulation/m_start_up.fpp[1035-1061]
- src/simulation/m_cbc.fpp[725-786]

### Expected fix
- Add `bc_x%beg, bc_x%end, bc_y%beg, bc_y%end, bc_z%beg, bc_z%end` to the OpenACC `GPU_DECLARE(create=...)` list (or declare the full `bc_x/bc_y/bc_z` structs for OpenACC).
- Add a matching `GPU_UPDATE(device='[...]')` for those beg/end members in `s_initialize_gpu_vars` after they are finalized on the host.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@qodo-code-review
Copy link
Copy Markdown
Contributor

qodo-code-review bot commented Apr 10, 2026

Code Review by Qodo

🐞 Bugs (5)   📘 Rule violations (3)   📎 Requirement gaps (0)   🎨 UX Issues (0)
🐞\ ≡ Correctness (2) ☼ Reliability (2) ⚙ Maintainability (1) ⭐ New (3)
📘\ ☼ Reliability (2) ⚙ Maintainability (1) ⭐ New (2)

Grey Divider


Action required

1. qbmm_idx allocations not deallocated 📘
Description
qbmm_idx allocatables are allocated via @:ALLOCATE(...) but there is no corresponding
@:DEALLOCATE(...) for these members, which breaks the project’s required allocation/deallocation
pairing and risks leaks across repeated init/finalize cycles. Add matching deallocations in the
module finalization path (and any early-return/error paths if applicable).
Code

src/simulation/m_global_parameters.fpp[R922-928]

+                    @:ALLOCATE(qbmm_idx%rs(nb), qbmm_idx%vs(nb))
+                    @:ALLOCATE(qbmm_idx%ps(nb), qbmm_idx%ms(nb))

                    gam = bub_pp%gam_g

                    if (qbmm) then
-                        @:ALLOCATE(bub_idx%moms(nb, nmom))
+                        @:ALLOCATE(qbmm_idx%moms(nb, nmom))
Evidence
PR Compliance ID 8 requires every @:ALLOCATE(...) to have a matching @:DEALLOCATE(...). The PR
introduces @:ALLOCATE calls for qbmm_idx%rs/vs/ps/ms/moms but no @:DEALLOCATE for these
members exists in the codebase finalization path.

CLAUDE.md
src/simulation/m_global_parameters.fpp[922-928]
src/simulation/m_global_parameters.fpp[995-996]
src/simulation/m_global_parameters.fpp[1299-1340]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`qbmm_idx` allocatable members are allocated with `@:ALLOCATE(...)` but are never freed with `@:DEALLOCATE(...)`, violating the required pairing and risking leaks when initialization/finalization occurs more than once.

## Issue Context
Allocations occur in `s_initialize_global_parameters_module` (or equivalent init logic) for `qbmm_idx%rs`, `qbmm_idx%vs`, `qbmm_idx%ps`, `qbmm_idx%ms`, and (when `qbmm`) `qbmm_idx%moms`. The module already has a `s_finalize_global_parameters_module` where other `@:DEALLOCATE(...)` calls are performed, but it does not currently deallocate `qbmm_idx` members.

## Fix Focus Areas
- src/simulation/m_global_parameters.fpp[922-952]
- src/simulation/m_global_parameters.fpp[995-1012]
- src/simulation/m_global_parameters.fpp[1299-1340]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. CBC BC codes missing 🐞
Description
In OpenACC builds, m_cbc selects CBC boundary logic using bc_x/y/z%beg/%end inside GPU kernels, but
those fields are not declared/updated on device after the refactor removed the mirrored bcxb/bcxe
scalars. This can lead to wrong boundary-condition branch selection (undefined values on device) and
incorrect/unstable CBC behavior on GPU runs.
Code

src/simulation/m_cbc.fpp[R69-75]

    $:GPU_DECLARE(create='[is1, is2, is3]')

    integer :: dj
-    integer :: bcxb, bcxe, bcyb, bcye, bczb, bcze
    integer :: cbc_dir, cbc_loc
    integer :: flux_cbc_index
-    $:GPU_DECLARE(create='[dj, bcxb, bcxe, bcyb, bcye, bczb, bcze]')
+    $:GPU_DECLARE(create='[dj]')
    $:GPU_DECLARE(create='[cbc_dir, cbc_loc, flux_cbc_index]')
Evidence
CBC kernel code branches on bc_*%beg/%end and grcbc_* inside an OpenACC parallel loop, requiring
those members to be present on device. However, the OpenACC declare/update path only manages
bc_*%vb*/%ve* and grcbc flags, not beg/end, and the PR removed the dedicated device-updated
bcxb/bcxe scalars that previously carried those values.

src/simulation/m_cbc.fpp[598-787]
src/simulation/m_global_parameters.fpp[211-223]
src/simulation/m_start_up.fpp[1054-1061]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
OpenACC device data management does not include `bc_x%beg`, `bc_x%end` (and same for y/z), but `m_cbc` reads these inside GPU kernels after the refactor removed the mirrored `bcxb/bcxe/...` scalars.

### Issue Context
- `m_cbc` branches on `bc_${XYZ}$%beg/%end` and uses `bc_${XYZ}$%grcbc_*` inside `$:GPU_PARALLEL_LOOP`.
- `m_global_parameters` OpenACC declarations only create `bc_*%vb*`/`bc_*%ve*` (and startup updates those plus `grcbc_*`), leaving `%beg/%end` undefined on device.

### Fix Focus Areas
- src/simulation/m_global_parameters.fpp[211-223]
- src/simulation/m_start_up.fpp[1054-1061]
- src/simulation/m_cbc.fpp[598-787]

### What to change
1. In the OpenACC branch of `m_global_parameters`, add `bc_x%beg, bc_x%end` (and y/z) to `GPU_DECLARE(create=...)` (or declare `bc_x, bc_y, bc_z` fully if supported).
2. In `s_initialize_gpu_vars` (or wherever BC GPU updates are centralized), add `GPU_UPDATE(device='[bc_x%beg, bc_x%end]')` (and y/z) after those values are finalized.
3. Keep existing updates for `grcbc_*` flags; ensure beg/end updates occur before any CBC kernels run.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Uninitialized eqn_idx fields read 🐞
Description
eqn_idx sub-fields like stress/xi/B/species are only assigned under feature flags, but multiple
targets read them unconditionally (e.g., copying to strxb/xibeg or writing indices.dat ranges). When
a feature is disabled, this is a read of undefined values and can produce incorrect indices.dat
output or propagate garbage indices into downstream logic.
Code

src/simulation/m_global_parameters.fpp[R1187-1202]

+        momxb = eqn_idx%mom%beg
+        momxe = eqn_idx%mom%end
+        advxb = eqn_idx%adv%beg
+        advxe = eqn_idx%adv%end
+        contxb = eqn_idx%cont%beg
+        contxe = eqn_idx%cont%end
+        bubxb = eqn_idx%bub%beg
+        bubxe = eqn_idx%bub%end
+        strxb = eqn_idx%stress%beg
+        strxe = eqn_idx%stress%end
+        intxb = eqn_idx%int_en%beg
+        intxe = eqn_idx%int_en%end
+        xibeg = eqn_idx%xi%beg
+        xiend = eqn_idx%xi%end
+        chemxb = eqn_idx%species%beg
+        chemxe = eqn_idx%species%end
Evidence
Both simulation and pre_process compute optional ranges (e.g., eqn_idx%stress%beg/end) only inside
if (hypoelasticity .or. hyperelasticity) / if (hyperelasticity) blocks, but later
unconditionally read these fields into global index scalars (strxb/strxe/xibeg/xiend) and
unconditionally pass them to write_range when generating indices.dat. This means configurations
with those features off will still read undefined derived-type members.

src/simulation/m_global_parameters.fpp[1050-1105]
src/simulation/m_global_parameters.fpp[1187-1206]
src/pre_process/m_global_parameters.fpp[730-806]
src/pre_process/m_data_output.fpp[641-652]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
Several `eqn_idx` members (e.g., `stress`, `xi`, `B`, `int_en`, `species`, and scalars like `c`, `damage`, `psi`) are conditionally assigned, but are read unconditionally later (copied into `strxb/strxe/...` and written to `indices.dat`). This reads undefined values when the related feature is disabled.

### Issue Context
- In `m_global_parameters` (simulation/pre_process/post_process), optional ranges are only set in feature-gated blocks.
- Later code unconditionally does `strxb = eqn_idx%stress%beg` etc.
- `m_data_output` (pre_process) unconditionally calls `write_range(eqn_idx%stress%beg, ...)`, `write_range(eqn_idx%xi%beg, ...)`, etc.

### Fix Focus Areas
- src/simulation/m_global_parameters.fpp[1050-1105]
- src/simulation/m_global_parameters.fpp[1187-1206]
- src/pre_process/m_global_parameters.fpp[730-806]
- src/pre_process/m_data_output.fpp[641-652]

### What to change
1. At the start of the equation-index construction routine in each target’s `m_global_parameters`, explicitly initialize all `eqn_idx` members to a known inactive state:
  - Set every `int_bounds_info` range’s `%beg`/`%end` to `0`.
  - Set scalar indices like `E`, `n`, `gamma`, `pi_inf`, `c`, `damage`, `psi` to `0` (or the established sentinel if the codebase uses one consistently).
2. Only then compute/overwrite the active indices under feature flags.
3. Optionally encapsulate this in a small helper like `call s_reset_eqn_idx(eqn_idx)` to avoid duplicated initialization across targets.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (2)
4. qbmm_idx allocations not freed 📘
Description
qbmm_idx%rs/vs/ps/ms (and sometimes qbmm_idx%moms) are allocated via @:ALLOCATE but are never
deallocated in s_finalize_global_parameters_module, risking memory leaks and non-deterministic
resource cleanup. This violates the required @:ALLOCATE/@:DEALLOCATE pairing policy.
Code

src/simulation/m_global_parameters.fpp[R922-929]

+                    @:ALLOCATE(qbmm_idx%rs(nb), qbmm_idx%vs(nb))
+                    @:ALLOCATE(qbmm_idx%ps(nb), qbmm_idx%ms(nb))

                   gam = bub_pp%gam_g

                   if (qbmm) then
-                        @:ALLOCATE(bub_idx%moms(nb, nmom))
+                        @:ALLOCATE(qbmm_idx%moms(nb, nmom))
                       do i = 1, nb
Evidence
PR Compliance ID 8 requires every @:ALLOCATE(...) to have a matching @:DEALLOCATE(...). The PR
allocates several qbmm_idx allocatables, but s_finalize_global_parameters_module does not
deallocate any qbmm_idx members.

CLAUDE.md
src/simulation/m_global_parameters.fpp[922-929]
src/simulation/m_global_parameters.fpp[995-996]
src/simulation/m_global_parameters.fpp[1299-1340]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`qbmm_idx` members are allocated with `@:ALLOCATE` in `s_initialize_global_parameters_module` but are never freed in `s_finalize_global_parameters_module`.
## Issue Context
This PR replaced `bub_idx` allocatables with `qbmm_idx` allocatables; the finalization path must be updated to deallocate the new allocations (including `qbmm_idx%moms` when `qbmm` is enabled).
## Fix Focus Areas
- src/simulation/m_global_parameters.fpp[922-929]
- src/simulation/m_global_parameters.fpp[995-996]
- src/simulation/m_global_parameters.fpp[1299-1340]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. BC beg/end missing on GPU 🐞
Description
OpenACC device code in m_cbc now branches on bc_x/bc_y/bc_z%beg/%end, but those members are not
included in the OpenACC GPU_DECLARE list and are never GPU_UPDATE’d, so kernels can read undefined
values and apply incorrect characteristic boundary conditions.
Code

src/simulation/m_cbc.fpp[R727-736]

+                        if ((cbc_loc == -1 .and. bc_${XYZ}$%beg == BC_CHAR_SLIP_WALL) &
+                            & .or. (cbc_loc == 1 .and. bc_${XYZ}$%end == BC_CHAR_SLIP_WALL)) then
                           call s_compute_slip_wall_L(lambda, L, rho, c, dpres_ds, dvel_ds)
-                        else if ((cbc_loc == -1 .and. bc${XYZ}$b == BC_CHAR_NR_SUB_BUFFER) &
-                                 & .or. (cbc_loc == 1 .and. bc${XYZ}$e == BC_CHAR_NR_SUB_BUFFER)) then
+                        else if ((cbc_loc == -1 .and. bc_${XYZ}$%beg == BC_CHAR_NR_SUB_BUFFER) &
+                                 & .or. (cbc_loc == 1 .and. bc_${XYZ}$%end == BC_CHAR_NR_SUB_BUFFER)) then
                           call s_compute_nonreflecting_subsonic_buffer_L(lambda, L, rho, c, mf, dalpha_rho_ds, dpres_ds, &
                               & dvel_ds, dadv_ds, dYs_ds)
-                        else if ((cbc_loc == -1 .and. bc${XYZ}$b == BC_CHAR_NR_SUB_INFLOW) &
-                                 & .or. (cbc_loc == 1 .and. bc${XYZ}$e == BC_CHAR_NR_SUB_INFLOW)) then
+                        else if ((cbc_loc == -1 .and. bc_${XYZ}$%beg == BC_CHAR_NR_SUB_INFLOW) &
+                                 & .or. (cbc_loc == 1 .and. bc_${XYZ}$%end == BC_CHAR_NR_SUB_INFLOW)) then
                           call s_compute_nonreflecting_subsonic_inflow_L(lambda, L, rho, c, dpres_ds, dvel_ds)
Evidence
m_cbc uses bc_${XYZ}$%beg/%end inside GPU loops to select the BC formulation, but simulation global
parameters only declare vb*/ve* components of bc_x/bc_y/bc_z for OpenACC (not beg/end), and GPU
initialization only updates vb*/ve* and grcbc flags to the device. Therefore, bc_*%beg/%end are not
device-resident/synchronized when referenced in device code.

src/simulation/m_cbc.fpp[725-786]
src/simulation/m_global_parameters.fpp[211-223]
src/simulation/m_start_up.fpp[1035-1061]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
CBC OpenACC kernels now read `bc_x%beg/%end` (and y/z) on-device, but these fields are not part of the OpenACC `GPU_DECLARE` set and are not copied to the device during GPU initialization. This can make boundary-condition selection nondeterministic/wrong in GPU runs.
### Issue Context
- `m_cbc` uses `bc_${XYZ}$%beg/%end` inside device loops to choose the CBC formulation.
- Under OpenACC, `m_global_parameters` only declares `bc_*%vb*`/`%ve*` on the device.
- `s_initialize_gpu_vars` updates `bc_*%vb*`/`%ve*` and `bc_*%grcbc_*` but not `bc_*%beg/%end`.
### Fix Focus Areas
- src/simulation/m_global_parameters.fpp[211-223]
- src/simulation/m_start_up.fpp[1035-1061]
- src/simulation/m_cbc.fpp[725-786]
### Expected fix
- Add `bc_x%beg, bc_x%end, bc_y%beg, bc_y%end, bc_z%beg, bc_z%end` to the OpenACC `GPU_DECLARE(create=...)` list (or declare the full `bc_x/bc_y/bc_z` structs for OpenACC).
- Add a matching `GPU_UPDATE(device='[...]')` for those beg/end members in `s_initialize_gpu_vars` after they are finalized on the host.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

6. Uppercase file/status keywords 📘
Description
The new open statement uses uppercase keyword arguments (FILE=, STATUS=), conflicting with the
project’s Fortran style convention of lowercase keywords. This reduces consistency/readability
across the codebase.
Code

src/pre_process/m_data_output.fpp[614]

+        open (newunit=iu, FILE='indices.dat', STATUS='unknown')
Evidence
PR Compliance ID 10 requires lowercase Fortran keywords/conventions. The modified open statement
introduces uppercase keyword arguments (FILE, STATUS) instead of lowercase.

CLAUDE.md
src/pre_process/m_data_output.fpp[614-614]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The `open` statement uses uppercase keyword arguments (`FILE=`, `STATUS=`), which conflicts with the project style preference for lowercase keywords.

## Issue Context
This was introduced while switching to `newunit=iu` for `indices.dat`.

## Fix Focus Areas
- src/pre_process/m_data_output.fpp[614-614]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


7. indices.dat range formatting overflow 🐞
Description
indices.dat summary ranges are written using an I2 field width and are gated only by beg /= 0, so
larger systems (e.g., QBMM: nb*nmom) can print as **/truncated and disabled-feature sentinels
(negative/nonzero) can still be emitted. This makes indices.dat misleading or unusable for
downstream parsing/inspection.
Code

src/pre_process/m_data_output.fpp[R669-675]

+        subroutine write_range(beg, end, label)
+
+            integer, intent(in)      :: beg, end
+            character(*), intent(in) :: label
+
+            if (beg /= 0) write (iu, '("[",I2,",",I2,"]",A)') beg, end, label
+
Evidence
write_range uses I2 for both begin/end, which overflows for indices > 99. The system size can
grow by terms like nb*nmom for QBMM (and other additive features), and the writer is called for
many ranges unconditionally.

src/pre_process/m_data_output.fpp[641-676]
src/pre_process/m_global_parameters.fpp[593-607]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The indices.dat range summary uses a too-narrow integer format (`I2`) and a weak guard (`beg /= 0`), which can produce `***`/truncated output for larger indices and can print disabled-feature sentinel values.

### Issue Context
`sys_size` and index ranges can exceed 99 (e.g., QBMM uses `eqn_idx%bub%end = eqn_idx%adv%end + nb*nmom`). The indices.dat summary is meant for humans and possibly scripts.

### Fix Focus Areas
- src/pre_process/m_data_output.fpp[641-676]
- src/pre_process/m_global_parameters.fpp[593-607]

### What to change
1. Change the write format to a width that won’t overflow (e.g., `I0` or `I6`) in `write_range`.
2. Strengthen the guard to print only valid active ranges (e.g., `if (beg > 0)`), assuming inactive indices are initialized to 0.
3. (Optional) If you keep sentinels other than 0, adjust the predicate accordingly (e.g., `beg >= 1`).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


8. Uninitialized eqn_idx printed 🐞
Description
indices.dat generation now unconditionally prints ranges for optional equation blocks
(stress/xi/B/color/species) using eqn_idx fields that are only conditionally assigned and have no
default initialization, so indices.dat can contain garbage ranges when features are disabled.
Code

src/pre_process/m_data_output.fpp[R641-652]

+        write (iu, '(A)') ""
+        call write_range(eqn_idx%cont%beg, eqn_idx%cont%end, " Continuity")
+        call write_range(eqn_idx%mom%beg, eqn_idx%mom%end, " Momentum")
+        call write_range(eqn_idx%E, eqn_idx%E, " Energy/Pressure")
+        call write_range(eqn_idx%adv%beg, eqn_idx%adv%end, " Advection")
+        call write_range(eqn_idx%bub%beg, eqn_idx%bub%end, " Bubbles")
+        call write_range(eqn_idx%stress%beg, eqn_idx%stress%end, " Stress")
+        call write_range(eqn_idx%int_en%beg, eqn_idx%int_en%end, " Internal Energies")
+        call write_range(eqn_idx%xi%beg, eqn_idx%xi%end, " Reference Map")
+        call write_range(eqn_idx%B%beg, eqn_idx%B%end, " Magnetic Field")
+        call write_range(eqn_idx%c, eqn_idx%c, " Color Function")
+        call write_range(eqn_idx%species%beg, eqn_idx%species%end, " Chemistry")
Evidence
eqn_idx_info and int_bounds_info do not define default values, and global-parameter initialization
assigns several eqn_idx ranges/scalars only under feature guards (e.g., stress only when
(hypo|hyper)elasticity, xi only when hyperelasticity, B only when mhd, c only when surface_tension).
The updated indices.dat writer now always calls write_range on these eqn_idx fields and only checks
beg /= 0, which reads potentially uninitialized integers and can print incorrect ranges.

src/common/m_derived_types.fpp[95-147]
src/pre_process/m_global_parameters.fpp[730-783]
src/pre_process/m_data_output.fpp[614-676]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`indices.dat` now prints summary ranges for multiple optional equation groups via `eqn_idx%...` fields, but those fields are only conditionally assigned in global-parameter initialization and have no default initialization. When a feature is off (e.g., no MHD), `eqn_idx%B%beg/%end` can be undefined yet still read by `write_range`, producing nondeterministic output.
### Issue Context
- `eqn_idx_info` uses `int_bounds_info` members with no default values.
- Several `eqn_idx` members are assigned only inside feature guards.
- `s_initialize_data_output_module` calls `write_range(eqn_idx%xi%beg,...)`, `write_range(eqn_idx%B%beg,...)`, and `write_range(eqn_idx%c,...)` unconditionally.
### Fix Focus Areas
- src/common/m_derived_types.fpp[95-147]
- src/pre_process/m_global_parameters.fpp[730-783]
- src/pre_process/m_data_output.fpp[614-676]
### Expected fix
Choose one (or combine):
1) **Explicit reset in global-parameter init**: At the very start of each target’s global-parameter initialization, set all `eqn_idx` scalar members to `0` and all `eqn_idx%<range>%beg/end` to `0` before filling the active ones.
2) **Default initialization in derived types**: Add default values (e.g., `integer :: beg=0, end=0` and `integer :: E=0`, etc.) so `eqn_idx` is safe by construction.
3) **Guard printing by feature flags**: Only call `write_range` for xi/B/stress/color/species when the corresponding feature is enabled.
Goal: make `0 = inactive` true in all builds and prevent reading undefined index values.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 10, 2026

📝 Walkthrough

Walkthrough

This pull request performs a large-scale refactoring of equation index management across the codebase. The changes introduce two new derived types—eqn_idx_info and qbmm_idx_info—to consolidate what were previously scattered individual index variables (e.g., E_idx, mom_idx, B_idx, alf_idx, gamma_idx, pi_inf_idx, c_idx, damage_idx, psi_idx, stress_idx, xi_idx, species_idx, adv_idx, cont_idx, n_idx, and the old bub_bounds_info). The refactoring systematically replaces all usages of these legacy index variables throughout the entire codebase with structured field accesses (e.g., eqn_idx%E, eqn_idx%mom, eqn_idx%adv%end). Additionally, a new GitHub Actions workflow file is added to enable automated Claude-based code review triggered by pull request events.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The PR title accurately summarizes the main refactoring work: unifying equation/range indices and cleaning up BC globals.
Linked Issues check ✅ Passed All coding requirements from #828 are met: BC scalars consolidated into bc_xyz_info, s_populate_capillary_buffers updated, equation indices unified into sys_idx/eqn_idx_info, QBMM allocatables separated into qbmm_idx_info, GPU-declarable struct design, and indices.dat improvements.
Out of Scope Changes check ✅ Passed All changes align with #828 objectives: consolidation of index types, removal of dead BC globals, refactored accessor patterns, and improved indices.dat generation without unrelated modifications.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description check ✅ Passed The PR description is comprehensive and well-structured, covering all major changes including BC scalars, unified equation indices, QBMM split, and indices.dat improvements.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
src/simulation/m_time_steppers.fpp (1)

916-959: ⚠️ Potential issue | 🟡 Minor

Missing deallocations for eqn_idx%n and eqn_idx%c allocations.

The allocation block allocates q_prim_vf(eqn_idx%n)%sf when adv_n is true (Line 239) and q_prim_vf(eqn_idx%c)%sf when surface_tension is true (Line 290), but the finalization subroutine does not deallocate these fields.

🔧 Proposed fix to add missing deallocations
             if (bubbles_euler) then
                 do i = eqn_idx%bub%beg, eqn_idx%bub%end
                     @:DEALLOCATE(q_prim_vf(i)%sf)
                 end do
+                if (adv_n) then
+                    @:DEALLOCATE(q_prim_vf(eqn_idx%n)%sf)
+                end if
             end if

             if (model_eqns == 3) then
                 do i = eqn_idx%int_en%beg, eqn_idx%int_en%end
                     @:DEALLOCATE(q_prim_vf(i)%sf)
                 end do
             end if
+
+            if (surface_tension) then
+                @:DEALLOCATE(q_prim_vf(eqn_idx%c)%sf)
+            end if
         end if

As per coding guidelines: "Every @:ALLOCATE(...) Fypp macro MUST have a matching @:DEALLOCATE(...)."

src/simulation/m_rhs.fpp (1)

1727-1747: ⚠️ Potential issue | 🟠 Major

s_finalize_rhs_module no longer mirrors the q_cons_qp / q_prim_qp allocation paths.

q_cons_qp%vf(l)%sf is allocated for l = 1:sys_size, and q_prim_qp is also allocated past eqn_idx%E in s_initialize_rhs_module, but this finalizer only frees mom:E and does alias cleanup for cont/adv. That leaves the conservative continuity/advection targets and every primitive field above eqn_idx%E live at shutdown.

Proposed direction
-        if (.not. igr) then
-            do j = eqn_idx%cont%beg, eqn_idx%cont%end
-                if (relativity) then
-                    @:DEALLOCATE(q_cons_qp%vf(j)%sf)
-                    @:DEALLOCATE(q_prim_qp%vf(j)%sf)
-                else
-                    nullify (q_prim_qp%vf(j)%sf)
-                end if
-            end do
-
-            do j = eqn_idx%adv%beg, eqn_idx%adv%end
-                nullify (q_prim_qp%vf(j)%sf)
-            end do
-
-            do j = eqn_idx%mom%beg, eqn_idx%E
-                @:DEALLOCATE(q_cons_qp%vf(j)%sf)
-                @:DEALLOCATE(q_prim_qp%vf(j)%sf)
-            end do
-        end if
+        if (.not. igr) then
+            do j = 1, sys_size
+                if (associated(q_prim_qp%vf(j)%sf, q_cons_qp%vf(j)%sf)) then
+                    nullify (q_prim_qp%vf(j)%sf)
+                end if
+            end do
+
+            do j = 1, sys_size
+                if (associated(q_cons_qp%vf(j)%sf)) then
+                    @:DEALLOCATE(q_cons_qp%vf(j)%sf)
+                end if
+                if (associated(q_prim_qp%vf(j)%sf)) then
+                    @:DEALLOCATE(q_prim_qp%vf(j)%sf)
+                end if
+            end do
+        end if

As per coding guidelines "Every @:ALLOCATE(...) Fypp macro MUST have a matching @:DEALLOCATE(...)."

src/pre_process/m_data_output.fpp (1)

619-675: ⚠️ Potential issue | 🟡 Minor

Use unlimited-width integer formatting in indices.dat.

The new file still formats indices with I3/I2. Once a case pushes any equation index past those widths, Fortran will print ***/**, which corrupts the mapping you just made easier to consume.

Suggested fix
-        write (iu, '(I3,A20,A20)') i, "\alpha_{" // trim(temp) // "} \rho_{" // trim(temp) // "}", &
+        write (iu, '(I0,1X,A20,1X,A20)') i, "\alpha_{" // trim(temp) // "} \rho_{" // trim(temp) // "}", &
                    & "\alpha_{" // trim(temp) // "} \rho"
...
-        write (iu, '(I3,A20,A20)') i, "\rho u_" // coord(i - momxb + 1), "u_" // coord(i - momxb + 1)
+        write (iu, '(I0,1X,A20,1X,A20)') i, "\rho u_" // coord(i - momxb + 1), "u_" // coord(i - momxb + 1)
...
-        if (eqn_idx%E /= 0) write (iu, '(I3,A20,A20)') eqn_idx%E, "\rho U", "p"
+        if (eqn_idx%E /= 0) write (iu, '(I0,1X,A20,1X,A20)') eqn_idx%E, "\rho U", "p"
...
-        write (iu, '(I3,A20,A20)') i, "\alpha_{" // trim(temp) // "}", "\alpha_{" // trim(temp) // "}"
+        write (iu, '(I0,1X,A20,1X,A20)') i, "\alpha_{" // trim(temp) // "}", "\alpha_{" // trim(temp) // "}"
...
-        write (iu, '(I3,A20,A20)') chemxb + i - 1, "Y_{" // trim(species_names(i)) // "} \rho", &
+        write (iu, '(I0,1X,A20,1X,A20)') chemxb + i - 1, "Y_{" // trim(species_names(i)) // "} \rho", &
                    & "Y_{" // trim(species_names(i)) // "}"
...
-            if (beg /= 0) write (iu, '("[",I2,",",I2,"]",A)') beg, end, label
+            if (beg /= 0) write (iu, '("[",I0,",",I0,"]",A)') beg, end, label

Based on learnings "Flag modifications to public subroutine signatures, parameter defaults, or output formats as they affect downstream code and user workflows."

src/simulation/m_cbc.fpp (1)

727-785: ⚠️ Potential issue | 🔴 Critical

The BC struct members beg and end are not GPU-declared for OpenACC builds.

The GPU branches in lines 727–785 read bc_${XYZ}$%beg and bc_${XYZ}$%end directly within GPU kernels. However, src/simulation/m_global_parameters.fpp lines 218–222 show that for OpenACC, only the vector fields (bc_x%vb1, bc_x%vb2, bc_x%vb3, bc_x%ve1, bc_x%ve2, bc_x%ve3) are GPU_DECLARE'd; the scalar beg and end members are left host-only. OpenMP correctly declares the full struct. This mismatch means OpenACC GPU kernels may silently read stale or uninitialized host memory when branching on BC metadata, causing divergence from CPU behavior.

Add GPU declarations for bc_x%beg, bc_x%end, bc_y%beg, bc_y%end, bc_z%beg, bc_z%end in src/simulation/m_global_parameters.fpp for the OpenACC path, or refactor to use the already-declared vector fields.

🧹 Nitpick comments (6)
claude-code-review.yml (1)

145-164: Context fetching handles errors silently.

The 2>/dev/null || true at line 151 and similar patterns silently swallow API errors. While acceptable for "optional" context, consider adding minimal logging (e.g., echo "Skipped: $path" >&2) when files fail to fetch for easier debugging during workflow development.

src/pre_process/m_perturbation.fpp (1)

46-52: Use eqn_idx%adv here instead of eqn_idx%E + offset.

These lines work only because the advection block currently sits immediately after energy. That reintroduces the same implicit layout coupling this refactor is trying to remove.

♻️ Proposed refactor
-                    perturb_alpha = q_prim_vf(eqn_idx%E + perturb_sph_fluid)%sf(i, j, k)
+                    perturb_alpha = q_prim_vf(eqn_idx%adv%beg + perturb_sph_fluid - 1)%sf(i, j, k)
...
-                            q_prim_vf(l)%sf(i, j, k) = q_prim_vf(eqn_idx%E + l)%sf(i, j, k)*fluid_rho(l)
+                            q_prim_vf(eqn_idx%cont%beg + l - 1)%sf(i, j, k) = &
+                                q_prim_vf(eqn_idx%adv%beg + l - 1)%sf(i, j, k)*fluid_rho(l)
src/common/m_boundary_common.fpp (1)

1054-1058: Run the full shared-target test matrix for this API change.

Line 1054 changes a src/common boundary routine signature on the capillary path. Build coverage is good, but I’d still want ./mfc.sh test -j 8 across pre_process, simulation, and post_process before merging.

As per coding guidelines, "src/common/**/*.{fpp,f90}: Test changes to src/common/ comprehensively by running ALL three targets (./mfc.sh test -j 8) since this shared code affects all three executables".

src/simulation/m_start_up.fpp (1)

1035-1049: Duplicate GPU_UPDATE with overlapping variables.

Lines 1035-1038 and line 1049 both update adv_n, adap_dt, adap_dt_tol, adap_dt_max_iters, eqn_idx%n, pi_fac, and low_Mach to the device. This appears to be unintentional duplication that could be removed for clarity and minor performance improvement.

♻️ Suggested fix to remove duplicate GPU_UPDATE
         $:GPU_UPDATE(device='[R0ref, p0ref, rho0ref, ss, pv, vd, mu_l, mu_v, mu_g, gam_v, gam_g, M_v, M_g, R_v, R_g, Tw, cp_v, &
                      & cp_g, k_vl, k_gl, gam, gam_m, Eu, Ca, Web, Re_inv, Pe_c, phi_vg, phi_gv, omegaN, bubbles_euler, &
                      & polytropic, polydisperse, qbmm, ptil, bubble_model, thermal, poly_sigma, adv_n, adap_dt, adap_dt_tol, &
                      & adap_dt_max_iters, eqn_idx%n, pi_fac, low_Mach]')
 
         if (bubbles_euler) then
             $:GPU_UPDATE(device='[weight, R0]')
             if (.not. polytropic) then
                 $:GPU_UPDATE(device='[pb0, Pe_T, k_g, k_v, mass_g0, mass_v0, Re_trans_T, Re_trans_c, Im_trans_T, Im_trans_c]')
             else if (qbmm) then
                 $:GPU_UPDATE(device='[pb0]')
             end if
         end if
 
-        $:GPU_UPDATE(device='[adv_n, adap_dt, adap_dt_tol, adap_dt_max_iters, eqn_idx%n, pi_fac, low_Mach]')
-
         $:GPU_UPDATE(device='[acoustic_source, num_source]')
src/simulation/m_riemann_solvers.fpp (2)

253-258: Prefer eqn_idx%alf over eqn_idx%E + i for alpha slots.

These accesses still assume the alpha block starts immediately after pressure. Since the new index holder already exposes eqn_idx%alf, using that explicitly would finish the decoupling this refactor is aiming for and avoid baking the old layout back into the solver.

Representative change
- alpha_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, eqn_idx%E + i)
- alpha_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, eqn_idx%E + i)
+ alpha_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, eqn_idx%alf - 1 + i)
+ alpha_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, eqn_idx%alf - 1 + i)

Also applies to: 935-940, 1821-1859, 2238-2261, 2443-2467, 2840-2887, 3383-3388


2236-2245: Drop the duplicated alpha extraction loop.

The second loop reloads the same alpha_L/alpha_R values and does no extra work. In this GPU hot path it only adds instruction count and register pressure.

Proposed fix
   $:GPU_LOOP(parallelism='[seq]')
   do i = 1, num_fluids
       alpha_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, eqn_idx%E + i)
       alpha_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, eqn_idx%E + i)
   end do
-  $:GPU_LOOP(parallelism='[seq]')
-  do i = 1, num_fluids
-      alpha_L(i) = qL_prim_rs${XYZ}$_vf(j, k, l, eqn_idx%E + i)
-      alpha_R(i) = qR_prim_rs${XYZ}$_vf(j + 1, k, l, eqn_idx%E + i)
-  end do

Based on learnings: Avoid unnecessary host/device transfers in hot loops, redundant allocations, and algorithmic inefficiency.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ac3fd33f-76bc-45a2-90ba-13bfdcedc3ed

📥 Commits

Reviewing files that changed from the base of the PR and between ec94064 and a4c18bd.

📒 Files selected for processing (41)
  • claude-code-review.yml
  • src/common/include/1dHardcodedIC.fpp
  • src/common/include/2dHardcodedIC.fpp
  • src/common/include/3dHardcodedIC.fpp
  • src/common/m_boundary_common.fpp
  • src/common/m_chemistry.fpp
  • src/common/m_derived_types.fpp
  • src/common/m_phase_change.fpp
  • src/common/m_variables_conversion.fpp
  • src/post_process/m_data_output.fpp
  • src/post_process/m_derived_variables.fpp
  • src/post_process/m_global_parameters.fpp
  • src/post_process/m_start_up.fpp
  • src/pre_process/m_assign_variables.fpp
  • src/pre_process/m_data_output.fpp
  • src/pre_process/m_global_parameters.fpp
  • src/pre_process/m_icpp_patches.fpp
  • src/pre_process/m_initial_condition.fpp
  • src/pre_process/m_perturbation.fpp
  • src/pre_process/m_start_up.fpp
  • src/simulation/m_acoustic_src.fpp
  • src/simulation/m_body_forces.fpp
  • src/simulation/m_bubbles_EE.fpp
  • src/simulation/m_bubbles_EL.fpp
  • src/simulation/m_cbc.fpp
  • src/simulation/m_compute_cbc.fpp
  • src/simulation/m_data_output.fpp
  • src/simulation/m_global_parameters.fpp
  • src/simulation/m_hyperelastic.fpp
  • src/simulation/m_hypoelastic.fpp
  • src/simulation/m_ibm.fpp
  • src/simulation/m_igr.fpp
  • src/simulation/m_pressure_relaxation.fpp
  • src/simulation/m_qbmm.fpp
  • src/simulation/m_rhs.fpp
  • src/simulation/m_riemann_solvers.fpp
  • src/simulation/m_sim_helpers.fpp
  • src/simulation/m_start_up.fpp
  • src/simulation/m_surface_tension.fpp
  • src/simulation/m_time_steppers.fpp
  • src/simulation/m_viscous.fpp

Comment on lines +672 to +673
call s_compute_pressure(qK_cons_vf(eqn_idx%E)%sf(j, k, l), qK_cons_vf(eqn_idx%alf)%sf(j, k, l), dyn_pres_K, &
& pi_inf_K, gamma_K, rho_K, qv_K, rhoYks, pres, T, pres_mag=pres_mag)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Don't index qK_cons_vf with eqn_idx%alf unconditionally.

alf is unused for most EOS branches, but this call still evaluates qK_cons_vf(eqn_idx%alf) first. eqn_idx%alf is not initialized for every layout, so model-1/pre-process paths can read an undefined slot before s_compute_pressure even runs.

Suggested fix
-                    call s_compute_pressure(qK_cons_vf(eqn_idx%E)%sf(j, k, l), qK_cons_vf(eqn_idx%alf)%sf(j, k, l), dyn_pres_K, &
-                                            & pi_inf_K, gamma_K, rho_K, qv_K, rhoYks, pres, T, pres_mag=pres_mag)
+                    if (model_eqns == 4 .or. bubbles_euler) then
+                        vftmp = qK_cons_vf(eqn_idx%alf)%sf(j, k, l)
+                    else
+                        vftmp = 0._wp
+                    end if
+
+                    call s_compute_pressure(qK_cons_vf(eqn_idx%E)%sf(j, k, l), vftmp, dyn_pres_K, &
+                                            & pi_inf_K, gamma_K, rho_K, qv_K, rhoYks, pres, T, pres_mag=pres_mag)

Comment on lines +563 to 568
allocate (qbmm_idx%rs(nb), qbmm_idx%vs(nb))
allocate (qbmm_idx%ps(nb), qbmm_idx%ms(nb))

if (qbmm) then
allocate (bub_idx%moms(nb, nmom))
allocate (qbmm_idx%moms(nb, nmom))
do i = 1, nb
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Finalize the new qbmm_idx buffers as well.

These arrays are now allocated during initialization, but the module finalizer still never deallocates them. That leaves the QBMM index storage leaking across repeated post-process runs in the same process.

Suggested fix
 impure subroutine s_finalize_global_parameters_module
@@
+        if (allocated(qbmm_idx%moms)) deallocate(qbmm_idx%moms)
+        if (allocated(qbmm_idx%ms)) deallocate(qbmm_idx%ms)
+        if (allocated(qbmm_idx%ps)) deallocate(qbmm_idx%ps)
+        if (allocated(qbmm_idx%vs)) deallocate(qbmm_idx%vs)
+        if (allocated(qbmm_idx%rs)) deallocate(qbmm_idx%rs)

Also applies to: 643-644

Comment on lines +614 to +619
allocate (qbmm_idx%rs(nb), qbmm_idx%vs(nb))
allocate (qbmm_idx%ps(nb), qbmm_idx%ms(nb))

if (qbmm) then
allocate (bub_idx%moms(nb, nmom))
allocate (bub_idx%fullmom(nb,0:nmom,0:nmom))
allocate (qbmm_idx%moms(nb, nmom))
allocate (qbmm_idx%fullmom(nb,0:nmom,0:nmom))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add a matching teardown for the new qbmm_idx allocations.

These new module allocations never get released in s_finalize_global_parameters_module, so repeated initialize/finalize paths will leak the QBMM index tables.

Suggested fix
 impure subroutine s_finalize_global_parameters_module
@@
+        if (allocated(qbmm_idx%fullmom)) deallocate(qbmm_idx%fullmom)
+        if (allocated(qbmm_idx%moms)) deallocate(qbmm_idx%moms)
+        if (allocated(qbmm_idx%ms)) deallocate(qbmm_idx%ms)
+        if (allocated(qbmm_idx%ps)) deallocate(qbmm_idx%ps)
+        if (allocated(qbmm_idx%vs)) deallocate(qbmm_idx%vs)
+        if (allocated(qbmm_idx%rs)) deallocate(qbmm_idx%rs)

Also applies to: 696-697

Comment on lines +382 to 383
q_prim_vf(eqn_idx%alf)%sf(i, j, &
& 0) = patch_icpp(patch_id)%alpha(1)*exp(-0.5_wp*((myr - radius)**2._wp)/(thickness/3._wp)**2._wp)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Guard eqn_idx%alf before writing the annulus profile.

Line 382 and Line 444 dereference q_prim_vf(eqn_idx%alf) unconditionally. eqn_idx%alf is model-specific and inactive outside model_eqns == 4, so these paths can fall through to q_prim_vf(0) on other models.

Suggested fix
 subroutine s_icpp_varcircle(patch_id, patch_id_fp, q_prim_vf)
+        if (eqn_idx%alf <= 0) then
+            call s_mpi_abort('s_icpp_varcircle requires model_eqns == 4')
+        end if
 ...
 subroutine s_icpp_3dvarcircle(patch_id, patch_id_fp, q_prim_vf)
+        if (eqn_idx%alf <= 0) then
+            call s_mpi_abort('s_icpp_3dvarcircle requires model_eqns == 4')
+        end if

Also applies to: 444-445

Comment on lines +75 to 79
q_prim_vf(eqn_idx%mom%end)%sf(i, j, k) = rand_real*q_prim_vf(eqn_idx%mom%beg)%sf(i, j, k)
q_prim_vf(eqn_idx%mom%beg)%sf(i, j, k) = (1._wp + rand_real)*q_prim_vf(eqn_idx%mom%beg)%sf(i, j, k)
if (bubbles_euler) then
q_prim_vf(alf_idx)%sf(i, j, k) = (1._wp + rand_real)*q_prim_vf(alf_idx)%sf(i, j, k)
q_prim_vf(eqn_idx%alf)%sf(i, j, k) = (1._wp + rand_real)*q_prim_vf(eqn_idx%alf)%sf(i, j, k)
end if
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Guard this momentum perturbation for 1D.

On Line 75, eqn_idx%mom%end aliases eqn_idx%mom%beg when num_vels == 1. That means the first assignment overwrites the only velocity component before Line 76 scales it, so the 1D path gets a different perturbation than intended.

🐛 Proposed fix
-                    q_prim_vf(eqn_idx%mom%end)%sf(i, j, k) = rand_real*q_prim_vf(eqn_idx%mom%beg)%sf(i, j, k)
+                    if (num_vels > 1) then
+                        q_prim_vf(eqn_idx%mom%end)%sf(i, j, k) = rand_real*q_prim_vf(eqn_idx%mom%beg)%sf(i, j, k)
+                    end if
                     q_prim_vf(eqn_idx%mom%beg)%sf(i, j, k) = (1._wp + rand_real)*q_prim_vf(eqn_idx%mom%beg)%sf(i, j, k)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
q_prim_vf(eqn_idx%mom%end)%sf(i, j, k) = rand_real*q_prim_vf(eqn_idx%mom%beg)%sf(i, j, k)
q_prim_vf(eqn_idx%mom%beg)%sf(i, j, k) = (1._wp + rand_real)*q_prim_vf(eqn_idx%mom%beg)%sf(i, j, k)
if (bubbles_euler) then
q_prim_vf(alf_idx)%sf(i, j, k) = (1._wp + rand_real)*q_prim_vf(alf_idx)%sf(i, j, k)
q_prim_vf(eqn_idx%alf)%sf(i, j, k) = (1._wp + rand_real)*q_prim_vf(eqn_idx%alf)%sf(i, j, k)
end if
if (num_vels > 1) then
q_prim_vf(eqn_idx%mom%end)%sf(i, j, k) = rand_real*q_prim_vf(eqn_idx%mom%beg)%sf(i, j, k)
end if
q_prim_vf(eqn_idx%mom%beg)%sf(i, j, k) = (1._wp + rand_real)*q_prim_vf(eqn_idx%mom%beg)%sf(i, j, k)
if (bubbles_euler) then
q_prim_vf(eqn_idx%alf)%sf(i, j, k) = (1._wp + rand_real)*q_prim_vf(eqn_idx%alf)%sf(i, j, k)
end if

Comment on lines +922 to 929
@:ALLOCATE(qbmm_idx%rs(nb), qbmm_idx%vs(nb))
@:ALLOCATE(qbmm_idx%ps(nb), qbmm_idx%ms(nb))

gam = bub_pp%gam_g

if (qbmm) then
@:ALLOCATE(bub_idx%moms(nb, nmom))
@:ALLOCATE(qbmm_idx%moms(nb, nmom))
do i = 1, nb
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Pair the new qbmm_idx allocations with @:DEALLOCATE in teardown.

qbmm_idx%rs/vs/ps/ms and qbmm_idx%moms are now allocated here, but s_finalize_global_parameters_module never releases them. That leaves the new QBMM mapping storage leaking across reinitialization and violates the module’s existing allocate/finalize contract. As per coding guidelines, every @:ALLOCATE(...) Fypp macro MUST have a matching @:DEALLOCATE(...).

Suggested fix
 impure subroutine s_finalize_global_parameters_module
@@
+        if (allocated(qbmm_idx%moms)) @:DEALLOCATE(qbmm_idx%moms)
+        if (allocated(qbmm_idx%ms))   @:DEALLOCATE(qbmm_idx%ms)
+        if (allocated(qbmm_idx%ps))   @:DEALLOCATE(qbmm_idx%ps)
+        if (allocated(qbmm_idx%vs))   @:DEALLOCATE(qbmm_idx%vs)
+        if (allocated(qbmm_idx%rs))   @:DEALLOCATE(qbmm_idx%rs)

Also applies to: 995-996

Comment on lines +939 to +950
local_force_contribution(1) = local_force_contribution(1) - (q_prim_vf(eqn_idx%E + fluid_idx)%sf(i &
& + 1, j, k) - q_prim_vf(eqn_idx%E + fluid_idx)%sf(i - 1, j, &
& k))/(2._wp*dx) ! force is the negative pressure gradient
local_force_contribution(2) = local_force_contribution(2) - (q_prim_vf(E_idx + fluid_idx)%sf(i, &
& j + 1, k) - q_prim_vf(E_idx + fluid_idx)%sf(i, j - 1, k))/(2._wp*dy)
local_force_contribution(2) = local_force_contribution(2) - (q_prim_vf(eqn_idx%E + fluid_idx)%sf(i, &
& j + 1, k) - q_prim_vf(eqn_idx%E + fluid_idx)%sf(i, j - 1, k))/(2._wp*dy)
cell_volume = abs(dx*dy)
! add the 3D component of the pressure gradient, if we are working in 3 dimensions
if (num_dims == 3) then
dz = z_cc(k + 1) - z_cc(k)
local_force_contribution(3) = local_force_contribution(3) - (q_prim_vf(E_idx + fluid_idx)%sf(i, &
& j, k + 1) - q_prim_vf(E_idx + fluid_idx)%sf(i, j, k - 1))/(2._wp*dz)
local_force_contribution(3) = local_force_contribution(3) - (q_prim_vf(eqn_idx%E + fluid_idx) &
& %sf(i, j, k + 1) - q_prim_vf(eqn_idx%E + fluid_idx)%sf(i, j, &
& k - 1))/(2._wp*dz)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Pressure-force loop is reading advection fields as pressure.

Only eqn_idx%E is the pressure slot. For fluid_idx > 0, eqn_idx%E + fluid_idx steps into the advection block, so this loop starts subtracting grad(alpha) into the IBM force in multi-fluid cases. Compute the pressure gradient once from q_prim_vf(eqn_idx%E) here, or switch to the actual per-fluid pressure index if that was the intent.

do i = 1, num_fluids
alpha_rho(i) = q_cons_vf(i)%sf(j, k, l)
alpha(i) = q_cons_vf(E_idx + i)%sf(j, k, l)
alpha(i) = q_cons_vf(eqn_idx%E + i)%sf(j, k, l)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

AMD fallback still overruns alpha_rho/alpha at 3 fluids.

This loop runs to num_fluids, but under the USING_AMD branch above both arrays are still length 2. Since the AMD startup path allows num_fluids == 3, the third iteration writes past both buffers here.

💡 Minimal fix
-        #:if not MFC_CASE_OPTIMIZATION and USING_AMD
-            real(wp), dimension(2) :: alpha_rho, alpha
+        #:if not MFC_CASE_OPTIMIZATION and USING_AMD
+            real(wp), dimension(3) :: alpha_rho, alpha

Based on learnings: when compiling with USING_AMD and not MFC_CASE_OPTIMIZATION, similar simulation arrays are fixed at length 3, and s_check_amd allows num_fluids <= 3.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
alpha(i) = q_cons_vf(eqn_idx%E + i)%sf(j, k, l)
#:if not MFC_CASE_OPTIMIZATION and USING_AMD
real(wp), dimension(3) :: alpha_rho, alpha

Comment on lines 1821 to 1826
if (cyl_coord) then
do i = 1, num_dims
@:DEALLOCATE(tau_re_vf(cont_idx%end + i)%sf)
@:DEALLOCATE(tau_re_vf(eqn_idx%cont%end + i)%sf)
end do
@:DEALLOCATE(tau_re_vf(e_idx)%sf)
@:DEALLOCATE(tau_re_vf(eqn_idx%E)%sf)
@:DEALLOCATE(tau_re_vf)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Deallocate tau_Re_vf for every viscous run, not only cylindrical ones.

tau_Re_vf is allocated under if (viscous) in s_initialize_rhs_module, but this finalizer frees it only when cyl_coord is true. Cartesian viscous runs will leak these buffers.

Minimal fix
-                if (cyl_coord) then
+                if (viscous) then
                     do i = 1, num_dims
                         @:DEALLOCATE(tau_re_vf(eqn_idx%cont%end + i)%sf)
                     end do
                     @:DEALLOCATE(tau_re_vf(eqn_idx%E)%sf)
                     @:DEALLOCATE(tau_re_vf)
                 end if

As per coding guidelines "If an array is allocated inside an if block, its deallocation must follow the same condition to avoid memory leaks."

Comment on lines +449 to +450
G_L = G_L*max((1._wp - qL_prim_rs${XYZ}$_vf(j, k, l, eqn_idx%damage)), 0._wp)
G_R = G_R*max((1._wp - qR_prim_rs${XYZ}$_vf(j, k, l, eqn_idx%damage)), 0._wp)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Use j + 1 for the right-state damage sample.

G_R is computed from the right Riemann state everywhere else, but these reads take eqn_idx%damage from j instead of j + 1. That applies the left-cell damage to the right shear modulus and perturbs the elastic energy/wave-speed calculation across damaged interfaces.

Proposed fix
- G_R = G_R*max((1._wp - qR_prim_rs${XYZ}$_vf(j, k, l, eqn_idx%damage)), 0._wp)
+ G_R = G_R*max((1._wp - qR_prim_rs${XYZ}$_vf(j + 1, k, l, eqn_idx%damage)), 0._wp)

Based on learnings: Riemann solver indexing: left states at index j, right states at j+1; off-by-one errors corrupt fluxes.

Also applies to: 1129-1130

Comment on lines +922 to +928
@:ALLOCATE(qbmm_idx%rs(nb), qbmm_idx%vs(nb))
@:ALLOCATE(qbmm_idx%ps(nb), qbmm_idx%ms(nb))

gam = bub_pp%gam_g

if (qbmm) then
@:ALLOCATE(bub_idx%moms(nb, nmom))
@:ALLOCATE(qbmm_idx%moms(nb, nmom))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. qbmm_idx allocations not deallocated 📘 Rule violation ☼ Reliability

qbmm_idx allocatables are allocated via @:ALLOCATE(...) but there is no corresponding
@:DEALLOCATE(...) for these members, which breaks the project’s required allocation/deallocation
pairing and risks leaks across repeated init/finalize cycles. Add matching deallocations in the
module finalization path (and any early-return/error paths if applicable).
Agent Prompt
## Issue description
`qbmm_idx` allocatable members are allocated with `@:ALLOCATE(...)` but are never freed with `@:DEALLOCATE(...)`, violating the required pairing and risking leaks when initialization/finalization occurs more than once.

## Issue Context
Allocations occur in `s_initialize_global_parameters_module` (or equivalent init logic) for `qbmm_idx%rs`, `qbmm_idx%vs`, `qbmm_idx%ps`, `qbmm_idx%ms`, and (when `qbmm`) `qbmm_idx%moms`. The module already has a `s_finalize_global_parameters_module` where other `@:DEALLOCATE(...)` calls are performed, but it does not currently deallocate `qbmm_idx` members.

## Fix Focus Areas
- src/simulation/m_global_parameters.fpp[922-952]
- src/simulation/m_global_parameters.fpp[995-1012]
- src/simulation/m_global_parameters.fpp[1299-1340]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +1187 to +1202
momxb = eqn_idx%mom%beg
momxe = eqn_idx%mom%end
advxb = eqn_idx%adv%beg
advxe = eqn_idx%adv%end
contxb = eqn_idx%cont%beg
contxe = eqn_idx%cont%end
bubxb = eqn_idx%bub%beg
bubxe = eqn_idx%bub%end
strxb = eqn_idx%stress%beg
strxe = eqn_idx%stress%end
intxb = eqn_idx%int_en%beg
intxe = eqn_idx%int_en%end
xibeg = eqn_idx%xi%beg
xiend = eqn_idx%xi%end
chemxb = eqn_idx%species%beg
chemxe = eqn_idx%species%end
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

3. Uninitialized eqn_idx fields read 🐞 Bug ☼ Reliability

eqn_idx sub-fields like stress/xi/B/species are only assigned under feature flags, but multiple
targets read them unconditionally (e.g., copying to strxb/xibeg or writing indices.dat ranges). When
a feature is disabled, this is a read of undefined values and can produce incorrect indices.dat
output or propagate garbage indices into downstream logic.
Agent Prompt
### Issue description
Several `eqn_idx` members (e.g., `stress`, `xi`, `B`, `int_en`, `species`, and scalars like `c`, `damage`, `psi`) are conditionally assigned, but are read unconditionally later (copied into `strxb/strxe/...` and written to `indices.dat`). This reads undefined values when the related feature is disabled.

### Issue Context
- In `m_global_parameters` (simulation/pre_process/post_process), optional ranges are only set in feature-gated blocks.
- Later code unconditionally does `strxb = eqn_idx%stress%beg` etc.
- `m_data_output` (pre_process) unconditionally calls `write_range(eqn_idx%stress%beg, ...)`, `write_range(eqn_idx%xi%beg, ...)`, etc.

### Fix Focus Areas
- src/simulation/m_global_parameters.fpp[1050-1105]
- src/simulation/m_global_parameters.fpp[1187-1206]
- src/pre_process/m_global_parameters.fpp[730-806]
- src/pre_process/m_data_output.fpp[641-652]

### What to change
1. At the start of the equation-index construction routine in each target’s `m_global_parameters`, explicitly initialize all `eqn_idx` members to a known inactive state:
   - Set every `int_bounds_info` range’s `%beg`/`%end` to `0`.
   - Set scalar indices like `E`, `n`, `gamma`, `pi_inf`, `c`, `damage`, `psi` to `0` (or the established sentinel if the codebase uses one consistently).
2. Only then compute/overwrite the active indices under feature flags.
3. Optionally encapsulate this in a small helper like `call s_reset_eqn_idx(eqn_idx)` to avoid duplicated initialization across targets.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

- Add GPU_UPDATE for bc_x/y/z%beg/end so CBC device kernels see correct
  BC codes (was broken: old code extracted to scalars + updated, new code
  accessed struct members that were never synced to device)
- Add matching @:DEALLOCATE/@deallocate for qbmm_idx%rs/vs/ps/ms/moms
  in s_finalize_global_parameters_module for all three targets
- Remove GPU_DECLARE(create='[qbmm_idx]'): struct has allocatable members
  and is never accessed directly on device; members are always copied to
  local arrays before GPU use
- Remove redundant eqn_idx%n from secondary GPU_UPDATE (already covered
  by full eqn_idx struct update in s_initialize_global_parameters_module)
- Remove stale claude-code-review.yml from repo root (live copy is in
  .github/workflows/)
Single-line 'if (qbmm) @:DEALLOCATE(...)' is invalid because the macro
expands to multiple statements. Use explicit then/end if block instead.
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 10, 2026

Codecov Report

❌ Patch coverage is 64.01985% with 290 lines in your changes missing coverage. Please review.
✅ Project coverage is 64.90%. Comparing base (ec94064) to head (6737414).

Files with missing lines Patch % Lines
src/pre_process/m_global_parameters.fpp 65.21% 38 Missing and 2 partials ⚠️
src/post_process/m_global_parameters.fpp 65.78% 37 Missing and 2 partials ⚠️
src/simulation/m_riemann_solvers.fpp 63.82% 34 Missing ⚠️
src/pre_process/m_assign_variables.fpp 25.00% 27 Missing ⚠️
src/simulation/m_data_output.fpp 10.71% 24 Missing and 1 partial ⚠️
src/simulation/m_global_parameters.fpp 70.73% 24 Missing ⚠️
src/post_process/m_derived_variables.fpp 25.80% 23 Missing ⚠️
src/post_process/m_data_output.fpp 0.00% 16 Missing ⚠️
src/simulation/m_cbc.fpp 52.63% 9 Missing ⚠️
src/common/m_boundary_common.fpp 12.50% 3 Missing and 4 partials ⚠️
... and 13 more
Additional details and impacted files
@@           Coverage Diff           @@
##           master    #1365   +/-   ##
=======================================
  Coverage   64.90%   64.90%           
=======================================
  Files          70       70           
  Lines       18254    18259    +5     
  Branches     1508     1505    -3     
=======================================
+ Hits        11847    11851    +4     
- Misses       5444     5448    +4     
+ Partials      963      960    -3     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

E_idx, stress_idx%beg, c_idx, B_idx%beg/end were renamed as part of
the eqn_idx refactor but QPVF_IDX_VARS in case.py (used to generate
Fortran index expressions for case-optimization builds) was not updated,
causing pre_process build failures in case-opt CI jobs.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Updated storage for equation indices and boundary condition types

1 participant