Skip to content

Commit c27b3b1

Browse files
committed
Merge master into ci-phoenix-bench-single-node
Conflict in submit-slurm-job.sh: master (#1832) split partition selection by job_type, keeping the single-partition bench selector behind BENCH_GPU_PARTITION. This branch removes that selector entirely (bench-pair.sh benches master and PR in one job on the same GPUs), so the job_type branch is dead code here. Took this branch's unconditional partition list; select-gpu-partition.sh stays deleted. Claude-Session: https://claude.ai/code/session_01G77jhrA4JPDz5TqJzt8ACC
2 parents 0d560f4 + 5829daf commit c27b3b1

13 files changed

Lines changed: 392 additions & 36 deletions

src/common/m_derived_types.fpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -526,11 +526,12 @@ module m_derived_types
526526
!> Condensed-phase reactive-burn (programmed pressure detonation) parameters. The rate is
527527
!> dlambda/dt = k (1 - lambda) ((p - pign)/pref)^n, optionally scaled by exp(-ta/T) when ta > 0.
528528
type reactive_burn_parameters
529-
real(wp) :: k !< Rate coefficient [1/s]
530-
real(wp) :: pign !< Ignition pressure threshold [Pa]
531-
real(wp) :: pref !< Reference pressure for the pressure drive [Pa]
532-
real(wp) :: n !< Pressure-drive exponent
533-
real(wp) :: ta !< Activation temperature [K] (0 = pure pressure-driven; > 0 adds exp(-ta/T))
529+
real(wp) :: k !< Rate coefficient [1/s]
530+
real(wp) :: pign !< Ignition pressure threshold [Pa]
531+
real(wp) :: pref !< Reference pressure for the pressure drive [Pa]
532+
real(wp) :: n !< Pressure-drive exponent
533+
real(wp) :: ta !< Activation temperature [K] (0 = pure pressure-driven; > 0 adds exp(-ta/T))
534+
integer :: substeps !< Operator-split sub-steps per time step (0 = source added to the flow RHS)
534535
end type reactive_burn_parameters
535536
536537
!> Lagrangian bubble parameters

src/common/m_global_parameters_common.fpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,7 @@ contains
339339
rburn%pref = dflt_real
340340
rburn%n = dflt_real
341341
rburn%ta = 0._wp
342+
rburn%substeps = 0
342343

343344
! Case-optimization params: under case-opt these are compile-time constants in sim (skip assignment); in pre/post
344345
! MFC_CASE_OPTIMIZATION is always False so the block always executes there.

src/simulation/m_reactive_burn.fpp

Lines changed: 117 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,45 @@
1515
module m_reactive_burn
1616

1717
use m_global_parameters
18-
use m_variables_conversion, only: f_sg_thermal
18+
use m_variables_conversion, only: f_sg_thermal, s_compute_mixture_coefficients, f_pressure
1919

2020
implicit none
2121

22-
private; public :: s_compute_reactive_burn
22+
private; public :: s_compute_reactive_burn, s_reactive_burn_substep
2323

2424
contains
2525

26+
!> Programmed-burn rate dlambda/dt for one cell state. Both the RHS source and the operator-split integrator call this, so the
27+
!! rate law is stated once.
28+
!! @param pres Mixture pressure
29+
!! @param lambda Reaction progress, i.e. the product volume fraction
30+
!! @param alpha_rho_react Reactant partial density, for the optional Arrhenius factor
31+
!! @param alpha_react Reactant volume fraction, for the optional Arrhenius factor
32+
!! @param rate dlambda/dt; zero below the ignition pressure and once the reactant is spent
33+
subroutine s_burn_rate(pres, lambda, alpha_rho_react, alpha_react, rate)
34+
35+
$:GPU_ROUTINE(function_name='s_burn_rate', parallelism='[seq]', cray_inline=True)
36+
37+
real(wp), intent(in) :: pres, lambda, alpha_rho_react, alpha_react
38+
real(wp), intent(out) :: rate
39+
real(wp) :: drive
40+
41+
! Pressure-driven programmed burn: fires only behind the shock (p > rburn%pign).
42+
drive = (pres - rburn%pign)/rburn%pref
43+
if (drive > 0._wp .and. lambda < 1._wp) then
44+
rate = rburn%k*(1._wp - lambda)*drive**rburn%n
45+
! Optional Arrhenius dependence on the reactant phasic temperature from the stiffened-gas
46+
! EOS. rburn%ta = 0, the default, leaves the pure pressure-driven rate unchanged.
47+
if (rburn%ta > 0._wp) then
48+
rate = rate*exp(-rburn%ta/f_sg_thermal(pres, alpha_rho_react/max(alpha_react, sgm_eps), isentrope_n(1), &
49+
& isentrope_B(1), cvs(1)))
50+
end if
51+
else
52+
rate = 0._wp
53+
end if
54+
55+
end subroutine s_burn_rate
56+
2657
!> Add the programmed-burn reaction source to the continuity and volume-fraction RHS.
2758
!! @param rhs_vf Right-hand-side accumulator (inout)
2859
!! @param q_cons_vf Conserved variables (partial densities live here)
@@ -34,9 +65,9 @@ contains
3465
type(scalar_field), dimension(sys_size), intent(in) :: q_cons_vf, q_prim_vf
3566
type(int_bounds_info), dimension(1:3), intent(in) :: bounds
3667
integer :: x, y, z
37-
real(wp) :: rho, pres, lambda, rate, mdot, drive, T_r
68+
real(wp) :: rho, pres, lambda, rate, mdot
3869

39-
$:GPU_PARALLEL_LOOP(collapse=3, private='[rho, pres, lambda, rate, mdot, drive, T_r]', copyin='[bounds]')
70+
$:GPU_PARALLEL_LOOP(collapse=3, private='[rho, pres, lambda, rate, mdot]', copyin='[bounds]')
4071
do z = bounds(3)%beg, bounds(3)%end
4172
do y = bounds(2)%beg, bounds(2)%end
4273
do x = bounds(1)%beg, bounds(1)%end
@@ -45,20 +76,9 @@ contains
4576
pres = q_prim_vf(eqn_idx%E)%sf(x, y, z)
4677
lambda = q_prim_vf(eqn_idx%adv%beg + 1)%sf(x, y, z) ! reaction progress = product volume fraction
4778

48-
! pressure-driven programmed burn: fires only behind the shock (p > rburn%pign)
49-
drive = (pres - rburn%pign)/rburn%pref
50-
if (drive > 0._wp .and. lambda < 1._wp) then
51-
rate = rburn%k*(1._wp - lambda)*drive**rburn%n ! dlambda/dt
52-
53-
! Optional Arrhenius temperature dependence: rate *= exp(-rburn%ta/T_r), with T_r the
54-
! reactant phasic temperature from the stiffened-gas EOS T = (p + pi_inf)/((Gamma-1) rho cv).
55-
! rburn%ta = 0 (default) leaves the pure pressure-driven rate unchanged.
56-
if (rburn%ta > 0._wp) then
57-
T_r = f_sg_thermal(pres, q_cons_vf(eqn_idx%cont%beg)%sf(x, y, z)/q_prim_vf(eqn_idx%adv%beg)%sf(x, y, &
58-
& z), isentrope_n(1), isentrope_B(1), cvs(1))
59-
rate = rate*exp(-rburn%ta/T_r)
60-
end if
61-
79+
call s_burn_rate(pres, lambda, q_cons_vf(eqn_idx%cont%beg)%sf(x, y, z), q_prim_vf(eqn_idx%adv%beg)%sf(x, y, &
80+
& z), rate)
81+
if (rate > 0._wp) then
6282
mdot = rho*rate ! mass reactant -> product
6383

6484
! continuity: reactant loses mass, product gains it
@@ -76,4 +96,83 @@ contains
7696

7797
end subroutine s_compute_reactive_burn
7898

99+
!> Operator-split alternative to s_compute_reactive_burn, used when rburn%substeps > 0. The flow is frozen and the burn ODE is
100+
!! integrated over one time step in equal sub-steps, so the reaction time scale is decoupled from the acoustic CFL. The mixture
101+
!! pressure is re-evaluated from the frozen internal energy each sub-step, which is what carries the rate's own feedback: the
102+
!! coefficients move as the reactant becomes product.
103+
!! @param q_cons_vf Conserved variables, updated in place
104+
!! @param dtime Time step to integrate across
105+
!! @param bounds Interior cell bounds
106+
subroutine s_reactive_burn_substep(q_cons_vf, dtime, bounds)
107+
108+
type(scalar_field), dimension(sys_size), intent(inout) :: q_cons_vf
109+
real(wp), intent(in) :: dtime
110+
type(int_bounds_info), dimension(1:3), intent(in) :: bounds
111+
integer :: x, y, z, i, sub
112+
real(wp) :: rho, pres, lambda, rate
113+
real(wp) :: dt_sub, e_int, gamma_mix, pi_inf_mix, qv_mix
114+
real(wp) :: rho_mix, dlambda, dmass
115+
116+
! Bounded by num_fluids_max, not num_fluids: under case optimization num_fluids is a compile-time
117+
! constant that can be 1, and the reactant/product indices below are literal. The validator holds
118+
! reactive_burn to two fluids, so only the first two entries are ever used.
119+
real(wp), dimension(num_fluids_max) :: alpha_rho, alpha
120+
121+
dt_sub = dtime/real(rburn%substeps, wp)
122+
123+
$:GPU_PARALLEL_LOOP(collapse=3, private='[alpha_rho, alpha, rho, pres, lambda, rate, e_int, gamma_mix, pi_inf_mix, &
124+
& qv_mix, rho_mix, dlambda, dmass, i, sub]', copyin='[bounds, dt_sub]')
125+
do z = bounds(3)%beg, bounds(3)%end
126+
do y = bounds(2)%beg, bounds(2)%end
127+
do x = bounds(1)%beg, bounds(1)%end
128+
$:GPU_LOOP(parallelism='[seq]')
129+
do i = 1, num_fluids
130+
alpha_rho(i) = q_cons_vf(i + eqn_idx%cont%beg - 1)%sf(x, y, z)
131+
alpha(i) = q_cons_vf(i + eqn_idx%adv%beg - 1)%sf(x, y, z)
132+
end do
133+
rho = alpha_rho(1) + alpha_rho(2)
134+
135+
! Internal energy per unit volume is what the burn conserves: it moves mass and volume
136+
! between the phases, and the qv difference surfaces as pressure through the mixture EOS.
137+
e_int = q_cons_vf(eqn_idx%E)%sf(x, y, z)
138+
$:GPU_LOOP(parallelism='[seq]')
139+
do i = eqn_idx%mom%beg, eqn_idx%mom%end
140+
e_int = e_int - 0.5_wp*q_cons_vf(i)%sf(x, y, z)**2/rho
141+
end do
142+
143+
$:GPU_LOOP(parallelism='[seq]')
144+
do sub = 1, rburn%substeps
145+
lambda = alpha(2)
146+
call s_compute_mixture_coefficients(alpha_rho, alpha, rho_mix, gamma_mix, pi_inf_mix, qv_mix)
147+
pres = f_pressure(e_int, gamma_mix, pi_inf_mix, qv_mix)
148+
call s_burn_rate(pres, lambda, alpha_rho(1), alpha(1), rate)
149+
if (rate <= 0._wp) exit
150+
! A sub-step longer than the reaction time would carry the progress variable past one.
151+
! Stop it there and hand over the reactant's remaining mass in the same sub-step: capping
152+
! the two independently strands mass at zero volume, and the EOS divides one by the other.
153+
if (rate*dt_sub >= 1._wp - lambda) then
154+
dlambda = 1._wp - lambda
155+
dmass = alpha_rho(1)
156+
else
157+
dlambda = rate*dt_sub
158+
dmass = min(rho*dlambda, alpha_rho(1))
159+
end if
160+
alpha(1) = alpha(1) - dlambda
161+
alpha(2) = alpha(2) + dlambda
162+
alpha_rho(1) = alpha_rho(1) - dmass
163+
alpha_rho(2) = alpha_rho(2) + dmass
164+
end do
165+
166+
$:GPU_LOOP(parallelism='[seq]')
167+
do i = 1, num_fluids
168+
q_cons_vf(i + eqn_idx%cont%beg - 1)%sf(x, y, z) = alpha_rho(i)
169+
q_cons_vf(i + eqn_idx%adv%beg - 1)%sf(x, y, z) = alpha(i)
170+
end do
171+
end do
172+
end do
173+
end do
174+
$:END_GPU_PARALLEL_LOOP()
175+
176+
end subroutine s_reactive_burn_substep
177+
79178
end module m_reactive_burn

src/simulation/m_rhs.fpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -869,7 +869,9 @@ contains
869869
call nvtxEndRange
870870
end if
871871
872-
if (reactive_burn) then
872+
! With rburn%substeps > 0 the burn is integrated by operator splitting after the flow
873+
! update (s_reactive_burn_substep), not added to the flow RHS here.
874+
if (reactive_burn .and. rburn%substeps == 0) then
873875
call nvtxStartRange("RHS-REACTIVE-BURN")
874876
call s_compute_reactive_burn(rhs_vf, q_cons_qp%vf, q_prim_qp%vf, idwint)
875877
call nvtxEndRange

src/simulation/m_riemann_solver_hllc.fpp

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -839,17 +839,41 @@ contains
839839
! statement and private variable from the pure-fluid emission, keeping its body and directive
840840
! identical to the single kernel a build without hypoelasticity would compile. Sharing one kernel
841841
! pinned it at the GPU register ceiling for every HLLC user.
842+
! One source of truth for this kernel's private variables: both emissions of the shared body take
843+
! _hllc_s*, and only the hypoelastic one adds _hllc_e*. Two hand-written lists drifted apart once --
844+
! c_sum_Yi_Phi was private in one and shared in the other, which races under OpenMP offload.
845+
! Names are lists joined once, so no fragment carries a trailing separator to get wrong.
846+
#:set _hllc_s1 = ['i', 'j', 'k', 'l', 'q', 'T_L', 'T_R', 'vel_L_rms', 'vel_R_rms', 'pres_L', 'pres_R', &
847+
& 'rho_L', 'gamma_L', 'pi_inf_L', 'qv_L', 'rho_R', 'gamma_R']
848+
#:set _hllc_s2 = ['pi_inf_R', 'qv_R', 'alpha_L_sum', 'alpha_R_sum', 'E_L', 'E_R', 'MW_L', 'MW_R', &
849+
& 'R_gas_L', 'R_gas_R', 'Cp_L', 'Cp_R', 'Cv_L', 'Cv_R', 'c_sum_Yi_Phi']
850+
#:set _hllc_s3 = ['Gamm_L', 'Gamm_R', 'Y_L', 'Y_R', 'H_L', 'H_R', 'qv_avg', 'rho_avg', 'gamma_avg', &
851+
& 'H_avg', 'c_L', 'c_R', 'c_avg', 's_P', 's_M', 'xi_P', 'xi_M', 'xi_L']
852+
#:set _hllc_s4 = ['xi_R', 'xi_L_m1', 'xi_R_m1', 'Ms_L', 'Ms_R', 'pres_SL', 'pres_SR', 'vel_L', 'vel_R', &
853+
& 'Re_L', 'Re_R', 'alpha_L', 'alpha_R', 'alpha_rho_L', 'alpha_rho_R']
854+
#:set _hllc_s5 = ['alpha_lim_L', 'alpha_lim_R', 's_L', 's_R', 's_S', 'vel_avg_rms', 'pcorr', 'Ys_L', &
855+
& 'Ys_R', 'Xs_L', 'Xs_R', 'Gamma_iL', 'Gamma_iR', 'Cp_iL', 'Cp_iR']
856+
#:set _hllc_s6 = ['R_species', 'h_iL', 'h_iR']
857+
#:set _hllc_e1 = ['ptilde_L', 'ptilde_R', 'tau_e_L', 'tau_e_R', 'G_L', 'G_R', 'damage_L', 'damage_R', &
858+
& 'U_L', 'U_R', 'F_L', 'F_R', 'F_star_L', 'F_star_R', 'F_HLLC']
859+
#:set _hllc_e2 = ['u_n_HLLC', 'u_t_HLLC', 'u_t2_HLLC', 'pres_tot_L', 'pres_tot_R', 'u_n_L', 'u_n_R', &
860+
& 'u_t_L', 'u_t_R', 'u_t2_L', 'u_t2_R', 'tau_nn_L', 'tau_nn_R']
861+
#:set _hllc_e3 = ['tau_nt_L', 'tau_nt_R', 'tau_tt_L', 'tau_tt_R', 'tau_nt2_L', 'tau_nt2_R', 'tau_t2t2_L', &
862+
& 'tau_t2t2_R', 'tau_t1t2_L', 'tau_t1t2_R', 'tau_qq_L', 'tau_qq_R']
863+
#:set _hllc_e4 = ['p_face', 'tau_qq_face', 'A_L', 'A_R', 'denom_A', 'u_t_star', 'tau_nt_star', &
864+
& 'u_t2_star', 'tau_nt2_star', 'pres_tot_star', 'F_HLL', 'u_n_HLL_trace']
865+
#:set _hllc_e5 = ['u_t_HLL_trace', 'u_t2_HLL_trace', 'p_face_HLL', 'tau_qq_face_HLL', 'tau_nn_HLL', &
866+
& 'phi', 'Sigma_L', 'Sigma_R', 'dSigma', 'Sigma_ref', 'a_L_ref']
867+
#:set _hllc_e6 = ['a_R_ref', 'a_ref', 'du_t', 'dtau_nt', 'du_t2', 'dtau_nt2', 'sensor_ptot', 'sensor_vt', &
868+
& 'sensor_tnt', 'sensor_combined', 'idx_phys']
842869
#:if HYPO
843-
! Private list split across _hllc_p1/p2/p3 for Fypp line-length limits
844-
#:set _hllc_p1 = '[i, j, k, l, q, T_L, T_R, vel_L_rms, vel_R_rms, pres_L, pres_R, rho_L, gamma_L, pi_inf_L, qv_L, rho_R, gamma_R, pi_inf_R, qv_R, alpha_L_sum, alpha_R_sum, E_L, E_R, MW_L, MW_R, R_gas_L, R_gas_R, Cp_L, Cp_R, Cv_L, Cv_R, c_sum_Yi_Phi, Gamm_L, Gamm_R, Y_L, Y_R, H_L, H_R, qv_avg, rho_avg, gamma_avg, H_avg, c_L, c_R, c_avg, s_P, s_M, xi_P, xi_M, xi_L, xi_R, xi_L_m1, xi_R_m1, Ms_L, Ms_R, pres_SL, pres_SR, vel_L, vel_R, Re_L, Re_R, alpha_L, alpha_R, alpha_rho_L, alpha_rho_R, alpha_lim_L, alpha_lim_R, s_L, s_R, s_S, vel_avg_rms, pcorr, ptilde_L, ptilde_R, Ys_L, Ys_R, Xs_L, Xs_R, Gamma_iL, Gamma_iR, Cp_iL, Cp_iR, R_species, h_iL, h_iR, tau_e_L, tau_e_R, G_L, G_R, damage_L, damage_R,'
845-
#:set _hllc_p2 = 'U_L, U_R, F_L, F_R, F_star_L, F_star_R, F_HLLC, u_n_HLLC, u_t_HLLC, u_t2_HLLC, pres_tot_L, pres_tot_R, u_n_L, u_n_R, u_t_L, u_t_R, u_t2_L, u_t2_R, tau_nn_L, tau_nn_R, tau_nt_L, tau_nt_R, tau_tt_L, tau_tt_R, tau_nt2_L, tau_nt2_R, tau_t2t2_L, tau_t2t2_R, tau_t1t2_L, tau_t1t2_R, tau_qq_L, tau_qq_R, p_face, tau_qq_face, A_L, A_R, denom_A, u_t_star, tau_nt_star, u_t2_star, tau_nt2_star, pres_tot_star,'
846-
#:set _hllc_p3 = 'F_HLL, u_n_HLL_trace, u_t_HLL_trace, u_t2_HLL_trace, p_face_HLL, tau_qq_face_HLL, tau_nn_HLL, phi, Sigma_L, Sigma_R, dSigma, Sigma_ref, a_L_ref, a_R_ref, a_ref, du_t, dtau_nt, du_t2, dtau_nt2, sensor_ptot, sensor_vt, sensor_tnt, sensor_combined, idx_phys]'
847-
#:set _hllc_priv = _hllc_p1 + _hllc_p2 + _hllc_p3
870+
#:set _hllc_priv = '[' + ', '.join(_hllc_s1 + _hllc_s2 + _hllc_s3 + _hllc_s4 + _hllc_s5 + _hllc_s6 &
871+
& + _hllc_e1 + _hllc_e2 + _hllc_e3 + _hllc_e4 + _hllc_e5 &
872+
& + _hllc_e6) + ']'
848873
#:else
849-
! Master's pure-fluid private list, unchanged
850-
#:set _hllc_priv = '[i, T_L, T_R, vel_L_rms, vel_R_rms, pres_L, pres_R, rho_L, gamma_L, pi_inf_L, qv_L, rho_R, gamma_R, pi_inf_R, qv_R, alpha_L_sum, alpha_R_sum, E_L, E_R, MW_L, MW_R, R_gas_L, R_gas_R, Cp_L, Cp_R, Cv_L, Cv_R, Gamm_L, Gamm_R, Y_L, Y_R, H_L, H_R, qv_avg, rho_avg, gamma_avg, H_avg, c_L, c_R, c_avg, s_P, s_M, xi_P, xi_M, xi_L, xi_R, xi_L_m1, xi_R_m1, Ms_L, Ms_R, pres_SL, pres_SR, vel_L, vel_R, Re_L, Re_R, alpha_L, alpha_R, alpha_rho_L, alpha_rho_R, alpha_lim_L, alpha_lim_R, s_L, s_R, s_S, vel_avg_rms, pcorr, Ys_L, Ys_R, Xs_L, Xs_R, Gamma_iL, Gamma_iR, Cp_iL, Cp_iR, R_species, h_iL, h_iR]'
874+
#:set _hllc_priv = '[' + ', '.join(_hllc_s1 + _hllc_s2 + _hllc_s3 + _hllc_s4 + _hllc_s5 + _hllc_s6) &
875+
& + ']'
851876
#:endif
852-
! The two calls below are identical on purpose. An offload kernel is named
853877
! after the .fpp line of its GPU_PARALLEL_LOOP, so one shared call would give
854878
! both emissions the same name; amdflang then launches the wrong one and a
855879
! hypoelastic run faults inside the pure-fluid kernel. Two call sites are what

src/simulation/m_riemann_solver_lf.fpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,8 @@ contains
9494
& Re_L, Re_R, s_L, s_R, Ys_L, Ys_R, Cp_iL, Cp_iR, Xs_L, Xs_R, Gamma_iL, Gamma_iR, pcorr, &
9595
& vel_grad_L, vel_grad_R, idx_right_phys, vel_L_rms, vel_R_rms, alpha_L_sum, alpha_R_sum, &
9696
& pres_L, pres_R, rho_L, rho_R, gamma_L, gamma_R, pi_inf_L, pi_inf_R, qv_L, qv_R, c_L, c_R, &
97-
& E_L, E_R, ptilde_L, ptilde_R, s_M, s_P, Cp_L, Cp_R, Cv_L, Cv_R, R_gas_L, R_gas_R, MW_L, &
98-
& MW_R, T_L, T_R, Y_L, Y_R]', firstprivate='[Re_size_loc1, Re_size_loc2]')
97+
& Gamm_L, Gamm_R, E_L, E_R, ptilde_L, ptilde_R, s_M, s_P, Cp_L, Cp_R, Cv_L, Cv_R, R_gas_L, &
98+
& R_gas_R, MW_L, MW_R, T_L, T_R, Y_L, Y_R]', firstprivate='[Re_size_loc1, Re_size_loc2]')
9999
do l = ${Z_BND}$%beg, ${Z_BND}$%end
100100
do k = ${Y_BND}$%beg, ${Y_BND}$%end
101101
do j = ${X_BND}$%beg, ${X_BND}$%end

0 commit comments

Comments
 (0)