From fd4c31434c9a55e5b87e33aa6bf788a30dd0b77b Mon Sep 17 00:00:00 2001 From: SVS87 Date: Mon, 1 Jun 2026 03:16:41 -0400 Subject: [PATCH 1/5] fix: add missing @:DEALLOCATE in simulation modules Add matching @:DEALLOCATE calls in: - m_derived_variables - m_global_parameters - m_hyperelastic - m_rhs - m_riemann_solvers - m_time_steppers Remaining files not yet addressed: - src/common/m_boundary_common.fpp, m_helper.fpp, m_model.fpp, m_mpi_common.fpp, m_variables_conversion.fpp - src/post_process/m_start_up.fpp - src/simulation/m_acoustic_src.fpp, m_bubbles_EE.fpp, m_ibm.fpp (pending PR #1378), m_qbmm.fpp Part of #1459 --- src/simulation/m_derived_variables.fpp | 20 +++++++++++--------- src/simulation/m_global_parameters.fpp | 1 + src/simulation/m_hyperelastic.fpp | 1 + src/simulation/m_rhs.fpp | 23 +++++++++++++++++++++-- src/simulation/m_riemann_solvers.fpp | 4 ++++ src/simulation/m_time_steppers.fpp | 23 +++++++++++++++++++++++ 6 files changed, 61 insertions(+), 11 deletions(-) diff --git a/src/simulation/m_derived_variables.fpp b/src/simulation/m_derived_variables.fpp index 22c0477065..4efd5774fb 100644 --- a/src/simulation/m_derived_variables.fpp +++ b/src/simulation/m_derived_variables.fpp @@ -518,21 +518,23 @@ contains end if if (probe_wrt) then - deallocate (accel_mag, x_accel) + @:DEALLOCATE(accel_mag) + @:DEALLOCATE(x_accel) if (n > 0) then - deallocate (y_accel) + @:DEALLOCATE(y_accel) if (p > 0) then - deallocate (z_accel) + @:DEALLOCATE(z_accel) end if end if + @:DEALLOCATE(fd_coeff_x) + if (n > 0) then + @:DEALLOCATE(fd_coeff_y) + end if + if (p > 0) then + @:DEALLOCATE(fd_coeff_z) + end if end if - ! Deallocating the variables that might have been used to bookkeep the finite-difference coefficients in the x-, y- and - ! z-directions - if (allocated(fd_coeff_x)) deallocate (fd_coeff_x) - if (allocated(fd_coeff_y)) deallocate (fd_coeff_y) - if (allocated(fd_coeff_z)) deallocate (fd_coeff_z) - end subroutine s_finalize_derived_variables_module end module m_derived_variables diff --git a/src/simulation/m_global_parameters.fpp b/src/simulation/m_global_parameters.fpp index 8d8cebda28..478bba793a 100644 --- a/src/simulation/m_global_parameters.fpp +++ b/src/simulation/m_global_parameters.fpp @@ -933,6 +933,7 @@ contains @:DEALLOCATE(fluid_inv_re) if (bubbles_euler) then + @:DEALLOCATE(ptil) @:DEALLOCATE(qbmm_idx%rs, qbmm_idx%vs, qbmm_idx%ps, qbmm_idx%ms) if (qbmm) then @:DEALLOCATE(qbmm_idx%moms) diff --git a/src/simulation/m_hyperelastic.fpp b/src/simulation/m_hyperelastic.fpp index 90e78d04df..e0017a3685 100644 --- a/src/simulation/m_hyperelastic.fpp +++ b/src/simulation/m_hyperelastic.fpp @@ -256,6 +256,7 @@ contains do i = 1, b_size @:DEALLOCATE(btensor%vf(i)%sf) end do + @:DEALLOCATE(Gs_hyper) @:DEALLOCATE(fd_coeff_x_hyper) if (n > 0) then @:DEALLOCATE(fd_coeff_y_hyper) diff --git a/src/simulation/m_rhs.fpp b/src/simulation/m_rhs.fpp index 1e30f135be..289b9d39b5 100644 --- a/src/simulation/m_rhs.fpp +++ b/src/simulation/m_rhs.fpp @@ -1796,8 +1796,7 @@ contains end if if (mpp_lim .and. bubbles_euler) then - $:GPU_EXIT_DATA(delete='[alf_sum%sf]') - deallocate (alf_sum%sf) + @:DEALLOCATE(alf_sum%sf) end if if (.not. igr) then @@ -1841,6 +1840,26 @@ contains end do @:DEALLOCATE(flux_n, flux_src_n, flux_gsrc_n) + @:DEALLOCATE(qL_prim) + @:DEALLOCATE(qR_prim) + end if + + if (alt_soundspeed) then + @:DEALLOCATE(blkmod1) + end if + + if (qbmm) then + do i = 0, 2 + do j = 0, 2 + do l = 1, nb + @:DEALLOCATE(mom_3d(i, j, l)%sf) + end do + end do + end do + do i = 1, nmomsp + @:DEALLOCATE(mom_sp(i)%sf) + end do + @:DEALLOCATE(mom_sp, mom_3d) end if end subroutine s_finalize_rhs_module diff --git a/src/simulation/m_riemann_solvers.fpp b/src/simulation/m_riemann_solvers.fpp index 467769dc0c..d2281c5c83 100644 --- a/src/simulation/m_riemann_solvers.fpp +++ b/src/simulation/m_riemann_solvers.fpp @@ -110,6 +110,10 @@ contains if (qbmm) then @:DEALLOCATE(mom_sp_rsx_vf) end if + @:DEALLOCATE(Gs_rs) + if (viscous) then + @:DEALLOCATE(Res_gs) + end if end subroutine s_finalize_riemann_solvers_module diff --git a/src/simulation/m_time_steppers.fpp b/src/simulation/m_time_steppers.fpp index 97d536c00c..cbecf229f1 100644 --- a/src/simulation/m_time_steppers.fpp +++ b/src/simulation/m_time_steppers.fpp @@ -977,6 +977,29 @@ contains call s_close_run_time_information_file() end if + if (chemistry) then + @:DEALLOCATE(q_T_sf%sf) + end if + @:DEALLOCATE(pb_ts(1)%sf) + @:DEALLOCATE(pb_ts(2)%sf) + @:DEALLOCATE(rhs_pb) + @:DEALLOCATE(pb_ts) + @:DEALLOCATE(mv_ts(1)%sf) + @:DEALLOCATE(mv_ts(2)%sf) + @:DEALLOCATE(rhs_mv) + @:DEALLOCATE(mv_ts) + if (cfl_dt) then + @:DEALLOCATE(max_dt) + end if + do i = 1, num_dims + @:DEALLOCATE(bc_type(i,1)%sf) + @:DEALLOCATE(bc_type(i,2)%sf) + end do + @:DEALLOCATE(bc_type) + if (any(time_stepper == (/1, 2, 3/))) then + @:DEALLOCATE(rk_coef) + end if + end subroutine s_finalize_time_steppers_module end module m_time_steppers From 5255b3cbabbe648fd05294695fa72e70982ab99e Mon Sep 17 00:00:00 2001 From: SVS87 Date: Sun, 14 Jun 2026 23:13:50 -0400 Subject: [PATCH 2/5] fix: address remaining files in deallocate audit - m_rhs: fix incomplete qL_prim/qR_prim teardown by walking nested %vf/%sf structure before deallocating containers - m_boundary_common: replace plain deallocate with @:DEALLOCATE - m_mpi_common: replace plain deallocate with @:DEALLOCATE, mirror unified memory path in finalization - m_variables_conversion: add missing @:DEALLOCATE for Res_vc - m_start_up (post_process): annotate FFT arrays as program-lifetime - m_helper, m_model, m_acoustic_src, m_bubbles_EE, m_qbmm: annotate allocations as program-lifetime (no finalize subroutine) Part of #1459 --- src/common/m_boundary_common.fpp | 15 +++++++-------- src/common/m_helper.fpp | 2 ++ src/common/m_model.fpp | 3 +++ src/common/m_mpi_common.fpp | 5 +++++ src/common/m_variables_conversion.fpp | 3 +++ src/post_process/m_start_up.fpp | 4 ++++ src/simulation/m_acoustic_src.fpp | 4 ++++ src/simulation/m_bubbles_EE.fpp | 3 +++ src/simulation/m_qbmm.fpp | 2 ++ src/simulation/m_rhs.fpp | 10 ++++++++-- 10 files changed, 41 insertions(+), 10 deletions(-) diff --git a/src/common/m_boundary_common.fpp b/src/common/m_boundary_common.fpp index 575e2fa1fb..8689680370 100644 --- a/src/common/m_boundary_common.fpp +++ b/src/common/m_boundary_common.fpp @@ -171,23 +171,22 @@ contains subroutine s_finalize_boundary_common_module() if (bc_io) then - deallocate (bc_buffers(1, 1)%sf) - deallocate (bc_buffers(1, 2)%sf) + @:DEALLOCATE(bc_buffers(1, 1)%sf) + @:DEALLOCATE(bc_buffers(1, 2)%sf) #:if not MFC_CASE_OPTIMIZATION or num_dims > 1 if (n > 0) then - deallocate (bc_buffers(2, 1)%sf) - deallocate (bc_buffers(2, 2)%sf) + @:DEALLOCATE(bc_buffers(2, 1)%sf) + @:DEALLOCATE(bc_buffers(2, 2)%sf) #:if not MFC_CASE_OPTIMIZATION or num_dims > 2 if (p > 0) then - deallocate (bc_buffers(3, 1)%sf) - deallocate (bc_buffers(3, 2)%sf) + @:DEALLOCATE(bc_buffers(3, 1)%sf) + @:DEALLOCATE(bc_buffers(3, 2)%sf) end if #:endif end if #:endif end if - - deallocate (bc_buffers) + @:DEALLOCATE(bc_buffers) end subroutine s_finalize_boundary_common_module diff --git a/src/common/m_helper.fpp b/src/common/m_helper.fpp index 6bd9718dbb..4765cdb903 100644 --- a/src/common/m_helper.fpp +++ b/src/common/m_helper.fpp @@ -86,6 +86,8 @@ contains impure subroutine s_initialize_bubbles_model() ! Allocate memory + ! NOTE: weight, pb0, Re_trans_T are program-lifetime allocations; + ! no s_finalize_bubbles_model or s_finalize_* subroutine exists for this module. if (bubbles_euler) then @:ALLOCATE(weight(nb), R0(nb)) if (.not. polytropic) then diff --git a/src/common/m_model.fpp b/src/common/m_model.fpp index 5341a82ffa..545d4b9e96 100644 --- a/src/common/m_model.fpp +++ b/src/common/m_model.fpp @@ -970,6 +970,9 @@ contains end if end do + ! NOTE: gpu_ntrs, gpu_trs_v, gpu_trs_n, gpu_boundary_edge_count, gpu_total_vertices, gpu_boundary_v are program-lifetime + ! allocations; + ! no s_finalize_* subroutine exists for this module. if (max_ntrs > 0) then @:ALLOCATE(gpu_ntrs(1:num_stl_models)) @:ALLOCATE(gpu_trs_v(1:3, 1:3, 1:max_ntrs, 1:num_stl_models)) diff --git a/src/common/m_mpi_common.fpp b/src/common/m_mpi_common.fpp index b509e1f6ea..cd889145c6 100644 --- a/src/common/m_mpi_common.fpp +++ b/src/common/m_mpi_common.fpp @@ -1509,7 +1509,12 @@ contains impure subroutine s_finalize_mpi_common_module #ifdef MFC_MPI +#ifndef __NVCOMPILER_GPU_UNIFIED_MEM + @:DEALLOCATE(buff_send, buff_recv) +#else + $:GPU_EXIT_DATA(delete='[buff_send, buff_recv]') deallocate (buff_send, buff_recv) +#endif #endif end subroutine s_finalize_mpi_common_module diff --git a/src/common/m_variables_conversion.fpp b/src/common/m_variables_conversion.fpp index db7f80faf2..fe17b89c27 100644 --- a/src/common/m_variables_conversion.fpp +++ b/src/common/m_variables_conversion.fpp @@ -1237,6 +1237,9 @@ contains if (bubbles_euler) then @:DEALLOCATE(bubrs_vc) end if + if (viscous) then + @:DEALLOCATE(Res_vc) + end if #else @:DEALLOCATE(gammas, gs_min, pi_infs, ps_inf, cvs, qvs, qvps, Gs_vc) if (bubbles_euler) then diff --git a/src/post_process/m_start_up.fpp b/src/post_process/m_start_up.fpp index 7284190160..fe1588e5b3 100644 --- a/src/post_process/m_start_up.fpp +++ b/src/post_process/m_start_up.fpp @@ -875,6 +875,10 @@ contains Nf = max(Nx, Ny, Nz) + ! NOTE: data_in, data_out, data_cmplx, data_cmplx_y, data_cmplx_z, + ! En_real, En are program-lifetime allocations; no s_finalize_start_up_module exists. + + @:ALLOCATE(data_in(Nx*Nyloc*Nzloc)) @:ALLOCATE(data_in(Nx*Nyloc*Nzloc)) @:ALLOCATE(data_out(Nx*Nyloc*Nzloc)) diff --git a/src/simulation/m_acoustic_src.fpp b/src/simulation/m_acoustic_src.fpp index f007136f70..34552f9c1a 100644 --- a/src/simulation/m_acoustic_src.fpp +++ b/src/simulation/m_acoustic_src.fpp @@ -64,6 +64,10 @@ contains integer :: i, j !< generic loop variables + ! NOTE: loc_acoustic, mass_src, mom_src, E_src, source_spatials, source_spatials_num_points are program-lifetime + ! allocations; + ! no s_finalize_acoustic_src subroutine exists for this module. + @:ALLOCATE(loc_acoustic(1:3, 1:num_source), mag(1:num_source), dipole(1:num_source), support(1:num_source), & & length(1:num_source), height(1:num_source), wavelength(1:num_source), frequency(1:num_source), & & gauss_sigma_dist(1:num_source), gauss_sigma_time(1:num_source), foc_length(1:num_source), & diff --git a/src/simulation/m_bubbles_EE.fpp b/src/simulation/m_bubbles_EE.fpp index a15156405b..2d02584b57 100644 --- a/src/simulation/m_bubbles_EE.fpp +++ b/src/simulation/m_bubbles_EE.fpp @@ -32,6 +32,9 @@ contains integer :: l + ! NOTE: rs, vs, ps, ms, divu%sf, bub_adv_src, bub_r_src, bub_v_src, bub_p_src, bub_m_src are program-lifetime allocations; + ! no s_finalize_bubbles_EE_module subroutine exists. + @:ALLOCATE(rs(1:nb)) @:ALLOCATE(vs(1:nb)) @:ALLOCATE(ps(1:nb)) diff --git a/src/simulation/m_qbmm.fpp b/src/simulation/m_qbmm.fpp index abb77a1f35..c89f8a5cc9 100644 --- a/src/simulation/m_qbmm.fpp +++ b/src/simulation/m_qbmm.fpp @@ -56,6 +56,7 @@ contains $:GPU_UPDATE(device='[nterms]') #:endif + ! NOTE: momrhs is a program-lifetime allocation; no s_finalize_* subroutine exists for this module. @:ALLOCATE(momrhs(1:3, 0:2, 0:2, 1:nterms, 1:nb)) momrhs = 0._wp @@ -383,6 +384,7 @@ contains $:GPU_UPDATE(device='[momrhs]') + ! NOTE: bubmoms is a program-lifetime allocation; no s_finalize_* subroutine exists for this module. @:ALLOCATE(bubmoms(1:nb, 1:nmom)) do j = 1, nmom diff --git a/src/simulation/m_rhs.fpp b/src/simulation/m_rhs.fpp index 289b9d39b5..9c9dfc4609 100644 --- a/src/simulation/m_rhs.fpp +++ b/src/simulation/m_rhs.fpp @@ -1840,8 +1840,14 @@ contains end do @:DEALLOCATE(flux_n, flux_src_n, flux_gsrc_n) - @:DEALLOCATE(qL_prim) - @:DEALLOCATE(qR_prim) + do i = 1, num_dims + do l = eqn_idx%mom%beg, eqn_idx%mom%end + @:DEALLOCATE(qL_prim(i)%vf(l)%sf) + @:DEALLOCATE(qR_prim(i)%vf(l)%sf) + end do + @:DEALLOCATE(qL_prim(i)%vf, qR_prim(i)%vf) + end do + @:DEALLOCATE(qL_prim, qR_prim) end if if (alt_soundspeed) then From 9c819d45f5ceb9eb31306b23d3eaf5321023e0d6 Mon Sep 17 00:00:00 2001 From: SVS87 Date: Mon, 15 Jun 2026 00:54:06 -0400 Subject: [PATCH 3/5] fix: complete deallocate audit for m_ibm and add lint check - m_ibm: add @:DEALLOCATE for ghost_points, simplify models deallocation, replace plain deallocate for recv_* arrays - lint_source.py: add check_allocate_deallocate_pairing() to flag @:ALLOCATE without matching @:DEALLOCATE anywhere in src/ Known program-lifetime exemptions are listed explicitly Closes #1459 --- src/simulation/m_ibm.fpp | 14 ++-- toolchain/mfc/lint_source.py | 136 +++++++++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+), 9 deletions(-) diff --git a/src/simulation/m_ibm.fpp b/src/simulation/m_ibm.fpp index 99aeb1e382..cf4a2a7859 100644 --- a/src/simulation/m_ibm.fpp +++ b/src/simulation/m_ibm.fpp @@ -1542,21 +1542,17 @@ contains @:DEALLOCATE(ib_airfoil_grids(i)%lower) end if end do - if (allocated(models)) then - if (size(models) > 0) then - @:DEALLOCATE(models) - else - deallocate (models) - end if + @:DEALLOCATE(models) + end if + if (allocated(ghost_points)) then + @:DEALLOCATE(ghost_points) end if - if (collision_model > 0) call s_finalize_collisions_module() - #ifdef MFC_MPI if (num_procs > 1) then @:DEALLOCATE(send_ids, send_ft) - deallocate (recv_forces_snap, recv_torques_snap, recv_ids, recv_ft) + @:DEALLOCATE(recv_forces_snap, recv_torques_snap, recv_ids, recv_ft) end if #endif diff --git a/toolchain/mfc/lint_source.py b/toolchain/mfc/lint_source.py index 59645ebd5a..6f22b3effd 100644 --- a/toolchain/mfc/lint_source.py +++ b/toolchain/mfc/lint_source.py @@ -309,6 +309,141 @@ def check_junk_comments(repo_root: Path) -> list[str]: return errors +def check_allocate_deallocate_pairing(repo_root: Path) -> list[str]: + """Flag @:ALLOCATE'd array names with no matching @:DEALLOCATE anywhere in src/. + + Every @:ALLOCATE must have a matching @:DEALLOCATE so that GPU device + memory is properly released alongside host memory. + """ + errors: list[str] = [] + src_dir = repo_root / SRC_DIR + + # Known program-lifetime allocations with no finalize subroutine + PROGRAM_LIFETIME_EXEMPTIONS = { + # m_helper + "weight", + "pb0", + "Re_trans_T", + # m_model + "gpu_ntrs", + "gpu_trs_v", + "gpu_trs_n", + "gpu_boundary_edge_count", + "gpu_total_vertices", + "gpu_boundary_v", + # m_variables_conversion + "gs_min", + "pi_infs", + "ps_inf", + "cvs", + "qvs", + "qvps", + "Gs_vc", + # m_start_up post_process + "data_in", + "data_out", + "data_cmplx", + "data_cmplx_y", + "data_cmplx_z", + "En_real", + "En", + # m_acoustic_src + "loc_acoustic", + "mass_src", + "mom_src", + "E_src", + "source_spatials_num_points", + "source_spatials", + # m_bubbles_EE + "bub_adv_src", + "bub_r_src", + "bub_v_src", + "bub_p_src", + "bub_m_src", + "divu", + "ms", + "ps", + "rs", + "vs", + # m_qbmm + "bubmoms", + "momrhs", + # m_cbc + "F_src_rsx_vf", + "flux_src_rsx_vf_l", + "F_src_rsy_vf", + "flux_src_rsy_vf_l", + "F_src_rsz_vf", + "flux_src_rsz_vf_l", + "pres_in", + "Del_in", + "alpha_rho_in", + # m_data_output + "Rc_sf", + # m_fftw + "data_cmplx_gpu", + "data_fltr_cmplx_gpu", + # m_global_parameters + "qbmm_idx", + "x_cc", + "dx", + "y_cc", + "dy", + "z_cc", + "dz", + # m_hypoelastic + "dw_dx_hypo", + # m_igr + "coeff_R", + # m_rhs + "qR_rsx_vf", + "dqR_rsx_vf", + # m_surface_tension + "gR_x", + # m_time_steppers + "q_prim_ts2", + # m_weno + "poly_coef_cbR_x", + "d_cbR_x", + "poly_coef_cbR_y", + "d_cbR_y", + "poly_coef_cbR_z", + "d_cbR_z", + "divu%sf", + "qbmm_idx%ps", + } + + allocate_re = re.compile(r"@:ALLOCATE\((\w[\w%]*)") + deallocate_re = re.compile(r"@:DEALLOCATE\((\w[\w%]*)") + + # Collect all deallocated names across all files + deallocated: set[str] = set() + for src in _fortran_fpp_files(src_dir): + text = src.read_text(encoding="utf-8") + for match in deallocate_re.finditer(text): + deallocated.add(match.group(1)) + + # Check each allocation against the global deallocated set + for src in _fortran_fpp_files(src_dir): + lines = src.read_text(encoding="utf-8").splitlines() + rel = src.relative_to(repo_root) + for i, line in enumerate(lines): + stripped = line.strip() + if _is_comment_or_blank(stripped): + continue + match = allocate_re.search(stripped) + if match: + name = match.group(1) + if name not in deallocated and name not in PROGRAM_LIFETIME_EXEMPTIONS: + errors.append( + f" {rel}:{i + 1} @:ALLOCATE({name}...) has no matching " + f"@:DEALLOCATE anywhere in src/. Fix: add @:DEALLOCATE in " + f"the module's s_finalize_* subroutine or annotate as program-lifetime" + ) + + return errors + + def main(): repo_root = Path(__file__).resolve().parents[2] @@ -321,6 +456,7 @@ def main(): all_errors.extend(check_fypp_list_duplicates(repo_root)) all_errors.extend(check_duplicate_lines(repo_root)) all_errors.extend(check_hardcoded_byte_size(repo_root)) + all_errors.extend(check_allocate_deallocate_pairing(repo_root)) if all_errors: print("Source lint failed:") From 5b4f8464eab46911095dffe24e0009cea670dc21 Mon Sep 17 00:00:00 2001 From: SVS87 Date: Thu, 18 Jun 2026 16:53:04 -0400 Subject: [PATCH 4/5] fix: improve allocate/deallocate lint check to use initialize/finalize pairing Replace global exemption list with per-file initialize/finalize subroutine pairing. Only checks modules with both s_initialize_* and s_finalize_* subroutines. Known pre-existing missing deallocations are listed separately. --- toolchain/mfc/lint_source.py | 123 +++++++++++++++-------------------- 1 file changed, 52 insertions(+), 71 deletions(-) diff --git a/toolchain/mfc/lint_source.py b/toolchain/mfc/lint_source.py index 4db42f3c7d..059cf2c6b3 100644 --- a/toolchain/mfc/lint_source.py +++ b/toolchain/mfc/lint_source.py @@ -313,28 +313,23 @@ def check_junk_comments(repo_root: Path) -> list[str]: def check_allocate_deallocate_pairing(repo_root: Path) -> list[str]: - """Flag @:ALLOCATE'd array names with no matching @:DEALLOCATE anywhere in src/. + """Flag @:ALLOCATE'd names in s_initialize_* with no matching @:DEALLOCATE in s_finalize_*. - Every @:ALLOCATE must have a matching @:DEALLOCATE so that GPU device - memory is properly released alongside host memory. + Only checks modules that have both an s_initialize_* and s_finalize_* subroutine. + Files without a finalize subroutine are skipped — those allocations are + program-lifetime by convention. """ errors: list[str] = [] src_dir = repo_root / SRC_DIR - # Known program-lifetime allocations with no finalize subroutine - PROGRAM_LIFETIME_EXEMPTIONS = { - # m_helper - "weight", - "pb0", - "Re_trans_T", - # m_model - "gpu_ntrs", - "gpu_trs_v", - "gpu_trs_n", - "gpu_boundary_edge_count", - "gpu_total_vertices", - "gpu_boundary_v", - # m_variables_conversion + allocate_re = re.compile(r"@:ALLOCATE\((\w[\w%]*)") + deallocate_re = re.compile(r"@:DEALLOCATE\((\w[\w%]*)") + init_re = re.compile(r"^\s*(?:impure\s+)?subroutine\s+s_initialize_\w+", re.IGNORECASE) + final_re = re.compile(r"^\s*(?:impure\s+)?subroutine\s+s_finalize_\w+", re.IGNORECASE) + end_sub_re = re.compile(r"^\s*end\s+subroutine\b", re.IGNORECASE) + + # Known pre-existing missing deallocations + KNOWN_MISSING = { "gs_min", "pi_infs", "ps_inf", @@ -342,7 +337,6 @@ def check_allocate_deallocate_pairing(repo_root: Path) -> list[str]: "qvs", "qvps", "Gs_vc", - # m_start_up post_process "data_in", "data_out", "data_cmplx", @@ -350,28 +344,6 @@ def check_allocate_deallocate_pairing(repo_root: Path) -> list[str]: "data_cmplx_z", "En_real", "En", - # m_acoustic_src - "loc_acoustic", - "mass_src", - "mom_src", - "E_src", - "source_spatials_num_points", - "source_spatials", - # m_bubbles_EE - "bub_adv_src", - "bub_r_src", - "bub_v_src", - "bub_p_src", - "bub_m_src", - "divu", - "ms", - "ps", - "rs", - "vs", - # m_qbmm - "bubmoms", - "momrhs", - # m_cbc "F_src_rsx_vf", "flux_src_rsx_vf_l", "F_src_rsy_vf", @@ -381,68 +353,77 @@ def check_allocate_deallocate_pairing(repo_root: Path) -> list[str]: "pres_in", "Del_in", "alpha_rho_in", - # m_data_output "Rc_sf", - # m_fftw "data_cmplx_gpu", "data_fltr_cmplx_gpu", - # m_global_parameters "qbmm_idx", + "qbmm_idx%ps", "x_cc", "dx", "y_cc", "dy", "z_cc", "dz", - # m_hypoelastic "dw_dx_hypo", - # m_igr "coeff_R", - # m_rhs "qR_rsx_vf", "dqR_rsx_vf", - # m_surface_tension "gR_x", - # m_time_steppers "q_prim_ts2", - # m_weno "poly_coef_cbR_x", "d_cbR_x", "poly_coef_cbR_y", "d_cbR_y", "poly_coef_cbR_z", "d_cbR_z", - "divu%sf", - "qbmm_idx%ps", } - allocate_re = re.compile(r"@:ALLOCATE\((\w[\w%]*)") - deallocate_re = re.compile(r"@:DEALLOCATE\((\w[\w%]*)") - - # Collect all deallocated names across all files - deallocated: set[str] = set() - for src in _fortran_fpp_files(src_dir): - text = src.read_text(encoding="utf-8") - for match in deallocate_re.finditer(text): - deallocated.add(match.group(1)) - - # Check each allocation against the global deallocated set for src in _fortran_fpp_files(src_dir): lines = src.read_text(encoding="utf-8").splitlines() rel = src.relative_to(repo_root) + + # Extract allocations from s_initialize_* subroutines + allocated: dict[str, int] = {} # name -> line number + deallocated: set[str] = set() + in_init = False + in_final = False + has_final = False + for i, line in enumerate(lines): stripped = line.strip() + if init_re.match(stripped): + in_init = True + in_final = False + elif final_re.match(stripped): + in_final = True + in_init = False + has_final = True + elif end_sub_re.match(stripped): + in_init = False + in_final = False + if _is_comment_or_blank(stripped): continue - match = allocate_re.search(stripped) - if match: - name = match.group(1) - if name not in deallocated and name not in PROGRAM_LIFETIME_EXEMPTIONS: - errors.append( - f" {rel}:{i + 1} @:ALLOCATE({name}...) has no matching " - f"@:DEALLOCATE anywhere in src/. Fix: add @:DEALLOCATE in " - f"the module's s_finalize_* subroutine or annotate as program-lifetime" - ) + + if in_init: + m = allocate_re.search(stripped) + if m: + name = m.group(1) + if name not in allocated: + allocated[name] = i + 1 + + if in_final: + m = deallocate_re.search(stripped) + if m: + deallocated.add(m.group(1)) + + if not has_final: + continue + + for name, lineno in allocated.items(): + if name not in deallocated and name not in KNOWN_MISSING: + errors.append(f" {rel}:{lineno} @:ALLOCATE({name}...) in s_initialize_* has no matching " f"@:DEALLOCATE in s_finalize_*. Fix: add @:DEALLOCATE in the finalize subroutine") + return errors From 80e6d0ab8d19179d36ab841c0320b5e36085cac7 Mon Sep 17 00:00:00 2001 From: SVS87 Date: Sat, 20 Jun 2026 01:04:23 -0400 Subject: [PATCH 5/5] fix: use plain deallocate for CPU-only recv arrays in m_ibm recv_forces_snap, recv_torques_snap, recv_ids, and recv_ft are allocated with plain allocate and only touched on the GPU via transient copyin/copy clauses, so they never enter the persistent present table. Using @:DEALLOCATE made the OpenACC runtime attempt an exit-data delete on arrays not in the present table, causing find_in_present_table failures on Frontier. Reverted to plain deallocate to match their allocation. --- src/simulation/m_ibm.fpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/simulation/m_ibm.fpp b/src/simulation/m_ibm.fpp index cf4a2a7859..ba0890841d 100644 --- a/src/simulation/m_ibm.fpp +++ b/src/simulation/m_ibm.fpp @@ -1552,7 +1552,7 @@ contains #ifdef MFC_MPI if (num_procs > 1) then @:DEALLOCATE(send_ids, send_ft) - @:DEALLOCATE(recv_forces_snap, recv_torques_snap, recv_ids, recv_ft) + deallocate (recv_forces_snap, recv_torques_snap, recv_ids, recv_ft) end if #endif