@@ -15,7 +15,8 @@ namespace quokka::Riemann
1515{
1616constexpr double DELTA = 1.0e-4 ;
1717
18- // HLLD solver following Miyoshi and Kusano (2005), hereafter MK5.
18+ // HLLD solver based on Miyoshi & Kusano (2005), hereafter MK5.
19+ // Corrections based on Minoshima & Miyoshi (2021), hereafter MM21.
1920template <typename problem_t , int N_scalars, int N_mscalars, int fluxdim>
2021AMREX_FORCE_INLINE AMREX_GPU_DEVICE auto HLLD (quokka::HydroState<N_scalars, N_mscalars> const &sL , quokka::HydroState<N_scalars, N_mscalars> const &sR ,
2122 const double gamma, const double bx, const double perp_v_jump)
@@ -40,16 +41,20 @@ AMREX_FORCE_INLINE AMREX_GPU_DEVICE auto HLLD(quokka::HydroState<N_scalars, N_ms
4041 ConsHydro1D<N_scalars> u_star_R{};
4142
4243 // frequently used term
43- double const bx_sq = SQUARE (bx);
44+ const double vel_magn_sq_L = SQUARE (sL .u ) + (SQUARE (sL .v ) + SQUARE (sL .w ));
45+ const double vel_magn_sq_R = SQUARE (sR .u ) + (SQUARE (sR .v ) + SQUARE (sR .w ));
46+ const double bx_sq = SQUARE (bx);
47+ const double b_magn_sq_L = bx_sq + (SQUARE (sL .by ) + SQUARE (sL .bz ));
48+ const double b_magn_sq_R = bx_sq + (SQUARE (sR .by ) + SQUARE (sR .bz ));
4449
4550 // compute L/R states for select conserved variables
4651 // (group transverse vector components for floating-point associativity symmetry)
4752 // magnetic pressure
48- double const pb_L = 0.5 * (bx_sq + ( SQUARE ( sL . by ) + SQUARE ( sL . bz ))) ;
49- double const pb_R = 0.5 * (bx_sq + ( SQUARE ( sR . by ) + SQUARE ( sR . bz ))) ;
53+ const double pb_L = 0.5 * b_magn_sq_L ;
54+ const double pb_R = 0.5 * b_magn_sq_R ;
5055 // kinetic energy
51- double const ke_L = 0.5 * sL .rho * ( SQUARE ( sL . u ) + ( SQUARE ( sL . v ) + SQUARE ( sL . w )) );
52- double const ke_R = 0.5 * sR .rho * ( SQUARE ( sR . u ) + ( SQUARE ( sR . v ) + SQUARE ( sR . w )) );
56+ const double ke_L = 0.5 * ( sL .rho * vel_magn_sq_L );
57+ const double ke_R = 0.5 * ( sR .rho * vel_magn_sq_R );
5358 // set left conserved states
5459 u_L.rho = sL .rho ;
5560 u_L.mx = sL .u * u_L.rho ;
@@ -76,18 +81,21 @@ AMREX_FORCE_INLINE AMREX_GPU_DEVICE auto HLLD(quokka::HydroState<N_scalars, N_ms
7681
7782 // --- Step 2. Compute L & R wave speeds according to MK5, eqn. (67)
7883
79- const double fspd_L = FastMagnetoSonicSpeed (gamma, sL , bx);
80- const double fspd_R = FastMagnetoSonicSpeed (gamma, sR , bx);
81- spds[0 ] = std::min (sL .u - fspd_L, sR .u - fspd_R);
82- spds[4 ] = std::max (sL .u + fspd_L, sR .u + fspd_R);
83- const double fspd_m = -std::min (0.0 , spds[0 ]);
84- const double fspd_p = std::max (0.0 , spds[4 ]);
84+ const double spd_fms_L = FastMagnetoSonicSpeed (gamma, sL , bx);
85+ const double spd_fms_R = FastMagnetoSonicSpeed (gamma, sR , bx);
86+ const double spd_fms_max = std::max (spd_fms_L, spd_fms_R);
87+ const double u_min = std::min (sL .u , sR .u );
88+ const double u_max = std::max (sL .u , sR .u );
89+ spds[0 ] = std::min (0.0 , u_min - spd_fms_max);
90+ spds[4 ] = std::max (0.0 , u_max + spd_fms_max);
91+ const double fspd_m = -spds[0 ];
92+ const double fspd_p = spds[4 ];
8593
8694 // --- Step 3. Compute L/R fluxes
8795
8896 // total pressure
89- double ptot_L = sL .P + pb_L;
90- double ptot_R = sR .P + pb_R;
97+ const double ptot_L = sL .P + pb_L;
98+ const double ptot_R = sR .P + pb_R;
9199 // fluxes on the left side of the interface
92100 f_L.rho = u_L.mx ;
93101 f_L.mx = u_L.mx * sL .u + ptot_L - bx_sq;
@@ -116,25 +124,23 @@ AMREX_FORCE_INLINE AMREX_GPU_DEVICE auto HLLD(quokka::HydroState<N_scalars, N_ms
116124 // --- Step 4. Compute middle and Alfven wave speeds
117125
118126 // MK5: S_i - u_i (for i=L or R)
119- double siui_L = spds[0 ] - sL .u ;
120- double siui_R = spds[4 ] - sR .u ;
127+ const double siui_L = spds[0 ] - sL .u ;
128+ const double siui_R = spds[4 ] - sR .u ;
121129 // carbuncle detector
122- const double max_spd = std::max (fspd_L, fspd_R);
123- const double para_v_jump = sL .u - sR .u ; // negative -> compression
124- double theta = 1.0 ;
130+ const double para_v_jump = sR .u - sL .u ; // negative -> compression
125131 // tp := shock anisotropy, clamped to [0, 1], with theta = tp^4
126- const double denom_tp = std::max (1e-14 , max_spd - std::min (perp_v_jump, 0.0 ));
127- double tp = (max_spd - std::min (para_v_jump, 0.0 )) / denom_tp;
132+ const double denom_tp = std::max (1e-14 , spd_fms_max - std::min (perp_v_jump, 0.0 ));
133+ double tp = (spd_fms_max - std::min (para_v_jump, 0.0 )) / denom_tp;
128134 tp = amrex::Clamp (tp, 0.0 , 1.0 );
129- theta = SQUARE (SQUARE (tp));
130- // modified middle speed S_M from MK5 eqn (38)
135+ const double theta = SQUARE (SQUARE (tp));
136+ // modified middle speed S_M from MK5 eqn 38 with theta from MM21 eqn 9
131137 const double sm_denom = (siui_R * u_R.rho - siui_L * u_L.rho );
132138 spds[2 ] = (siui_R * u_R.mx - siui_L * u_L.mx + theta * (ptot_L - ptot_R)) / sm_denom;
133139 // S_i - S_M (for i=L or R)
134- double sism_L = spds[0 ] - spds[2 ];
135- double sism_R = spds[4 ] - spds[2 ];
136- double sism_inv_L = 1.0 / sism_L;
137- double sism_inv_R = 1.0 / sism_R;
140+ const double sism_L = spds[0 ] - spds[2 ];
141+ const double sism_R = spds[4 ] - spds[2 ];
142+ const double sism_inv_L = 1.0 / sism_L;
143+ const double sism_inv_R = 1.0 / sism_R;
138144 // MK5: rho_i from eqn (43)
139145 u_star_L.rho = u_L.rho * siui_L * sism_inv_L;
140146 u_star_R.rho = u_R.rho * siui_R * sism_inv_R;
@@ -145,21 +151,45 @@ AMREX_FORCE_INLINE AMREX_GPU_DEVICE auto HLLD(quokka::HydroState<N_scalars, N_ms
145151 u_star_R.scalar [n] = u_R.scalar [n] * siui_R * sism_inv_R;
146152 }
147153
148- double u_star_rho_inv_L = 1.0 / u_star_L.rho ;
149- double u_star_rho_inv_R = 1.0 / u_star_R.rho ;
150- double rho_sqrt_L = std::sqrt (u_star_L.rho );
151- double rho_sqrt_R = std::sqrt (u_star_R.rho );
154+ const double u_star_rho_inv_L = 1.0 / u_star_L.rho ;
155+ const double u_star_rho_inv_R = 1.0 / u_star_R.rho ;
156+ const double rho_sqrt_L = std::sqrt (u_star_L.rho );
157+ const double rho_sqrt_R = std::sqrt (u_star_R.rho );
152158 // MK5: eqn (51)
153159 spds[1 ] = spds[2 ] - std::abs (bx) / rho_sqrt_L;
154160 spds[3 ] = spds[2 ] + std::abs (bx) / rho_sqrt_R;
155161
156162 // --- Step 5. Compute intermediate states
157163
158- // compute total pressure
159- // MK5: eqn (41) can be calculated (more explicitly) via eqn (23)
160- double ptot_star_L = ptot_L + u_L.rho * siui_L * (spds[2 ] - sL .u );
161- double ptot_star_R = ptot_R + u_R.rho * siui_R * (spds[2 ] - sR .u );
162- double const ptot_star = 0.5 * (ptot_star_L + ptot_star_R);
164+ // // total pressure (no correction)
165+ // // MK5: eqn (41) can be calculated (more explicitly) via eqn (23)
166+ // double ptot_star_L = ptot_L + u_L.rho * siui_L * (spds[2] - sL.u);
167+ // double ptot_star_R = ptot_R + u_R.rho * siui_R * (spds[2] - sR.u);
168+ // double const ptot_star = 0.5 * (ptot_star_L + ptot_star_R);
169+
170+ // total pressure (w/ MM21 low-Mach correction)
171+ // MM21 eqn 8
172+ const double spd_ca_sq_L = b_magn_sq_L / sL .rho ;
173+ const double spd_ca_sq_R = b_magn_sq_R / sR .rho ;
174+ const double spd_cax_sq_L = bx_sq / sL .rho ;
175+ const double spd_cax_sq_R = bx_sq / sR .rho ;
176+ // cu := modified fast magnetosonic speed (MM21 eqn 14)
177+ const double cu_sqrt_arg_L = std::max (0.0 , SQUARE (spd_ca_sq_L + vel_magn_sq_L) - 4.0 * vel_magn_sq_L * spd_cax_sq_L);
178+ const double cu_sqrt_arg_R = std::max (0.0 , SQUARE (spd_ca_sq_R + vel_magn_sq_R) - 4.0 * vel_magn_sq_R * spd_cax_sq_R);
179+ const double spd_cu_sq_L = 0.5 * ((spd_ca_sq_L + vel_magn_sq_L) + std::sqrt (cu_sqrt_arg_L));
180+ const double spd_cu_sq_R = 0.5 * ((spd_ca_sq_R + vel_magn_sq_R) + std::sqrt (cu_sqrt_arg_R));
181+ const double spd_cu_L = std::sqrt (std::max (0.0 , spd_cu_sq_L));
182+ const double spd_cu_R = std::sqrt (std::max (0.0 , spd_cu_sq_R));
183+ const double spd_cu_max = std::max (spd_cu_L, spd_cu_R);
184+ // limiter (MM21 eqn 16)
185+ const double chi = std::min (1.0 , spd_cu_max / std::max (1e-14 , spd_fms_max));
186+ const double phi = chi * (2.0 - chi);
187+ // corrected total star pressure (MM21 eqn 15)
188+ const double ptot_star_numer_term1 = (siui_R * u_R.rho ) * ptot_L;
189+ const double ptot_star_numer_term2 = (siui_L * u_L.rho ) * ptot_R;
190+ const double ptot_star_numer_term3 = phi * (u_L.rho * u_R.rho ) * (siui_R * siui_L) * (sR .u - sL .u );
191+ const double ptot_star_numer = ptot_star_numer_term1 - ptot_star_numer_term2 + ptot_star_numer_term3;
192+ const double ptot_star = ptot_star_numer / sm_denom;
163193
164194 // MK5: u_L^(star, dstar) from, eqn (39)
165195 u_star_L.mx = u_star_L.rho * spds[2 ];
@@ -205,7 +235,7 @@ AMREX_FORCE_INLINE AMREX_GPU_DEVICE auto HLLD(quokka::HydroState<N_scalars, N_ms
205235 }
206236 // vec(v_R^star) dot vec(b_R^star)
207237 // group transverse momenta-components for floating-point associativity
208- double vb_star_R = (u_star_R.mx * bx + (u_star_R.my * u_star_R.by + u_star_R.mz * u_star_R.bz )) * u_star_rho_inv_R;
238+ const double vb_star_R = (u_star_R.mx * bx + (u_star_R.my * u_star_R.by + u_star_R.mz * u_star_R.bz )) * u_star_rho_inv_R;
209239 // MK5: eqn (48)
210240 u_star_R.E = (siui_R * u_R.E - ptot_R * sR .u + ptot_star * spds[2 ] + bx * (sR .u * bx + (sR .v * u_R.by + sR .w * u_R.bz ) - vb_star_R)) * sism_inv_R;
211241
0 commit comments