xref: /honee/qfunctions/riemann_solver.h (revision c7ece6efd17014bd7b01fc517a8c82707db4fa34)
1 // Copyright (c) 2017-2024, Lawrence Livermore National Security, LLC and other CEED contributors.
2 // All Rights Reserved. See the top-level LICENSE and NOTICE files for details.
3 //
4 // SPDX-License-Identifier: BSD-2-Clause
5 //
6 // This file is part of CEED:  http://github.com/ceed
7 
8 /// @file
9 /// Helper functions for solving the Riemann problem.
10 // The left and right states are specified from the perspective of an outward-facing normal vector pointing left to right:
11 //
12 //     (domain)
13 //    /               (outward facing normal)
14 // |------------|   /
15 // |            |  /
16 // |    Left    |---->  Right
17 // | (Interior) |    (Exterior)
18 // |------------|
19 //
20 // The right state is exterior to the domain and the left state is the interior to the domain.
21 // Much of the work references Eleuterio F. Toro's "Riemann Solvers and Numerical Methods for Fluid Dynamics", 2009
22 #include "newtonian_state.h"
23 #include "newtonian_types.h"
24 
25 enum RiemannFluxType_ { RIEMANN_HLL, RIEMANN_HLLC };
26 typedef enum RiemannFluxType_ RiemannFluxType;
27 
28 typedef struct {
29   CeedScalar left, right;
30 } RoeWeights;
31 
32 CEED_QFUNCTION_HELPER RoeWeights RoeSetup(CeedScalar rho_left, CeedScalar rho_right) {
33   CeedScalar sqrt_left = sqrt(rho_left), sqrt_right = sqrt(rho_right);
34   RoeWeights w = {sqrt_left / (sqrt_left + sqrt_right), sqrt_right / (sqrt_left + sqrt_right)};
35   return w;
36 }
37 
38 CEED_QFUNCTION_HELPER RoeWeights RoeSetup_fwd(CeedScalar rho_left, CeedScalar rho_right, CeedScalar drho_left, CeedScalar drho_right) {
39   CeedScalar sqrt_left = sqrt(rho_left), sqrt_right = sqrt(rho_right);
40   CeedScalar square_sum_root = Square(sqrt_left + sqrt_right);
41   CeedScalar r_right = (sqrt_left / (2 * sqrt_right * square_sum_root)) * drho_right - (sqrt_right / (2 * sqrt_left * square_sum_root)) * drho_left;
42   CeedScalar r_left  = (sqrt_right / (2 * sqrt_left * square_sum_root)) * drho_left - (sqrt_left / (2 * sqrt_right * square_sum_root)) * drho_right;
43   RoeWeights dw      = {r_left, r_right};
44   return dw;
45 }
46 
47 CEED_QFUNCTION_HELPER CeedScalar RoeAverage(RoeWeights r, CeedScalar q_left, CeedScalar q_right) { return r.left * q_left + r.right * q_right; }
48 
49 CEED_QFUNCTION_HELPER CeedScalar RoeAverage_fwd(RoeWeights r, RoeWeights dr, CeedScalar q_left, CeedScalar q_right, CeedScalar dq_left,
50                                                 CeedScalar dq_right) {
51   return q_right * dr.right + q_left * dr.left + r.right * dq_right + r.left * dq_left;
52 }
53 
54 CEED_QFUNCTION_HELPER StateConservative Flux_HLL(State left, State right, StateConservative flux_left, StateConservative flux_right,
55                                                  CeedScalar s_left, CeedScalar s_right) {
56   CeedScalar U_left[5], U_right[5], F_right[5], F_left[5], F_hll[5];
57   UnpackState_U(left.U, U_left);
58   UnpackState_U(right.U, U_right);
59   UnpackState_U(flux_left, F_left);
60   UnpackState_U(flux_right, F_right);
61   for (int i = 0; i < 5; i++) {
62     F_hll[i] = (s_right * F_left[i] - s_left * F_right[i] + s_left * s_right * (U_right[i] - U_left[i])) / (s_right - s_left);
63   }
64   StateConservative F = {
65       F_hll[0],
66       {F_hll[1], F_hll[2], F_hll[3]},
67       F_hll[4],
68   };
69   return F;
70 }
71 
72 CEED_QFUNCTION_HELPER StateConservative Flux_HLL_fwd(State left, State right, State dleft, State dright, StateConservative flux_left,
73                                                      StateConservative flux_right, StateConservative dflux_left, StateConservative dflux_right,
74                                                      CeedScalar S_l, CeedScalar S_r, CeedScalar dS_l, CeedScalar dS_r) {
75   CeedScalar U_l[5], U_r[5], F_r[5], F_l[5];
76   UnpackState_U(left.U, U_l);
77   UnpackState_U(right.U, U_r);
78   UnpackState_U(flux_left, F_l);
79   UnpackState_U(flux_right, F_r);
80 
81   CeedScalar dU_l[5], dU_r[5], dF_r[5], dF_l[5], dF_hll[5] = {0.};
82   UnpackState_U(dleft.U, dU_l);
83   UnpackState_U(dright.U, dU_r);
84   UnpackState_U(dflux_left, dF_l);
85   UnpackState_U(dflux_right, dF_r);
86   for (int i = 0; i < 5; i++) {
87     const CeedScalar U_diff      = U_r[i] - U_l[i];
88     const CeedScalar S_diff      = S_r - S_l;
89     const CeedScalar F_hll_denom = S_r * F_l[i] - S_l * F_r[i] + S_l * S_r * U_diff;
90 
91     dF_hll[i] += ((F_l[i] + S_r * U_diff) * S_diff - F_hll_denom) / Square(S_diff) * dS_r;
92     dF_hll[i] += ((-F_r[i] + S_r * U_diff) * S_diff + F_hll_denom) / Square(S_diff) * dS_l;
93     dF_hll[i] += (S_r * dF_l[i] - S_l * dF_r[i] + S_r * S_l * dU_r[i] - S_r * S_l * dU_l[i]) / S_diff;
94   }
95   StateConservative dF = {
96       dF_hll[0],
97       {dF_hll[1], dF_hll[2], dF_hll[3]},
98       dF_hll[4],
99   };
100   return dF;
101 }
102 
103 CEED_QFUNCTION_HELPER void ComputeHLLSpeeds_Roe(NewtonianIdealGasContext gas, State left, CeedScalar u_left, State right, CeedScalar u_right,
104                                                 CeedScalar *s_left, CeedScalar *s_right) {
105   const CeedScalar gamma = HeatCapacityRatio(gas);
106 
107   RoeWeights r = RoeSetup(left.U.density, right.U.density);
108   // Speed estimate
109   // Roe average eigenvalues for left and right non-linear waves.
110   // Stability requires that these speed estimates are *at least* as fast as the physical wave speeds.
111   CeedScalar u_roe = RoeAverage(r, u_left, u_right);
112 
113   // TODO: revisit this for gravity
114   CeedScalar H_left  = TotalSpecificEnthalpy(gas, left);
115   CeedScalar H_right = TotalSpecificEnthalpy(gas, right);
116   CeedScalar H_roe   = RoeAverage(r, H_left, H_right);
117   CeedScalar a_roe   = sqrt((gamma - 1) * (H_roe - 0.5 * Square(u_roe)));
118 
119   // Einfeldt (1988) justifies (and Toro's book repeats) that Roe speeds can be used here.
120   *s_left  = u_roe - a_roe;
121   *s_right = u_roe + a_roe;
122 }
123 
124 CEED_QFUNCTION_HELPER void ComputeHLLSpeeds_Roe_fwd(NewtonianIdealGasContext gas, State left, State dleft, CeedScalar u_left, CeedScalar du_left,
125                                                     State right, State dright, CeedScalar u_right, CeedScalar du_right, CeedScalar *s_left,
126                                                     CeedScalar *ds_left, CeedScalar *s_right, CeedScalar *ds_right) {
127   const CeedScalar gamma = HeatCapacityRatio(gas);
128 
129   RoeWeights r  = RoeSetup(left.U.density, right.U.density);
130   RoeWeights dr = RoeSetup_fwd(left.U.density, right.U.density, dleft.U.density, dright.U.density);
131   // Speed estimate
132   // Roe average eigenvalues for left and right non-linear waves.
133   // Stability requires that these speed estimates are *at least* as fast as the physical wave speeds.
134   CeedScalar u_roe  = RoeAverage(r, u_left, u_right);
135   CeedScalar du_roe = RoeAverage_fwd(r, dr, u_left, u_right, du_left, du_right);
136 
137   CeedScalar H_left   = TotalSpecificEnthalpy(gas, left);
138   CeedScalar H_right  = TotalSpecificEnthalpy(gas, right);
139   CeedScalar dH_left  = TotalSpecificEnthalpy_fwd(gas, left, dleft);
140   CeedScalar dH_right = TotalSpecificEnthalpy_fwd(gas, right, dright);
141 
142   CeedScalar H_roe  = RoeAverage(r, H_left, H_right);
143   CeedScalar dH_roe = RoeAverage_fwd(r, dr, H_left, H_right, dH_left, dH_right);
144   CeedScalar a_roe  = sqrt((gamma - 1) * (H_roe - 0.5 * Square(u_roe)));
145   CeedScalar da_roe = 0.5 * (gamma - 1) / sqrt(H_roe) * dH_roe - 0.5 * sqrt(gamma - 1) * u_roe / sqrt(H_roe - 0.5 * Square(u_roe)) * du_roe;
146 
147   *s_left   = u_roe - a_roe;
148   *ds_left  = du_roe - da_roe;
149   *s_right  = u_roe + a_roe;
150   *ds_right = du_roe + da_roe;
151 }
152 
153 // *****************************************************************************
154 // @brief Harten Lax VanLeer (HLL) approximate Riemann solver.
155 // Taking in two states (left, right) and returns RiemannFlux_HLL.
156 // The left and right states are specified from the perspective of an outward-facing normal vector pointing left to right.
157 //
158 // @param[in] gas    NewtonianIdealGasContext for the fluid
159 // @param[in] left   Fluid state of the domain interior (the current solution)
160 // @param[in] right  Fluid state of the domain exterior (free stream conditions)
161 // @param[in] normal Normalized, outward facing boundary normal vector
162 //
163 // @return StateConservative with HLL Riemann Flux
164 // *****************************************************************************
165 CEED_QFUNCTION_HELPER StateConservative RiemannFlux_HLL(NewtonianIdealGasContext gas, State left, State right, const CeedScalar normal[3]) {
166   StateConservative flux_left  = FluxInviscidDotNormal(gas, left, normal);
167   StateConservative flux_right = FluxInviscidDotNormal(gas, right, normal);
168 
169   CeedScalar u_left  = Dot3(left.Y.velocity, normal);
170   CeedScalar u_right = Dot3(right.Y.velocity, normal);
171 
172   CeedScalar s_left, s_right;
173   ComputeHLLSpeeds_Roe(gas, left, u_left, right, u_right, &s_left, &s_right);
174 
175   // Compute HLL flux
176   if (0 <= s_left) {
177     return flux_left;
178   } else if (s_right <= 0) {
179     return flux_right;
180   } else {
181     return Flux_HLL(left, right, flux_left, flux_right, s_left, s_right);
182   }
183 }
184 
185 // *****************************************************************************
186 // @brief Forward-mode Derivative of Harten Lax VanLeer (HLL) approximate Riemann solver.
187 //
188 // @param gas    NewtonianIdealGasContext for the fluid
189 // @param left   Fluid state of the domain interior (the current solution)
190 // @param right  Fluid state of the domain exterior (free stream conditions)
191 // @param dleft  Derivative of fluid state of the domain interior (the current solution)
192 // @param dright Derivative of fluid state of the domain exterior (free stream conditions)
193 // @param normal Normalized, outward facing boundary normal vector
194 //
195 // @return StateConservative with derivative of HLL Riemann Flux
196 // *****************************************************************************
197 CEED_QFUNCTION_HELPER StateConservative RiemannFlux_HLL_fwd(NewtonianIdealGasContext gas, State left, State dleft, State right, State dright,
198                                                             const CeedScalar normal[3]) {
199   StateConservative flux_left   = FluxInviscidDotNormal(gas, left, normal);
200   StateConservative flux_right  = FluxInviscidDotNormal(gas, right, normal);
201   StateConservative dflux_left  = FluxInviscidDotNormal_fwd(gas, left, dleft, normal);
202   StateConservative dflux_right = FluxInviscidDotNormal_fwd(gas, right, dright, normal);
203 
204   CeedScalar u_left   = Dot3(left.Y.velocity, normal);
205   CeedScalar u_right  = Dot3(right.Y.velocity, normal);
206   CeedScalar du_left  = Dot3(dleft.Y.velocity, normal);
207   CeedScalar du_right = Dot3(dright.Y.velocity, normal);
208 
209   CeedScalar s_left, ds_left, s_right, ds_right;
210   ComputeHLLSpeeds_Roe_fwd(gas, left, dleft, u_left, du_left, right, dright, u_right, du_right, &s_left, &ds_left, &s_right, &ds_right);
211 
212   if (0 <= s_left) {
213     return dflux_left;
214   } else if (s_right <= 0) {
215     return dflux_right;
216   } else {
217     return Flux_HLL_fwd(left, right, dleft, dright, flux_left, flux_right, dflux_left, dflux_right, s_left, s_right, ds_left, ds_right);
218   }
219 }
220 
221 CEED_QFUNCTION_HELPER StateConservative RiemannFlux_HLLC_Star(NewtonianIdealGasContext gas, State side, StateConservative F_side,
222                                                               const CeedScalar normal[3], CeedScalar u_side, CeedScalar s_side, CeedScalar s_star) {
223   CeedScalar fact  = side.U.density * (s_side - u_side) / (s_side - s_star);
224   CeedScalar denom = side.U.density * (s_side - u_side);
225   // U_* = fact * star
226   StateConservative star = {
227       1.0,
228       {
229         side.Y.velocity[0] + (s_star - u_side) * normal[0],
230         side.Y.velocity[1] + (s_star - u_side) * normal[1],
231         side.Y.velocity[2] + (s_star - u_side) * normal[2],
232         },
233       side.U.E_total / side.U.density  //
234           + (s_star - u_side) * (s_star + side.Y.pressure / denom)
235   };
236   return StateConservativeAXPBYPCZ(1, F_side, s_side * fact, star, -s_side, side.U);
237 }
238 
239 CEED_QFUNCTION_HELPER StateConservative RiemannFlux_HLLC_Star_fwd(NewtonianIdealGasContext gas, State side, State dside, StateConservative F_side,
240                                                                   StateConservative dF_side, const CeedScalar normal[3], CeedScalar u_side,
241                                                                   CeedScalar du_side, CeedScalar s_side, CeedScalar ds_side, CeedScalar s_star,
242                                                                   CeedScalar ds_star) {
243   CeedScalar fact  = side.U.density * (s_side - u_side) / (s_side - s_star);
244   CeedScalar dfact = (side.U.density * (ds_side - du_side) + dside.U.density * (s_side - u_side)) / (s_side - s_star)  //
245                      - fact / (s_side - s_star) * (ds_side - ds_star);
246   CeedScalar denom  = side.U.density * (s_side - u_side);
247   CeedScalar ddenom = side.U.density * (ds_side - du_side) + dside.U.density * (s_side - u_side);
248 
249   StateConservative star = {
250       1.0,
251       {
252         side.Y.velocity[0] + (s_star - u_side) * normal[0],
253         side.Y.velocity[1] + (s_star - u_side) * normal[1],
254         side.Y.velocity[2] + (s_star - u_side) * normal[2],
255         },
256       side.U.E_total / side.U.density  //
257           + (s_star - u_side) * (s_star + side.Y.pressure / denom)
258   };
259   StateConservative dstar = {
260       0.,
261       {
262         dside.Y.velocity[0] + (ds_star - du_side) * normal[0],
263         dside.Y.velocity[1] + (ds_star - du_side) * normal[1],
264         dside.Y.velocity[2] + (ds_star - du_side) * normal[2],
265         },
266       dside.U.E_total / side.U.density - side.U.E_total / Square(side.U.density) * dside.U.density  //
267           + (ds_star - du_side) * (s_star + side.Y.pressure / denom)  //
268           + (s_star - u_side) * (ds_star + dside.Y.pressure / denom - side.Y.pressure / Square(denom) * ddenom)  //
269   };
270 
271   const CeedScalar        a[] = {1, ds_side * fact + s_side * dfact, s_side * fact, -ds_side, -s_side};
272   const StateConservative U[] = {dF_side, star, dstar, side.U, dside.U};
273   return StateConservativeMult(5, a, U);
274 }
275 
276 // HLLC Riemann solver (from Toro's book)
277 CEED_QFUNCTION_HELPER StateConservative RiemannFlux_HLLC(NewtonianIdealGasContext gas, State left, State right, const CeedScalar normal[3]) {
278   StateConservative flux_left  = FluxInviscidDotNormal(gas, left, normal);
279   StateConservative flux_right = FluxInviscidDotNormal(gas, right, normal);
280 
281   CeedScalar u_left  = Dot3(left.Y.velocity, normal);
282   CeedScalar u_right = Dot3(right.Y.velocity, normal);
283   CeedScalar s_left, s_right;
284   ComputeHLLSpeeds_Roe(gas, left, u_left, right, u_right, &s_left, &s_right);
285 
286   // Contact wave speed; Toro (10.37)
287   CeedScalar rhou_left = left.U.density * u_left, rhou_right = right.U.density * u_right;
288   CeedScalar numer  = right.Y.pressure - left.Y.pressure + rhou_left * (s_left - u_left) - rhou_right * (s_right - u_right);
289   CeedScalar denom  = left.U.density * (s_left - u_left) - right.U.density * (s_right - u_right);
290   CeedScalar s_star = numer / denom;
291 
292   // Compute HLLC flux
293   if (0 <= s_left) {
294     return flux_left;
295   } else if (0 <= s_star) {
296     return RiemannFlux_HLLC_Star(gas, left, flux_left, normal, u_left, s_left, s_star);
297   } else if (0 <= s_right) {
298     return RiemannFlux_HLLC_Star(gas, right, flux_right, normal, u_right, s_right, s_star);
299   } else {
300     return flux_right;
301   }
302 }
303 
304 CEED_QFUNCTION_HELPER StateConservative RiemannFlux_HLLC_fwd(NewtonianIdealGasContext gas, State left, State dleft, State right, State dright,
305                                                              const CeedScalar normal[3]) {
306   StateConservative flux_left   = FluxInviscidDotNormal(gas, left, normal);
307   StateConservative flux_right  = FluxInviscidDotNormal(gas, right, normal);
308   StateConservative dflux_left  = FluxInviscidDotNormal_fwd(gas, left, dleft, normal);
309   StateConservative dflux_right = FluxInviscidDotNormal_fwd(gas, right, dright, normal);
310 
311   CeedScalar u_left   = Dot3(left.Y.velocity, normal);
312   CeedScalar u_right  = Dot3(right.Y.velocity, normal);
313   CeedScalar du_left  = Dot3(dleft.Y.velocity, normal);
314   CeedScalar du_right = Dot3(dright.Y.velocity, normal);
315 
316   CeedScalar s_left, ds_left, s_right, ds_right;
317   ComputeHLLSpeeds_Roe_fwd(gas, left, dleft, u_left, du_left, right, dright, u_right, du_right, &s_left, &ds_left, &s_right, &ds_right);
318 
319   // Contact wave speed; Toro (10.37)
320   CeedScalar rhou_left = left.U.density * u_left, drhou_left = left.U.density * du_left + dleft.U.density * u_left;
321   CeedScalar rhou_right = right.U.density * u_right, drhou_right = right.U.density * du_right + dright.U.density * u_right;
322   CeedScalar numer = right.Y.pressure - left.Y.pressure  //
323                      + rhou_left * (s_left - u_left)     //
324                      - rhou_right * (s_right - u_right);
325   CeedScalar dnumer = dright.Y.pressure - dleft.Y.pressure                                //
326                       + rhou_left * (ds_left - du_left) + drhou_left * (s_left - u_left)  //
327                       - rhou_right * (ds_right - du_right) - drhou_right * (s_right - u_right);
328   CeedScalar denom  = left.U.density * (s_left - u_left) - right.U.density * (s_right - u_right);
329   CeedScalar ddenom = left.U.density * (ds_left - du_left) + dleft.U.density * (s_left - u_left)  //
330                       - right.U.density * (ds_right - du_right) - dright.U.density * (s_right - u_right);
331   CeedScalar s_star  = numer / denom;
332   CeedScalar ds_star = dnumer / denom - numer / Square(denom) * ddenom;
333 
334   // Compute HLLC flux
335   if (0 <= s_left) {
336     return dflux_left;
337   } else if (0 <= s_star) {
338     return RiemannFlux_HLLC_Star_fwd(gas, left, dleft, flux_left, dflux_left, normal, u_left, du_left, s_left, ds_left, s_star, ds_star);
339   } else if (0 <= s_right) {
340     return RiemannFlux_HLLC_Star_fwd(gas, right, dright, flux_right, dflux_right, normal, u_right, du_right, s_right, ds_right, s_star, ds_star);
341   } else {
342     return dflux_right;
343   }
344 }
345