ryujin 2.1.1 revision 9dcb748690310d6a540ebb8b066d1a0834fc7604
riemann_solver.template.h
Go to the documentation of this file.
1//
2// SPDX-License-Identifier: MIT
3// Copyright (C) 2020 - 2023 by the ryujin authors
4//
5
6#pragma once
7
8#include <compile_time_options.h>
9
10#include "riemann_solver.h"
11
12#include <newton.h>
13#include <simd.h>
14
15// #define DEBUG_RIEMANN_SOLVER
16
17namespace ryujin
18{
19 namespace EulerAEOS
20 {
21 /*
22 * The RiemannSolver is a guaranteed maximal wavespeed (GMS) estimate
23 * for the extended Riemann problem outlined in
24 * @cite ClaytonGuermondPopov-2022.
25 *
26 * In contrast to the algorithm outlined in above reference the
27 * algorithm takes a couple of shortcuts to significantly decrease the
28 * computational footprint. These simplifications still guarantee that
29 * we have an upper bound on the maximal wavespeed - but the number
30 * bound might be larger. In particular:
31 *
32 * - We do not check and treat the case phi(p_min) > 0. This
33 * corresponds to two expansion waves, see ยง5.2 in the reference. In
34 * this case we have
35 *
36 * 0 < p_star < p_min <= p_max.
37 *
38 * And due to the fact that p_star < p_min the wavespeeds reduce to
39 * a left wavespeed v_L - a_L and right wavespeed v_R + a_R. This
40 * implies that it is sufficient to set p_2 to ANY value provided
41 * that p_2 <= p_min hold true in order to compute the correct
42 * wavespeed.
43 *
44 * If p_2 > p_min then a more pessimistic bound is computed.
45 *
46 * - FIXME: Simplification in p_star_RS
47 */
48
49
50 template <int dim, typename Number>
51 DEAL_II_ALWAYS_INLINE inline Number
52 RiemannSolver<dim, Number>::c(const Number gamma) const
53 {
54 /*
55 * We implement the continuous and monotonic function c(gamma) as
56 * defined in (A.3) on page A469 of @cite ClaytonGuermondPopov-2022.
57 * But with a simplified quick cut-off for the case gamma > 3:
58 *
59 * c(gamma)^2 = 1 for gamma <= 5 / 3
60 * c(gamma)^2 = (3 * gamma + 11) / (6 * gamma + 6) in between
61 * c(gamma)^2 = max(1/2, 5 / 6 - slope (gamma - 3)) for gamma > 3
62 *
63 * Due to the fact that the function is monotonic we can simply clip
64 * the values without checking the conditions:
65 */
66
67 constexpr ScalarNumber slope =
68 ScalarNumber(-0.34976871477801828189920753948709);
69
70 const Number first_radicand = (ScalarNumber(3.) * gamma + Number(11.)) /
71 (ScalarNumber(6.) * gamma + Number(6.));
72
73 const Number second_radicand =
74 Number(5. / 6.) + slope * (gamma - Number(3.));
75
76 Number radicand = std::min(first_radicand, second_radicand);
77 radicand = std::min(Number(1.), radicand);
78 radicand = std::max(Number(1. / 2.), radicand);
79
80 return std::sqrt(radicand);
81 }
82
83
84 template <int dim, typename Number>
85 DEAL_II_ALWAYS_INLINE inline Number RiemannSolver<dim, Number>::alpha(
86 const Number &rho, const Number &gamma, const Number &a) const
87 {
88 const auto interpolation_b = hyperbolic_system.eos_interpolation_b();
89
90 const Number numerator =
91 ScalarNumber(2.) * a * (Number(1.) - interpolation_b * rho);
92
93 const Number denominator = gamma - Number(1.);
94
95 return numerator / denominator;
96 }
97
98
99 template <int dim, typename Number>
100 DEAL_II_ALWAYS_INLINE inline Number
102 const primitive_type &riemann_data_i,
103 const primitive_type &riemann_data_j) const
104 {
105 const auto &[rho_i, u_i, p_i, gamma_i, a_i] = riemann_data_i;
106 const auto &[rho_j, u_j, p_j, gamma_j, a_j] = riemann_data_j;
107 const auto alpha_i = alpha(rho_i, gamma_i, a_i);
108 const auto alpha_j = alpha(rho_j, gamma_j, a_j);
109
110 /*
111 * First get p_min, p_max.
112 *
113 * Then, we get gamma_min/max, and alpha_min/max. Note that the
114 * *_min/max values are associated with p_min/max and are not
115 * necessarily the minimum/maximum of *_i vs *_j.
116 */
117
118 const Number p_min = std::min(p_i, p_j);
119 const Number p_max = std::max(p_i, p_j);
120
121 const Number gamma_min =
122 dealii::compare_and_apply_mask<dealii::SIMDComparison::less_than>(
123 p_i, p_j, gamma_i, gamma_j);
124
125 const Number alpha_min =
126 dealii::compare_and_apply_mask<dealii::SIMDComparison::less_than>(
127 p_i, p_j, alpha_i, alpha_j);
128
129 const Number alpha_hat_min = c(gamma_min) * alpha_min;
130
131 const Number alpha_max = dealii::compare_and_apply_mask<
132 dealii::SIMDComparison::greater_than_or_equal>(
133 p_i, p_j, alpha_i, alpha_j);
134
135 const Number gamma_m = std::min(gamma_i, gamma_j);
136 const Number gamma_M = std::max(gamma_i, gamma_j);
137
138 const Number numerator =
139 positive_part(alpha_hat_min + alpha_max - (u_j - u_i));
140
141 const Number p_ratio = p_min / p_max;
142
143 /*
144 * Here, we use a trick: The r-factor only shows up in the formula
145 * for the case \gamma_min = \gamma_m, otherwise the r-factor
146 * vanishes. We can accomplish this by using the following modified
147 * exponent (where we substitute gamma_m by gamma_min):
148 */
149 const Number r_exponent =
150 (gamma_M - gamma_min) / (ScalarNumber(2.) * gamma_min * gamma_M);
151
152 /*
153 * Compute (5.7) first formula for \tilde p_1^\ast and (5.8)
154 * second formula for \tilde p_2^\ast at the same time:
155 */
156
157 const Number first_exponent =
158 (gamma_M - Number(1.)) / (ScalarNumber(2.) * gamma_M);
159 const Number first_exponent_inverse = Number(1.) / first_exponent;
160
161 const Number first_denom =
162 alpha_hat_min * ryujin::pow(p_ratio, r_exponent - first_exponent) +
163 alpha_max;
164
165 const Number p_1_tilde =
166 p_max * ryujin::pow(numerator / first_denom, first_exponent_inverse);
167#ifdef DEBUG_RIEMANN_SOLVER
168 std::cout << "RS p_1_tilde = " << p_1_tilde << "\n";
169#endif
170
171 /*
172 * Compute (5.7) second formula for \tilde p_2^\ast and (5.8) first
173 * formula for \tilde p_1^\ast at the same time:
174 */
175
176 const Number second_exponent =
177 (gamma_m - Number(1.)) / (ScalarNumber(2.) * gamma_m);
178 const Number second_exponent_inverse = Number(1.) / second_exponent;
179
180 Number second_denom =
181 alpha_hat_min * ryujin::pow(p_ratio, -second_exponent) +
182 alpha_max * ryujin::pow(p_ratio, r_exponent);
183
184 const Number p_2_tilde = p_max * ryujin::pow(numerator / second_denom,
185 second_exponent_inverse);
186
187#ifdef DEBUG_RIEMANN_SOLVER
188 std::cout << "RS p_2_tilde = " << p_2_tilde << "\n";
189#endif
190
191 return std::min(p_1_tilde, p_2_tilde);
192 }
193
194
195 template <int dim, typename Number>
196 DEAL_II_ALWAYS_INLINE inline Number
198 const primitive_type &riemann_data_i,
199 const primitive_type &riemann_data_j) const
200 {
201 const auto &[rho_i, u_i, p_i, gamma_i, a_i] = riemann_data_i;
202 const auto &[rho_j, u_j, p_j, gamma_j, a_j] = riemann_data_j;
203
204 const Number gamma_m = std::min(gamma_i, gamma_j);
205
206 const Number alpha_hat_i = c(gamma_i) * alpha(rho_i, gamma_i, a_i);
207 const Number alpha_hat_j = c(gamma_j) * alpha(rho_j, gamma_j, a_j);
208
209 /*
210 * Compute (5.10) formula for \tilde p_1^\ast:
211 *
212 * Cost: 2x pow, 4x division, 0x sqrt
213 */
214
215 const Number exponent =
216 (gamma_m - Number(1.)) / (ScalarNumber(2.) * gamma_m);
217 const Number exponent_inverse = Number(1.) / exponent;
218
219 const Number numerator =
220 positive_part(alpha_hat_i + alpha_hat_j - (u_j - u_i));
221
222 const Number denominator =
223 alpha_hat_i * ryujin::pow(p_i / p_j, -exponent) + alpha_hat_j;
224
225 const Number p_1_tilde =
226 p_j * ryujin::pow(numerator / denominator, exponent_inverse);
227
228#ifdef DEBUG_RIEMANN_SOLVER
229 std::cout << "SS p_1_tilde = " << p_1_tilde << "\n";
230#endif
231
232 const auto p_2_tilde = p_star_failsafe(riemann_data_i, riemann_data_j);
233
234 return std::min(p_1_tilde, p_2_tilde);
235 }
236
237
238 template <int dim, typename Number>
239 DEAL_II_ALWAYS_INLINE inline Number
241 const primitive_type &riemann_data_i,
242 const primitive_type &riemann_data_j) const
243 {
244 const auto interpolation_b = hyperbolic_system.eos_interpolation_b();
245
246 const auto &[rho_i, u_i, p_i, gamma_i, a_i] = riemann_data_i;
247 const auto &[rho_j, u_j, p_j, gamma_j, a_j] = riemann_data_j;
248
249 /*
250 * Compute (5.11) formula for \tilde p_2^\ast:
251 *
252 * Cost: 0x pow, 3x division, 3x sqrt
253 */
254
255 const Number p_max = std::max(p_i, p_j);
256
257 Number radicand_i =
258 ScalarNumber(2.) * (Number(1.) - interpolation_b * rho_i) * p_max;
259 radicand_i /= rho_i * ((gamma_i + Number(1.)) * p_max +
260 (gamma_i - Number(1.)) * p_i);
261
262 const Number x_i = std::sqrt(radicand_i);
263
264 Number radicand_j =
265 ScalarNumber(2.) * (Number(1.) - interpolation_b * rho_j) * p_max;
266 radicand_j /= rho_j * ((gamma_j + Number(1.)) * p_max +
267 (gamma_j - Number(1.)) * p_j);
268
269 const Number x_j = std::sqrt(radicand_j);
270
271 const Number a = x_i + x_j;
272 const Number b = u_j - u_i;
273 const Number c = -p_i * x_i - p_j * x_j;
274
275 const Number base = (-b + std::sqrt(b * b - ScalarNumber(4.) * a * c)) /
276 (ScalarNumber(2.) * a);
277 const Number p_2_tilde = base * base;
278
279#ifdef DEBUG_RIEMANN_SOLVER
280 std::cout << "SS p_2_tilde = " << p_2_tilde << "\n";
281#endif
282 return p_2_tilde;
283 }
284
285
286 template <int dim, typename Number>
287 DEAL_II_ALWAYS_INLINE inline Number
289 const primitive_type &riemann_data_i,
290 const primitive_type &riemann_data_j) const
291 {
292 const auto &[rho_i, u_i, p_i, gamma_i, a_i] = riemann_data_i;
293 const auto &[rho_j, u_j, p_j, gamma_j, a_j] = riemann_data_j;
294 const auto alpha_i = alpha(rho_i, gamma_i, a_i);
295 const auto alpha_j = alpha(rho_j, gamma_j, a_j);
296
297 /*
298 * First get p_min, p_max.
299 *
300 * Then, we get gamma_min/max, and alpha_min/max. Note that the
301 * *_min/max values are associated with p_min/max and are not
302 * necessarily the minimum/maximum of *_i vs *_j.
303 */
304
305 const Number p_min = std::min(p_i, p_j);
306 const Number p_max = std::max(p_i, p_j);
307
308 const Number gamma_min =
309 dealii::compare_and_apply_mask<dealii::SIMDComparison::less_than>(
310 p_i, p_j, gamma_i, gamma_j);
311
312 const Number alpha_min =
313 dealii::compare_and_apply_mask<dealii::SIMDComparison::less_than>(
314 p_i, p_j, alpha_i, alpha_j);
315
316 const Number alpha_hat_min = c(gamma_min) * alpha_min;
317
318 const Number gamma_max = dealii::compare_and_apply_mask<
319 dealii::SIMDComparison::greater_than_or_equal>(
320 p_i, p_j, gamma_i, gamma_j);
321
322 const Number alpha_max = dealii::compare_and_apply_mask<
323 dealii::SIMDComparison::greater_than_or_equal>(
324 p_i, p_j, alpha_i, alpha_j);
325
326 const Number alpha_hat_max = c(gamma_max) * alpha_max;
327
328 const Number gamma_m = std::min(gamma_i, gamma_j);
329 const Number gamma_M = std::max(gamma_i, gamma_j);
330
331 const Number p_ratio = p_min / p_max;
332
333 /*
334 * Here, we use a trick: The r-factor only shows up in the formula
335 * for the case \gamma_min = \gamma_m, otherwise the r-factor
336 * vanishes. We can accomplish this by using the following modified
337 * exponent (where we substitute gamma_m by gamma_min):
338 */
339 const Number r_exponent =
340 (gamma_M - gamma_min) / (ScalarNumber(2.) * gamma_min * gamma_M);
341
342 /*
343 * Compute a simultaneous upper bound on
344 * (5.7) second formula for \tilde p_2^\ast
345 * (5.8) first formula for \tilde p_1^\ast
346 * (5.11) formula for \tilde p_2^\ast
347 */
348
349 const Number exponent =
350 (gamma_m - Number(1.)) / (ScalarNumber(2.) * gamma_m);
351 const Number exponent_inverse = Number(1.) / exponent;
352
353 const Number numerator =
354 positive_part(alpha_hat_min + /*SIC!*/ alpha_max - (u_j - u_i));
355
356 Number denominator = alpha_hat_min * ryujin::pow(p_ratio, -exponent) +
357 alpha_hat_max * ryujin::pow(p_ratio, r_exponent);
358
359 const Number p_tilde =
360 p_max * ryujin::pow(numerator / denominator, exponent_inverse);
361
362#ifdef DEBUG_RIEMANN_SOLVER
363 std::cout << "IN p_*_tilde = " << p_tilde << "\n";
364#endif
365
366 return p_tilde;
367 }
368
369
370 template <int dim, typename Number>
371 DEAL_II_ALWAYS_INLINE inline Number
372 RiemannSolver<dim, Number>::f(const primitive_type &riemann_data,
373 const Number p_star) const
374 {
375 const auto interpolation_b = hyperbolic_system.eos_interpolation_b();
376
377 const auto &[rho, u, p, gamma, a] = riemann_data;
378
379 const Number one_minus_b_rho = Number(1.) - interpolation_b * rho;
380
381 const Number Az =
382 ScalarNumber(2.) * one_minus_b_rho / (rho * (gamma + Number(1.)));
383
384 const Number Bz = (gamma - Number(1.)) / (gamma + Number(1.)) * p;
385
386 const Number radicand = Az / (p_star + Bz);
387
388 const Number true_value = (p_star - p) * std::sqrt(radicand);
389
390 const auto exponent = ScalarNumber(0.5) * (gamma - Number(1.)) / gamma;
391 const Number factor = ryujin::pow(p_star / p, exponent) - Number(1.);
392 const auto false_value = ScalarNumber(2.) * a * one_minus_b_rho * factor /
393 (gamma - Number(1.));
394
395 return dealii::compare_and_apply_mask<
396 dealii::SIMDComparison::greater_than_or_equal>(
397 p_star, p, true_value, false_value);
398 }
399
400
401 template <int dim, typename Number>
402 DEAL_II_ALWAYS_INLINE inline Number
403 RiemannSolver<dim, Number>::phi(const primitive_type &riemann_data_i,
404 const primitive_type &riemann_data_j,
405 const Number p_in) const
406 {
407 const Number &u_i = riemann_data_i[1];
408 const Number &u_j = riemann_data_j[1];
409
410 return f(riemann_data_i, p_in) + f(riemann_data_j, p_in) + u_j - u_i;
411 }
412
413
414 template <int dim, typename Number>
415 DEAL_II_ALWAYS_INLINE inline Number
417 const primitive_type &riemann_data_i,
418 const primitive_type &riemann_data_j) const
419 {
420 const auto interpolation_b = hyperbolic_system.eos_interpolation_b();
421
422 const auto &[rho_i, u_i, p_i, gamma_i, a_i] = riemann_data_i;
423 const auto &[rho_j, u_j, p_j, gamma_j, a_j] = riemann_data_j;
424
425 const Number p_max = std::max(p_i, p_j);
426
427 const Number radicand_inverse_i =
428 ScalarNumber(0.5) * rho_i / (Number(1.) - interpolation_b * rho_i) *
429 ((gamma_i + Number(1.)) * p_max + (gamma_i - Number(1.)) * p_i);
430
431 const Number value_i = (p_max - p_i) / std::sqrt(radicand_inverse_i);
432
433 const Number radicand_jnverse_j =
434 ScalarNumber(0.5) * rho_j / (Number(1.) - interpolation_b * rho_j) *
435 ((gamma_j + Number(1.)) * p_max + (gamma_j - Number(1.)) * p_j);
436
437 const Number value_j = (p_max - p_j) / std::sqrt(radicand_jnverse_j);
438
439 return value_i + value_j + u_j - u_i;
440 }
441
442
443 template <int dim, typename Number>
444 DEAL_II_ALWAYS_INLINE inline Number
446 const primitive_type &riemann_data, const Number p_star) const
447 {
448 const auto &[rho, u, p, gamma, a] = riemann_data;
449
450 const auto factor =
451 ScalarNumber(0.5) * (gamma + ScalarNumber(1.)) / gamma;
452
453 const Number tmp = positive_part((p_star - p) / p);
454
455 return u - a * std::sqrt(Number(1.) + factor * tmp);
456 }
457
458
459 template <int dim, typename Number>
460 DEAL_II_ALWAYS_INLINE inline Number
462 const Number p_star) const
463 {
464 const auto &[rho, u, p, gamma, a] = riemann_data;
465
466 const auto factor =
467 ScalarNumber(0.5) * (gamma + ScalarNumber(1.)) / gamma;
468
469 const Number tmp = positive_part((p_star - p) / p);
470
471 return u + a * std::sqrt(Number(1.) + factor * tmp);
472 }
473
474
475 template <int dim, typename Number>
476 DEAL_II_ALWAYS_INLINE inline Number
478 const primitive_type &riemann_data_i,
479 const primitive_type &riemann_data_j,
480 const Number p_star) const
481 {
482 const Number nu_11 = lambda1_minus(riemann_data_i, p_star);
483 const Number nu_32 = lambda3_plus(riemann_data_j, p_star);
484
485 return std::max(positive_part(nu_32), negative_part(nu_11));
486 }
487
488
489 template <int dim, typename Number>
491 const primitive_type &riemann_data_i,
492 const primitive_type &riemann_data_j) const
493 {
494 const auto &[rho_i, u_i, p_i, gamma_i, a_i] = riemann_data_i;
495 const auto &[rho_j, u_j, p_j, gamma_j, a_j] = riemann_data_j;
496
497#ifdef DEBUG_RIEMANN_SOLVER
498 std::cout << "rho_left: " << rho_i << std::endl;
499 std::cout << "u_left: " << u_i << std::endl;
500 std::cout << "p_left: " << p_i << std::endl;
501 std::cout << "gamma_left: " << gamma_i << std::endl;
502 std::cout << "a_left: " << a_i << std::endl;
503 std::cout << "rho_right: " << rho_j << std::endl;
504 std::cout << "u_right: " << u_j << std::endl;
505 std::cout << "p_right: " << p_j << std::endl;
506 std::cout << "gamma_right: " << gamma_j << std::endl;
507 std::cout << "a_right: " << a_j << std::endl;
508#endif
509
510 const Number p_max = std::max(p_i, p_j);
511 const Number phi_p_max = phi_of_p_max(riemann_data_i, riemann_data_j);
512
513 if (!hyperbolic_system.compute_strict_bounds()) {
514#ifdef DEBUG_RIEMANN_SOLVER
515 const Number p_star_RS = p_star_RS_full(riemann_data_i, riemann_data_j);
516 const Number p_star_SS = p_star_SS_full(riemann_data_i, riemann_data_j);
517 const Number p_debug =
518 dealii::compare_and_apply_mask<dealii::SIMDComparison::less_than>(
519 phi_p_max, Number(0.), p_star_SS, std::min(p_max, p_star_RS));
520 std::cout << " p^*_debug = " << p_debug << "\n";
521 std::cout << " phi(p_*_d) = "
522 << phi(riemann_data_i, riemann_data_j, p_debug) << "\n";
523 std::cout << "-> lambda_deb = "
524 << compute_lambda(riemann_data_i, riemann_data_j, p_debug)
525 << std::endl;
526#endif
527
528 const Number p_star_tilde =
529 p_star_interpolated(riemann_data_i, riemann_data_j);
530 const Number p_star_backup =
531 p_star_failsafe(riemann_data_i, riemann_data_j);
532
533 const Number p_2 =
534 dealii::compare_and_apply_mask<dealii::SIMDComparison::less_than>(
535 phi_p_max,
536 Number(0.),
537 std::min(p_star_tilde, p_star_backup),
538 std::min(p_max, p_star_tilde));
539
540#ifdef DEBUG_RIEMANN_SOLVER
541 std::cout << " p^*_tilde = " << p_2 << "\n";
542 std::cout << " phi(p_*_t) = "
543 << phi(riemann_data_i, riemann_data_j, p_2) << "\n";
544 std::cout << "-> lambda_max = "
545 << compute_lambda(riemann_data_i, riemann_data_j, p_2) << "\n"
546 << std::endl;
547#endif
548
549 return compute_lambda(riemann_data_i, riemann_data_j, p_2);
550 }
551
552 const Number p_star_RS = p_star_RS_full(riemann_data_i, riemann_data_j);
553 const Number p_star_SS = p_star_SS_full(riemann_data_i, riemann_data_j);
554
555 const Number p_2 =
556 dealii::compare_and_apply_mask<dealii::SIMDComparison::less_than>(
557 phi_p_max, Number(0.), p_star_SS, std::min(p_max, p_star_RS));
558
559#ifdef DEBUG_RIEMANN_SOLVER
560 std::cout << " p^*_tilde = " << p_2 << "\n";
561 std::cout << " phi(p_*_t) = "
562 << phi(riemann_data_i, riemann_data_j, p_2) << "\n";
563 std::cout << "-> lambda_max = "
564 << compute_lambda(riemann_data_i, riemann_data_j, p_2)
565 << std::endl;
566#endif
567
568 return compute_lambda(riemann_data_i, riemann_data_j, p_2);
569 }
570
571 } // namespace EulerAEOS
572} // namespace ryujin
Number p_star_RS_full(const primitive_type &riemann_data_i, const primitive_type &riemann_data_j) const
Number lambda1_minus(const primitive_type &riemann_data, const Number p_star) const
Number alpha(const Number &rho, const Number &gamma, const Number &a) const
Number p_star_failsafe(const primitive_type &riemann_data_i, const primitive_type &riemann_data_j) const
Number p_star_SS_full(const primitive_type &riemann_data_i, const primitive_type &riemann_data_j) const
Number lambda3_plus(const primitive_type &primitive_state, const Number p_star) const
typename HyperbolicSystemView::ScalarNumber ScalarNumber
Number p_star_interpolated(const primitive_type &riemann_data_i, const primitive_type &riemann_data_j) const
Number phi_of_p_max(const primitive_type &riemann_data_i, const primitive_type &riemann_data_j) const
Number compute_lambda(const primitive_type &riemann_data_i, const primitive_type &riemann_data_j, const Number p_star) const
std::array< Number, riemann_data_size > primitive_type
Number c(const Number gamma_Z) const
Number compute(const primitive_type &riemann_data_i, const primitive_type &riemann_data_j) const
T pow(const T x, const T b)
DEAL_II_ALWAYS_INLINE Number negative_part(const Number number)
Definition: simd.h:123
DEAL_II_ALWAYS_INLINE Number positive_part(const Number number)
Definition: simd.h:111