ryujin 2.1.1 revision ee5cbcbf2346c1299c942d0e1f13b46449973c18
Loading...
Searching...
No Matches
initial_state_exact_riemann_solution.h
Go to the documentation of this file.
1//
2// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3// Copyright (C) 2025 by the ryujin authors
4// Copyright (C) 2025 by Triad National Security, LLC
5//
6
7#pragma once
8
9#include <compile_time_options.h>
10
12
13#include <deal.II/base/tensor.h>
14
15#include <cmath>
16
17// #define DEBUG_SOLUTION
18
19namespace ryujin
20{
21 namespace EulerInitialStates
22 {
35 template <typename Description, int dim, typename Number>
36 class ExactRiemannSolution : public InitialState<Description, dim, Number>
37 {
38 public:
43
45 using View = typename HyperbolicSystem::template View<dim, Number>;
46 using state_type = typename View::state_type;
47
48 using ScalarNumber = typename View::ScalarNumber;
49
50
51 ExactRiemannSolution(const HyperbolicSystem &hyperbolic_system,
52 const std::string subsection)
53 : InitialState<Description, dim, Number>("exact riemann solution",
54 subsection)
55 , hyperbolic_system_(hyperbolic_system)
56 {
57 gamma_ = 1.4;
58 if constexpr (!View::have_gamma) {
59 this->add_parameter("gamma", gamma_, "The ratio of specific heats");
60 }
61
62 primitive_left_[0] = 1.4;
63 primitive_left_[1] = 0.0;
64 primitive_left_[2] = 1.0;
65 this->add_parameter("primitive state left",
66 primitive_left_,
67 "1d primitive state [rho, u, p] (for the "
68 "polytropic gas EOS) on the left");
69
70 primitive_right_[0] = 1.4;
71 primitive_right_[1] = 0.0;
72 primitive_right_[2] = 1.0;
73 this->add_parameter("primitive state right",
74 primitive_right_,
75 "1d primitive state [rho, u, p] (for the "
76 "polytropic gas EOS) on the right");
77
78 // Convert the primitive states to conserved states
79 const auto prepare_riemann_data = [&]() {
80 const auto view = hyperbolic_system_.template view<dim, Number>();
81 if constexpr (View::have_gamma) {
82 gamma_ = view.gamma();
83 }
84
85 const Number p_L = primitive_left_[2];
86 const Number p_R = primitive_right_[2];
87
88 p_star_ = compute_pstar(p_L, p_R, primitive_left_, primitive_right_);
89
90 const Number u_L = primitive_left_[1];
91 u_star_ = u_L - fZofP(p_star_, primitive_left_);
92
93#ifdef DEBUG_SOLUTION
94 const Number u_R = primitive_right_[1];
95 std::cout << "left data = " << primitive_left_
96 << "\nright data = " << primitive_right_
97 << "\np_star = " << p_star_
98 << "\nu_star = " << u_star_
99 << "\nVerifying u_star = "
100 << u_R + fZofP(p_star_, primitive_right_) << std::endl;
101#endif
102
103 lambda_left_minus_ = lambda(p_star_, primitive_left_, -1.);
104 lambda_left_plus_ =
105 lambda_intermediate(p_star_, primitive_left_, -1.);
106 lambda_right_minus_ =
107 lambda_intermediate(p_star_, primitive_right_, 1.);
108 lambda_right_plus_ = lambda(p_star_, primitive_right_, 1.);
109
110
111#ifdef DEBUG_SOLUTION
112 std::cout << "lambda_left_minus = " << lambda_left_minus_
113 << "\nlambda_left_plus = " << lambda_left_plus_
114 << "\nlambda_right_minus = " << lambda_right_minus_
115 << "\nlambda_right_plus = " << lambda_right_plus_
116 << std::endl;
117#endif
118 };
119
120 this->parse_parameters_call_back.connect(prepare_riemann_data);
121 prepare_riemann_data();
122 }
123
124
125 state_type compute(const dealii::Point<dim> &point, Number t) final
126 {
127 const auto view = hyperbolic_system_.template view<dim, Number>();
128
129 const double &x = point[0];
130
131 const Number xi = x / t;
132
133 dealii::Tensor<1, 3, Number> primitive_state;
134
135 if (t < 1.e-14 && x < 0.) {
136 primitive_state = primitive_left_;
137#ifdef DEBUG_SOLUTION
138 std::cout << "Left primitive state: " << primitive_state << std::endl;
139#endif
140
141 } else if (t < 1.e-14 && x > 0.) {
142 primitive_state = primitive_right_;
143#ifdef DEBUG_SOLUTION
144 std::cout << "Right primitive state: " << primitive_state
145 << std::endl;
146#endif
147
148 } else if (xi < lambda_left_minus_) {
149 /* Left state: */
150 primitive_state = primitive_left_;
151#ifdef DEBUG_SOLUTION
152 std::cout << "Left primitive state: " << primitive_state << std::endl;
153#endif
154
155 } else if (xi < lambda_left_plus_) {
156 const auto c_LL =
157 expansion_solution(p_star_, xi, primitive_left_, -1.);
158 primitive_state = c_LL;
159#ifdef DEBUG_SOLUTION
160 std::cout << "Left expansion state: " << primitive_state << std::endl;
161#endif
162
163 } else if (xi < u_star_) {
164 primitive_state = cstar_solution(p_star_, u_star_, primitive_left_);
165
166 const Number p_L = primitive_left_[2];
167 if (p_star_ < p_L)
168 primitive_state = expansion_solution(
169 p_star_, lambda_left_plus_, primitive_left_, -1.);
170#ifdef DEBUG_SOLUTION
171 std::cout << "Left cstar state: " << primitive_state << std::endl;
172#endif
173
174 } else if (xi < lambda_right_minus_) {
175 primitive_state = cstar_solution(p_star_, u_star_, primitive_right_);
176
177 const Number p_R = primitive_right_[2];
178 if (p_star_ < p_R)
179 primitive_state = expansion_solution(
180 p_star_, lambda_right_minus_, primitive_right_, 1.);
181#ifdef DEBUG_SOLUTION
182 std::cout << "Right cstar state: " << primitive_state << std::endl;
183#endif
184
185 } else if (xi < lambda_right_plus_) {
186 primitive_state =
187 expansion_solution(p_star_, xi, primitive_right_, 1.);
188#ifdef DEBUG_SOLUTION
189 std::cout << "Right expansion state: " << primitive_state
190 << std::endl;
191#endif
192
193 } else {
194 /* Right state: */
195 primitive_state = primitive_right_;
196#ifdef DEBUG_SOLUTION
197 std::cout << "Right primitive state: " << primitive_state
198 << std::endl;
199#endif
200 }
201
202 using state_type_1d =
203 typename HyperbolicSystem::template View<1, Number>::state_type;
204 static_assert(state_type_1d::dimension <=
205 dealii::Tensor<1, 3, Number>::dimension);
206
207 state_type_1d result;
208 for (unsigned int i = 0; i < state_type_1d::dimension; ++i)
209 result[i] = primitive_state[i];
210 return view.from_initial_state(result);
211 }
212
213 private:
215
219
220 Number gamma_;
221
222 dealii::Tensor<1, 3, Number> primitive_left_;
223 dealii::Tensor<1, 3, Number> primitive_right_;
224
226
230
231 const HyperbolicSystem &hyperbolic_system_;
232
233 Number p_star_;
234 Number u_star_;
235 Number lambda_left_minus_;
236 Number lambda_left_plus_;
237 Number lambda_right_minus_;
238 Number lambda_right_plus_;
239
241
245
246 Number fZofP(const Number &p_in,
247 const dealii::Tensor<1, 3, Number> &data_in) const
248 {
249 // Get left/right data
250 const Number rho_Z = data_in[0];
251 const Number p_Z = data_in[2];
252
253 const Number c_Z = std::sqrt(gamma_ * p_Z / rho_Z);
254
255 const Number A_Z = 2. / (gamma_ + 1.) / rho_Z;
256 const Number B_Z = (gamma_ - 1.) / (gamma_ + 1.) * p_Z;
257
258 const Number exp = 0.5 * (gamma_ - 1.) / gamma_;
259 Number left_brach = 2. * c_Z / (gamma_ - 1.);
260 left_brach *= (std::pow(p_in / p_Z, exp) - 1.);
261
262 Number f_of_p = (p_in - p_Z) * std::sqrt(A_Z / (p_in + B_Z));
263
264 if (p_in <= p_Z)
265 f_of_p = left_brach;
266
267 return f_of_p;
268 }
269
270
271 Number dfZofP(const Number &p_in,
272 const dealii::Tensor<1, 3, Number> &data_in) const
273 {
274 // Get left/right data
275 const Number rho_Z = data_in[0];
276 const Number p_Z = data_in[2];
277
278 const Number c_Z = std::sqrt(gamma_ * p_Z / rho_Z);
279
280 const Number A_Z = 2. / (gamma_ + 1.) / rho_Z;
281 const Number B_Z = (gamma_ - 1.) / (gamma_ + 1.) * p_Z;
282
283 Number exp = 0.5 * (gamma_ - 1.) / gamma_;
284 Number left_brach = 2. * c_Z / (gamma_ - 1.) * exp;
285 exp -= 1.;
286
287 left_brach *= std::pow(p_in / p_Z, exp - 1.) / p_Z;
288
289 Number right_branch = std::pow(A_Z / (p_in + B_Z), 1.5);
290 right_branch *= (2. * B_Z + p_in + p_Z) / (2. * A_Z);
291
292 Number df_of_p = right_branch;
293
294 if (p_in <= p_Z)
295 df_of_p = left_brach;
296
297 return df_of_p;
298 }
299
300
301 Number dphi(const Number &p_in,
302 const dealii::Tensor<1, 3, Number> &data_left,
303 const dealii::Tensor<1, 3, Number> &data_right) const
304 {
305 return dfZofP(p_in, data_left) + dfZofP(p_in, data_right);
306 }
307
308
309 Number phi(const Number &p_in,
310 const dealii::Tensor<1, 3, Number> &data_left,
311 const dealii::Tensor<1, 3, Number> &data_right) const
312 {
313 const Number u_L = data_left[1];
314 const Number u_R = data_right[1];
315
316 return fZofP(p_in, data_right) + fZofP(p_in, data_left) + u_R - u_L;
317 }
318
319
320 Number lambda(const Number &p_in,
321 const dealii::Tensor<1, 3, Number> &data_in,
322 const Number &sign) const
323 {
324 // Get left/right data
325 const Number rho_Z = data_in[0];
326 const Number u_Z = data_in[1];
327 const Number p_Z = data_in[2];
328
329 const Number c_Z = std::sqrt(gamma_ * p_Z / rho_Z);
330
331 const Number radicand =
332 1. + 0.5 * (gamma_ + 1.) / gamma_ * std::max(p_in / p_Z - 1., 0.);
333
334 return u_Z + sign * c_Z * std::sqrt(radicand);
335 }
336
337
338 Number lambda_intermediate(const Number &p_in,
339 const dealii::Tensor<1, 3, Number> &data_in,
340 const Number &sign) const
341 {
342 const Number rho_Z = data_in[0];
343 const Number u_Z = data_in[1];
344 const Number p_Z = data_in[2];
345
346 const Number c_Z = std::sqrt(gamma_ * p_Z / rho_Z);
347
348 const auto lambda_value = lambda(p_in, data_in, sign);
349
350 const Number f_of_p = fZofP(p_in, data_in);
351
352 const Number exp = 0.5 * (gamma_ - 1.) / gamma_;
353 const Number expansion_speed =
354 u_Z + sign * (f_of_p + c_Z * std::pow(p_in / p_Z, exp));
355
356 Number result = lambda_value;
357 if (p_in < p_Z)
358 result = expansion_speed;
359
360 return result;
361 }
362
363
364 dealii::Tensor<1, 3, Number>
365 cstar_solution(const Number &p_star,
366 const Number &u_star,
367 const dealii::Tensor<1, 3, Number> &data_in) const
368 {
369 const Number rho_Z = data_in[0];
370 const Number p_Z = data_in[2];
371
372 // Define rho_star
373 const Number p_ratio = p_star / p_Z;
374 const Number gamma_ratio = (gamma_ - 1.) / (gamma_ + 1.);
375
376 const Number numerator = rho_Z * (p_ratio + gamma_ratio);
377 const Number denominator = gamma_ratio * p_ratio + 1.;
378
379 Number rho_star = numerator / denominator;
380
381 auto result = data_in;
382 result[0] = rho_star;
383 result[1] = u_star;
384 result[2] = p_star;
385
386 return result;
387 }
388
389
390 dealii::Tensor<1, 3, Number>
391 expansion_solution(const Number & /*p_star*/,
392 const Number &xi,
393 const dealii::Tensor<1, 3, Number> &data_in,
394 const Number &sign) const
395 {
396 const Number rho_Z = data_in[0];
397 const Number u_Z = data_in[1];
398 const Number p_Z = data_in[2];
399
400 const Number c_Z = std::sqrt(gamma_ * p_Z / rho_Z);
401
402 // Define rho_expansion
403 const Number gamma_ratio = (gamma_ - 1.) / (gamma_ + 1.);
404
405 const Number first = 2. / (gamma_ + 1.);
406 const Number second = gamma_ratio / c_Z * (u_Z - xi);
407 const Number exp = 2. / (gamma_ - 1.);
408
409 Number rho_expansion = rho_Z * std::pow(first - sign * second, exp);
410
411 // Define p_expansion
412 const Number factor = p_Z / std::pow(rho_Z, gamma_);
413 const Number p_expansion = factor * std::pow(rho_expansion, gamma_);
414
415 // Define u_expansion
416 const Number u_expansion = u_Z + sign * fZofP(p_expansion, data_in);
417
418 auto result = data_in;
419 result[0] = rho_expansion;
420 result[1] = u_expansion;
421 result[2] = p_expansion;
422
423 return result;
424 }
425
426
430 double compute_pstar(double p_1,
431 double p_2,
432 dealii::Tensor<1, 3, Number> data_1,
433 dealii::Tensor<1, 3, Number> data_2)
434 {
435 constexpr Number eps = std::numeric_limits<Number>::epsilon();
436
437 // Ensure that p_1 <= p_2
438
439 if (p_1 > p_2) {
440 std::swap(p_1, p_2);
441 std::swap(data_1, data_2);
442 }
443
444#ifdef DEBUG
445 {
446 const double phi_1 = phi(p_1, data_1, data_2);
447 const double phi_2 = phi(p_2, data_1, data_2);
448 Assert(phi_1 * phi_2 <= 0.,
449 dealii::ExcMessage(
450 "Euler::ExactRiemannSolver: failed to compute p_star."));
451 }
452#endif
453
454 //
455 // We simply compute the root of phi with a bisection method down
456 // to machine precision. This is not terribly efficient but luckily
457 // happens only once during initialization.
458 //
459
460#ifdef DEBUG_SOLUTION
461 std::cout << "Computing p_star with a bisection method." << std::endl;
462#endif
463
464 unsigned int iter = 0;
465 for (; iter < 200; ++iter) {
466
467 // Check for convergence:
468 if (std::abs(p_2 - p_1) < 10. * eps * std::max(p_1, p_2)) {
469 break;
470 }
471
472 const double phi_2 = phi(p_2, data_1, data_2);
473
474#ifdef DEBUG_SOLUTION
475 const double phi_1 = phi(p_1, data_1, data_2);
476
477 std::cout << "\niter: " << iter << "\n";
478 std::cout << "p_1: " << p_1 << "\n";
479 std::cout << "p_2: " << p_2 << "\n";
480 std::cout << "phi_1: " << phi_1 << "\n";
481 std::cout << "phi_2: " << phi_2 << "\n";
482#endif
483
484 const auto p_m = 0.5 * (p_2 + p_1);
485 const double phi_m = phi(p_m, data_1, data_2);
486
487 if (phi_m * phi_2 >= 0.) {
488 p_2 = p_m;
489 } else {
490 p_1 = p_m;
491 }
492 }
493
494#ifdef DEBUG_SOLUTION
495 const double phi_2 = phi(p_2, data_1, data_2);
496 std::cout << "After " << iter << " iterations:"
497 << "\np_star = " << p_2 << "\nphi(p_star) = " << phi_2
498 << "\n|p_2 - p_1| = " << std::abs(p_2 - p_1) << std::endl;
499#endif
500
501 return p_2;
502 }
503
505 };
506 } // namespace EulerInitialStates
507} // namespace ryujin
typename HyperbolicSystem::template View< dim, Number > View
ExactRiemannSolution(const HyperbolicSystem &hyperbolic_system, const std::string subsection)
state_type compute(const dealii::Point< dim > &point, Number t) final
Euler::HyperbolicSystem HyperbolicSystem
Definition description.h:34