@@ -257,8 +257,6 @@ template <typename problem_t> class QuokkaSimulation : public AMRSimulation<prob
257257 {
258258 AMRSimulation<problem_t >::initialize ();
259259
260- static_assert (!(Physics_Traits<problem_t >::is_mhd_enabled && Physics_Traits<problem_t >::is_radiation_enabled),
261- " MHD + Radiation is not supported yet." );
262260#if (AMREX_SPACEDIM != 3)
263261 static_assert (!Physics_Traits<problem_t >::is_mhd_enabled, " MHD is only supported in 3D." );
264262#endif // (AMREX_SPACEDIM != 3)
@@ -269,7 +267,7 @@ template <typename problem_t> class QuokkaSimulation : public AMRSimulation<prob
269267 readParmParse ();
270268 // set gamma
271269 amrex::ParmParse eos (" eos" );
272- eos.add (" eos_gamma" , quokka::EOS_Traits<problem_t >::gamma);
270+ eos.add (" eos_gamma" , :: quokka::EOS_Traits<problem_t >::gamma);
273271 // initialize Microphysics params
274272 init_extern_parameters ();
275273#if defined(PHOTOCHEMISTRY) || defined(CHEMISTRY)
@@ -421,7 +419,7 @@ template <typename problem_t> class QuokkaSimulation : public AMRSimulation<prob
421419 void subcycleRadiationAtLevel (int lev, amrex::Real time, amrex::Real dt_lev_hydro, amrex::FluxRegister *fr_as_crse, amrex::FluxRegister *fr_as_fine);
422420
423421 auto computeRadiationFluxes (amrex::Array4<const amrex::Real> const &consVar, const amrex::Box &indexRange, int nvars,
424- amrex::GpuArray<amrex::Real, AMREX_SPACEDIM > dx)
422+ amrex::GpuArray<amrex::Real, AMREX_SPACEDIM > dx, std::array<amrex::Array4< const amrex::Real>, AMREX_SPACEDIM > cons_fc = {} )
425423 -> std::tuple<std::array<amrex::FArrayBox, AMREX_SPACEDIM>, std::array<amrex::FArrayBox, AMREX_SPACEDIM>>;
426424
427425 auto computeHydroFluxes (amrex::MultiFab const &consVar_cc, std::array<amrex::MultiFab, AMREX_SPACEDIM > const &consVar_fc, int nvars, int nghost_Riemann,
@@ -438,7 +436,8 @@ template <typename problem_t> class QuokkaSimulation : public AMRSimulation<prob
438436
439437 template <FluxDir DIR >
440438 void fluxFunction (amrex::Array4<const amrex::Real> const &consState, amrex::FArrayBox &x1Flux, amrex::FArrayBox &x1FluxDiffusive,
441- const amrex::Box &indexRange, int nvars, amrex::GpuArray<amrex::Real, AMREX_SPACEDIM > dx);
439+ const amrex::Box &indexRange, int nvars, amrex::GpuArray<amrex::Real, AMREX_SPACEDIM > dx,
440+ std::array<amrex::Array4<const amrex::Real>, AMREX_SPACEDIM > cons_fc = {});
442441
443442 template <FluxDir DIR >
444443 void hydroFluxFunction (amrex::MultiFab &primVar, amrex::MultiFab &cc_bfield_perp_comps_mf, amrex::MultiFab &leftState, amrex::MultiFab &rightState,
@@ -900,8 +899,8 @@ template <typename problem_t> void QuokkaSimulation<problem_t>::printCellPropert
900899 const amrex::Real vel_mag = std::sqrt (vsq);
901900 const amrex::Real Ekin = 0.5 * rho * vsq;
902901 const amrex::Real Eint = Etot - Ekin;
903- const amrex::Real P = quokka::EOS <problem_t >::ComputePressure (rho, Eint);
904- const amrex::Real cs = quokka::EOS <problem_t >::ComputeSoundSpeed (rho, P);
902+ const amrex::Real P = :: quokka::EOS <problem_t >::ComputePressure (rho, Eint);
903+ const amrex::Real cs = :: quokka::EOS <problem_t >::ComputeSoundSpeed (rho, P);
905904
906905 amrex::AllPrint () << std::format (" ...[level {}] \t cell density = {:e}, |v| = {:e}, cs = {:e}\n " , lev, rho, vel_mag, cs);
907906 }
@@ -3132,15 +3131,25 @@ void QuokkaSimulation<problem_t>::subcycleRadiationAtLevel(int lev, amrex::Real
31323131 auto const &radEnergySource_arr = radEnergySource.array (iter);
31333132 RadSystem<problem_t >::SetRadEnergySource (radEnergySource_arr, indexRange, dx, prob_lo, prob_hi, time_subcycle + dt_radiation);
31343133
3134+ // Build face-centered array for MHD-aware radiation coupling
3135+ std::array<amrex::Array4<const amrex::Real>, AMREX_SPACEDIM > cons_fc_arr;
3136+ if constexpr (Physics_Traits<problem_t >::is_mhd_enabled) {
3137+ cons_fc_arr[0 ] = state_new_fc_[lev][0 ].const_array (iter);
3138+ cons_fc_arr[1 ] = state_new_fc_[lev][1 ].const_array (iter);
3139+ #if AMREX_SPACEDIM == 3
3140+ cons_fc_arr[2 ] = state_new_fc_[lev][2 ].const_array (iter);
3141+ #endif
3142+ }
3143+
31353144 // Full gas update (gas_update_factor = 1.0)
31363145 if constexpr (Physics_Traits<problem_t >::nGroups <= 1 ) {
31373146 RadSystem<problem_t >::AddSourceTermsSingleGroup (stateTmp1, radEnergySource_arr, indexRange, dt_stage2_implicit, 1.0 ,
31383147 dustGasInteractionCoeff_, rad_tol, rad_tol_rel, tempFloor,
3139- p_iteration_counter, p_iteration_failure_counter);
3148+ p_iteration_counter, p_iteration_failure_counter, cons_fc_arr );
31403149 } else {
31413150 RadSystem<problem_t >::AddSourceTermsMultiGroup (stateTmp1, radEnergySource_arr, indexRange, dt_stage2_implicit, 1.0 ,
31423151 dustGasInteractionCoeff_, rad_tol, rad_tol_rel, tempFloor,
3143- p_iteration_counter, p_iteration_failure_counter);
3152+ p_iteration_counter, p_iteration_failure_counter, cons_fc_arr );
31443153 }
31453154 }
31463155 }
@@ -3162,6 +3171,17 @@ void QuokkaSimulation<problem_t>::subcycleRadiationAtLevel(int lev, amrex::Real
31623171 const amrex::Box &indexRange = iter.validbox ();
31633172 auto const &stateNew = state_new_cc_[lev].array (iter);
31643173 auto const &stateTmp = state_tmp1_cc.const_array (iter);
3174+
3175+ // Build face-centered array for MHD-aware energy conversion
3176+ auto cons_fc = std::array<amrex::Array4<const amrex::Real>, AMREX_SPACEDIM >{};
3177+ if constexpr (Physics_Traits<problem_t >::is_mhd_enabled) {
3178+ cons_fc[0 ] = state_new_fc_[lev][0 ].const_array (iter);
3179+ cons_fc[1 ] = state_new_fc_[lev][1 ].const_array (iter);
3180+ #if AMREX_SPACEDIM == 3
3181+ cons_fc[2 ] = state_new_fc_[lev][2 ].const_array (iter);
3182+ #endif
3183+ }
3184+
31653185 // gasInternalEnergy is the primary variable for the coupling source g; combine it directly.
31663186 // gasEnergy (total = internal + kinetic) is then derived from the combined Eint and momentum.
31673187 // Combining gasEnergy directly instead would introduce a spurious kinematic term
@@ -3184,8 +3204,10 @@ void QuokkaSimulation<problem_t>::subcycleRadiationAtLevel(int lev, amrex::Real
31843204 stateNew (i, j, k, RadSystem<problem_t >::x3GasMomentum_index) = x3Mom;
31853205 stateNew (i, j, k, RadSystem<problem_t >::gasInternalEnergy_index) = Eint;
31863206 // Derive gasEnergy (total) from combined internal energy + kinetic energy of combined momentum.
3207+ // When MHD is enabled, also include magnetic energy.
3208+ const double Emag = HydroSystem<problem_t >::ComputeCellCenteredMagneticEnergy (i, j, k, cons_fc);
31873209 stateNew (i, j, k, RadSystem<problem_t >::gasEnergy_index) =
3188- RadSystem <problem_t >::ComputeEgasFromEint (rho, x1Mom, x2Mom, x3Mom, Eint);
3210+ ::quokka:: EOS <problem_t >::ComputeEgasFromEint (rho, x1Mom, x2Mom, x3Mom, Eint, Emag );
31893211 });
31903212 }
31913213 }
@@ -3208,21 +3230,41 @@ void QuokkaSimulation<problem_t>::subcycleRadiationAtLevel(int lev, amrex::Real
32083230 auto const &radEnergySource_arr = radEnergySource.array (iter);
32093231 RadSystem<problem_t >::SetRadEnergySource (radEnergySource_arr, indexRange, dx, prob_lo, prob_hi, time_subcycle + dt_radiation);
32103232
3233+ // Build face-centered array for MHD-aware radiation coupling
3234+ std::array<amrex::Array4<const amrex::Real>, AMREX_SPACEDIM > cons_fc_arr;
3235+ if constexpr (Physics_Traits<problem_t >::is_mhd_enabled) {
3236+ cons_fc_arr[0 ] = state_new_fc_[lev][0 ].const_array (iter);
3237+ cons_fc_arr[1 ] = state_new_fc_[lev][1 ].const_array (iter);
3238+ #if AMREX_SPACEDIM == 3
3239+ cons_fc_arr[2 ] = state_new_fc_[lev][2 ].const_array (iter);
3240+ #endif
3241+ }
3242+
32113243 // Full gas update (gas_update_factor = 1.0)
32123244 if constexpr (Physics_Traits<problem_t >::nGroups <= 1 ) {
32133245 RadSystem<problem_t >::AddSourceTermsSingleGroup (stateNew_cc, radEnergySource_arr, indexRange, dt_stage3_implicit, 1.0 ,
32143246 dustGasInteractionCoeff_, rad_tol, rad_tol_rel, tempFloor, p_iteration_counter,
3215- p_iteration_failure_counter);
3247+ p_iteration_failure_counter, cons_fc_arr );
32163248 } else {
32173249 RadSystem<problem_t >::AddSourceTermsMultiGroup (stateNew_cc, radEnergySource_arr, indexRange, dt_stage3_implicit, 1.0 ,
32183250 dustGasInteractionCoeff_, rad_tol, rad_tol_rel, tempFloor, p_iteration_counter,
3219- p_iteration_failure_counter);
3251+ p_iteration_failure_counter, cons_fc_arr );
32203252 }
32213253 }
32223254#ifdef PHOTOCHEMISTRY
32233255 if (enablePhotoChemistry_ == 1 ) {
3224- // compute photo-chemistry
3225- quokka::photochemistry::computePhotoChemistry<problem_t >(state_new_cc_[lev], dt_radiation, 1 , max_density_allowed, min_density_allowed);
3256+ std::array<amrex::MultiFab const *, AMREX_SPACEDIM > fc_ptrs{};
3257+ if constexpr (Physics_Traits<problem_t >::is_mhd_enabled) {
3258+ fc_ptrs[0 ] = &state_new_fc_[lev][0 ];
3259+ #if (AMREX_SPACEDIM >= 2)
3260+ fc_ptrs[1 ] = &state_new_fc_[lev][1 ];
3261+ #endif
3262+ #if (AMREX_SPACEDIM == 3)
3263+ fc_ptrs[2 ] = &state_new_fc_[lev][2 ];
3264+ #endif
3265+ }
3266+ quokka::photochemistry::computePhotoChemistry<problem_t >(state_new_cc_[lev], fc_ptrs, dt_radiation, 1 , max_density_allowed,
3267+ min_density_allowed);
32263268 }
32273269#endif
32283270
@@ -3321,7 +3363,15 @@ void QuokkaSimulation<problem_t>::advanceRadiationForwardEuler(int lev, amrex::R
33213363 const amrex::Box &indexRange = iter.validbox ();
33223364 auto const &stateOld_cc = state_old_cc_[lev].const_array (iter);
33233365 auto const &stateNew_cc = state_out.array (iter);
3324- auto [fluxArrays, fluxDiffusiveArrays] = computeRadiationFluxes (stateOld_cc, indexRange, ncompHyperbolic_, dx);
3366+ std::array<amrex::Array4<const amrex::Real>, AMREX_SPACEDIM > cons_fc_arr;
3367+ if constexpr (Physics_Traits<problem_t >::is_mhd_enabled) {
3368+ cons_fc_arr[0 ] = state_old_fc_[lev][0 ].const_array (iter);
3369+ cons_fc_arr[1 ] = state_old_fc_[lev][1 ].const_array (iter);
3370+ #if (AMREX_SPACEDIM == 3)
3371+ cons_fc_arr[2 ] = state_old_fc_[lev][2 ].const_array (iter);
3372+ #endif
3373+ }
3374+ auto [fluxArrays, fluxDiffusiveArrays] = computeRadiationFluxes (stateOld_cc, indexRange, ncompHyperbolic_, dx, cons_fc_arr);
33253375
33263376 // Stage 1 of RK2-SSP
33273377 RadSystem<problem_t >::PredictStep (
@@ -3373,8 +3423,16 @@ void QuokkaSimulation<problem_t>::advanceRadiationMidpointRK2(int lev, amrex::Re
33733423 auto const &stateOld_cc = state_old_cc_[lev].const_array (iter);
33743424 auto const &stateInter_cc = state_inter.const_array (iter);
33753425 auto const &stateNew_cc = state_new_cc_[lev].array (iter);
3376- auto [fluxArraysOld, fluxDiffusiveArraysOld] = computeRadiationFluxes (stateOld_cc, indexRange, ncompHyperbolic_, dx);
3377- auto [fluxArrays, fluxDiffusiveArrays] = computeRadiationFluxes (stateInter_cc, indexRange, ncompHyperbolic_, dx);
3426+ std::array<amrex::Array4<const amrex::Real>, AMREX_SPACEDIM > cons_fc_arr;
3427+ if constexpr (Physics_Traits<problem_t >::is_mhd_enabled) {
3428+ cons_fc_arr[0 ] = state_old_fc_[lev][0 ].const_array (iter);
3429+ cons_fc_arr[1 ] = state_old_fc_[lev][1 ].const_array (iter);
3430+ #if (AMREX_SPACEDIM == 3)
3431+ cons_fc_arr[2 ] = state_old_fc_[lev][2 ].const_array (iter);
3432+ #endif
3433+ }
3434+ auto [fluxArraysOld, fluxDiffusiveArraysOld] = computeRadiationFluxes (stateOld_cc, indexRange, ncompHyperbolic_, dx, cons_fc_arr);
3435+ auto [fluxArrays, fluxDiffusiveArrays] = computeRadiationFluxes (stateInter_cc, indexRange, ncompHyperbolic_, dx, cons_fc_arr);
33783436
33793437 // Stage 2 of RK2-SSP with Shu-Osher coefficients
33803438 RadSystem<problem_t >::AddFluxesRK2 (
@@ -3400,7 +3458,8 @@ void QuokkaSimulation<problem_t>::advanceRadiationMidpointRK2(int lev, amrex::Re
34003458
34013459template <typename problem_t >
34023460auto QuokkaSimulation<problem_t >::computeRadiationFluxes(amrex::Array4<const amrex::Real> const &consVar, const amrex::Box &indexRange, const int nvars,
3403- amrex::GpuArray<amrex::Real, AMREX_SPACEDIM > dx)
3461+ amrex::GpuArray<amrex::Real, AMREX_SPACEDIM > dx,
3462+ std::array<amrex::Array4<const amrex::Real>, AMREX_SPACEDIM > cons_fc)
34043463 -> std::tuple<std::array<amrex::FArrayBox, AMREX_SPACEDIM >, std::array<amrex::FArrayBox, AMREX_SPACEDIM >>
34053464{
34063465 amrex::Box const &x1FluxRange = amrex::surroundingNodes (indexRange, 0 );
@@ -3417,9 +3476,9 @@ auto QuokkaSimulation<problem_t>::computeRadiationFluxes(amrex::Array4<const amr
34173476 amrex::FArrayBox x3FluxDiffusive (x3FluxRange, nvars, amrex::The_Async_Arena ());
34183477#endif
34193478
3420- AMREX_D_TERM (fluxFunction<FluxDir::X1 >(consVar, x1Flux, x1FluxDiffusive, indexRange, nvars, dx);
3421- , fluxFunction<FluxDir::X2 >(consVar, x2Flux, x2FluxDiffusive, indexRange, nvars, dx);
3422- , fluxFunction<FluxDir::X3 >(consVar, x3Flux, x3FluxDiffusive, indexRange, nvars, dx);)
3479+ AMREX_D_TERM (fluxFunction<FluxDir::X1 >(consVar, x1Flux, x1FluxDiffusive, indexRange, nvars, dx, cons_fc );
3480+ , fluxFunction<FluxDir::X2 >(consVar, x2Flux, x2FluxDiffusive, indexRange, nvars, dx, cons_fc );
3481+ , fluxFunction<FluxDir::X3 >(consVar, x3Flux, x3FluxDiffusive, indexRange, nvars, dx, cons_fc );)
34233482
34243483 std::array<amrex::FArrayBox, AMREX_SPACEDIM > fluxArrays = {AMREX_D_DECL (std::move (x1Flux), std::move (x2Flux), std::move (x3Flux))};
34253484 std::array<amrex::FArrayBox, AMREX_SPACEDIM > fluxDiffusiveArrays{
@@ -3431,7 +3490,8 @@ auto QuokkaSimulation<problem_t>::computeRadiationFluxes(amrex::Array4<const amr
34313490template <typename problem_t >
34323491template <FluxDir DIR >
34333492void QuokkaSimulation<problem_t >::fluxFunction(amrex::Array4<const amrex::Real> const &consState, amrex::FArrayBox &x1Flux, amrex::FArrayBox &x1FluxDiffusive,
3434- const amrex::Box &indexRange, const int nvars, amrex::GpuArray<amrex::Real, AMREX_SPACEDIM > dx)
3493+ const amrex::Box &indexRange, const int nvars, amrex::GpuArray<amrex::Real, AMREX_SPACEDIM > dx,
3494+ std::array<amrex::Array4<const amrex::Real>, AMREX_SPACEDIM > cons_fc)
34353495{
34363496 int dir = 0 ;
34373497 if constexpr (DIR == FluxDir::X1 ) {
@@ -3478,7 +3538,7 @@ void QuokkaSimulation<problem_t>::fluxFunction(amrex::Array4<const amrex::Real>
34783538 // interface-centered kernel
34793539 amrex::Box const &x1FluxRange = amrex::surroundingNodes (indexRange, dir);
34803540 RadSystem<problem_t >::template ComputeFluxes<DIR >(x1Flux.array (), x1FluxDiffusive.array (), x1LeftState.array (), x1RightState.array (), x1FluxRange,
3481- consState, dx, use_wavespeed_correction_); // watch out for argument order!!
3541+ consState, dx, use_wavespeed_correction_, cons_fc ); // watch out for argument order!!
34823542}
34833543
34843544// Save single-level plotfile
0 commit comments