ryujin 2.1.1 revision a15074459a388761bd8df6bd4ef7e6abe9d8077b
limiter.h
Go to the documentation of this file.
1//
2// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3// Copyright (C) 2020 - 2024 by the ryujin authors
4//
5
6#pragma once
7
8#include "hyperbolic_system.h"
9
10#include <compile_time_options.h>
12#include <newton.h>
13#include <simd.h>
14
15namespace ryujin
16{
17 namespace EulerAEOS
18 {
19 template <typename ScalarNumber = double>
20 class LimiterParameters : public dealii::ParameterAcceptor
21 {
22 public:
23 LimiterParameters(const std::string &subsection = "/Limiter")
24 : ParameterAcceptor(subsection)
25 {
26 iterations_ = 2;
27 add_parameter(
28 "iterations", iterations_, "Number of limiter iterations");
29
30 if constexpr (std::is_same<ScalarNumber, double>::value)
31 newton_tolerance_ = 1.e-10;
32 else
33 newton_tolerance_ = 1.e-4;
34 add_parameter("newton tolerance",
35 newton_tolerance_,
36 "Tolerance for the quadratic newton stopping criterion");
37
38 newton_max_iterations_ = 2;
39 add_parameter("newton max iterations",
40 newton_max_iterations_,
41 "Maximal number of quadratic newton iterations performed "
42 "during limiting");
43
44 relaxation_factor_ = ScalarNumber(1.);
45 add_parameter("relaxation factor",
46 relaxation_factor_,
47 "Factor for scaling the relaxation window with r_i = "
48 "factor * (m_i/|Omega|)^(1.5/d).");
49 }
50
51 ACCESSOR_READ_ONLY(iterations);
52 ACCESSOR_READ_ONLY(newton_tolerance);
53 ACCESSOR_READ_ONLY(newton_max_iterations);
54 ACCESSOR_READ_ONLY(relaxation_factor);
55
56 private:
57 unsigned int iterations_;
58 ScalarNumber newton_tolerance_;
59 unsigned int newton_max_iterations_;
60 ScalarNumber relaxation_factor_;
61 };
62
63
96 template <int dim, typename Number = double>
97 class Limiter
98 {
99 public:
104
108 static constexpr unsigned int problem_dimension = View::problem_dimension;
109
113 using state_type = typename View::state_type;
114
118 static constexpr unsigned int n_precomputed_values =
120
125
130
135
140
159
163 static constexpr unsigned int n_bounds = 4;
164
168 using Bounds = std::array<Number, n_bounds>;
169
173 Limiter(const HyperbolicSystem &hyperbolic_system,
174 const Parameters &parameters,
176 &precomputed_values)
177 : hyperbolic_system(hyperbolic_system)
178 , parameters(parameters)
179 , precomputed_values(precomputed_values)
180 {
181 }
182
186 void reset(const unsigned int i,
187 const state_type &U_i,
188 const flux_contribution_type &flux_i);
189
194 void accumulate(const unsigned int *js,
195 const state_type &U_j,
196 const flux_contribution_type &flux_j,
197 const dealii::Tensor<1, dim, Number> &scaled_c_ij,
198 const Number beta_ij);
199
203 Bounds bounds(const Number hd_i) const;
204
205 //*}
208
223 std::tuple<Number, bool> limit(const Bounds &bounds,
224 const state_type &U,
225 const state_type &P,
226 const Number t_min = Number(0.),
227 const Number t_max = Number(1.));
228 //*}
233
240 static bool
241 is_in_invariant_domain(const HyperbolicSystem &hyperbolic_system,
242 const Bounds &bounds,
243 const state_type &U);
244
245 private:
247
249
250 const HyperbolicSystem &hyperbolic_system;
251 const Parameters &parameters;
252
254 &precomputed_values;
255
256 state_type U_i;
258
259 Bounds bounds_;
260
261 Number rho_relaxation_numerator;
262 Number rho_relaxation_denominator;
263 Number s_interp_max;
264
266 };
267
268
269 /*
270 * -------------------------------------------------------------------------
271 * Inline definitions
272 * -------------------------------------------------------------------------
273 */
274
275
276 template <int dim, typename Number>
277 DEAL_II_ALWAYS_INLINE inline void
278 Limiter<dim, Number>::reset(const unsigned int i,
279 const state_type &new_U_i,
280 const flux_contribution_type &new_flux_i)
281 {
282 U_i = new_U_i;
283 flux_i = new_flux_i;
284
285 /* Bounds: */
286
287 auto &[rho_min, rho_max, s_min, gamma_min] = bounds_;
288
289 rho_min = Number(std::numeric_limits<ScalarNumber>::max());
290 rho_max = Number(0.);
291 s_min = Number(std::numeric_limits<ScalarNumber>::max());
292
293 const auto &[p_i, gamma_min_i, s_i, eta_i] =
294 precomputed_values
295 .template get_tensor<Number, precomputed_state_type>(i);
296
297 gamma_min = gamma_min_i;
298
299 /* Relaxation: */
300
301 rho_relaxation_numerator = Number(0.);
302 rho_relaxation_denominator = Number(0.);
303 s_interp_max = Number(0.);
304 }
305
306
307 template <int dim, typename Number>
308 DEAL_II_ALWAYS_INLINE inline void Limiter<dim, Number>::accumulate(
309 const unsigned int *js,
310 const state_type &U_j,
311 const flux_contribution_type &flux_j,
312 const dealii::Tensor<1, dim, Number> &scaled_c_ij,
313 const Number beta_ij)
314 {
315 const auto view = hyperbolic_system.view<dim, Number>();
316
317 /* Bounds: */
318 auto &[rho_min, rho_max, s_min, gamma_min] = bounds_;
319
320 const auto rho_i = view.density(U_i);
321 const auto rho_j = view.density(U_j);
322
323 const auto U_ij_bar =
324 ScalarNumber(0.5) * (U_i + U_j) -
325 ScalarNumber(0.5) * contract(add(flux_j, -flux_i), scaled_c_ij);
326
327 const auto rho_ij_bar = view.density(U_ij_bar);
328
329 /* Density bounds: */
330
331 rho_min = std::min(rho_min, rho_ij_bar);
332 rho_max = std::max(rho_max, rho_ij_bar);
333
334 /* Density relaxation: */
335
336 rho_relaxation_numerator += beta_ij * (rho_i + rho_j);
337 rho_relaxation_denominator += std::abs(beta_ij);
338
339 /* Surrogate entropy bounds and relaxation: */
340
341 if (view.compute_strict_bounds()) {
342 /*
343 * Compute strict bounds precisely as outlined in @cite ryujin-2023-4
344 *
345 * This means, we compute
346 * - the surrogate entropy at dof j with the gamma_min of index i,
347 * - the currogate entropy of the bar state U_ij_bar
348 * - an interpolated surrogate entropy at (U_i + U_j) / 2 for
349 * bounds relaxation:
350 */
351
352 const auto s_j = view.surrogate_specific_entropy(U_j, gamma_min);
353
354 const auto s_ij_bar =
355 view.surrogate_specific_entropy(U_ij_bar, gamma_min);
356
357 const Number s_interp = view.surrogate_specific_entropy(
358 (U_i + U_j) * ScalarNumber(.5), gamma_min);
359
360 s_min = std::min(s_min, s_j);
361 s_min = std::min(s_min, s_ij_bar);
362 s_interp_max = std::max(s_interp_max, s_interp);
363
364 } else {
365 /*
366 * Compute a cheaper bound solely relying on the diagonal s_j
367 * (computed with gamma_min_j) and the surrogate entropy s_ij_bar
368 * of the bar state. We use the s_ij_bar for computing the bounds
369 * relaxation as well.
370 */
371 const auto [p_j, gamma_min_j, s_j, eta_j] =
372 precomputed_values
373 .template get_tensor<Number, precomputed_state_type>(js);
374
375 const auto s_ij_bar =
376 view.surrogate_specific_entropy(U_ij_bar, gamma_min);
377
378 s_min = std::min(s_min, s_j);
379 s_min = std::min(s_min, s_ij_bar);
380 s_interp_max = std::max(s_interp_max, s_ij_bar);
381 }
382 }
383
384
385 template <int dim, typename Number>
386 DEAL_II_ALWAYS_INLINE inline auto
387 Limiter<dim, Number>::bounds(const Number hd_i) const -> Bounds
388 {
389 const auto view = hyperbolic_system.view<dim, Number>();
390
391 auto relaxed_bounds = bounds_;
392 auto &[rho_min, rho_max, s_min, gamma_min] = relaxed_bounds;
393
394 /* Use r_i = factor * (m_i / |Omega|) ^ (1.5 / d): */
395
396 Number r_i = std::sqrt(hd_i); // in 3D: ^ 3/6
397 if constexpr (dim == 2) //
398 r_i = dealii::Utilities::fixed_power<3>(std::sqrt(r_i)); // in 2D: ^ 3/4
399 else if constexpr (dim == 1) //
400 r_i = dealii::Utilities::fixed_power<3>(r_i); // in 1D: ^ 3/2
401 r_i *= parameters.relaxation_factor();
402
403 constexpr ScalarNumber eps = std::numeric_limits<ScalarNumber>::epsilon();
404 const Number rho_relaxation =
405 std::abs(rho_relaxation_numerator) /
406 (std::abs(rho_relaxation_denominator) + Number(eps));
407
408 rho_min = std::max((Number(1.) - r_i) * rho_min,
409 rho_min - ScalarNumber(2.) * rho_relaxation);
410
411 rho_max = std::min((Number(1.) + r_i) * rho_max,
412 rho_max + ScalarNumber(2.) * rho_relaxation);
413
414 s_min = std::max((Number(1.) - r_i) * s_min,
415 Number(2.) * s_min - s_interp_max);
416
417 /*
418 * If we have a maximum compressibility constant, b, the maximum
419 * bound for rho changes. See @cite ryujin-2023-4 for how to define
420 * rho_max.
421 */
422
423 const auto numerator = (gamma_min + Number(1.)) * rho_max;
424 const auto interpolation_b = view.eos_interpolation_b();
425 const auto denominator =
426 gamma_min - Number(1.) + ScalarNumber(2.) * interpolation_b * rho_max;
427 const auto upper_bound = numerator / denominator;
428
429 rho_max = std::min(upper_bound, rho_max);
430
431 return relaxed_bounds;
432 }
433
434
435 template <int dim, typename Number>
436 DEAL_II_ALWAYS_INLINE inline bool
438 const HyperbolicSystem & /*hyperbolic_system*/,
439 const Bounds & /*bounds*/,
440 const state_type & /*U*/)
441 {
442 AssertThrow(false, dealii::ExcNotImplemented());
443 __builtin_trap();
444 return true;
445 }
446
447 } // namespace EulerAEOS
448} // namespace ryujin
dealii::Tensor< 1, problem_dimension, Number > state_type
std::array< Number, n_precomputed_values > precomputed_state_type
typename get_value_type< Number >::type ScalarNumber
static constexpr unsigned int n_precomputed_values
static constexpr unsigned int problem_dimension
LimiterParameters(const std::string &subsection="/Limiter")
Definition: limiter.h:23
ACCESSOR_READ_ONLY(newton_max_iterations)
typename View::state_type state_type
Definition: limiter.h:113
static constexpr unsigned int n_bounds
Definition: limiter.h:163
typename View::ScalarNumber ScalarNumber
Definition: limiter.h:134
static constexpr unsigned int n_precomputed_values
Definition: limiter.h:118
static constexpr unsigned int problem_dimension
Definition: limiter.h:108
typename View::precomputed_state_type precomputed_state_type
Definition: limiter.h:124
typename View::flux_contribution_type flux_contribution_type
Definition: limiter.h:129
void reset(const unsigned int i, const state_type &U_i, const flux_contribution_type &flux_i)
Definition: limiter.h:278
void accumulate(const unsigned int *js, const state_type &U_j, const flux_contribution_type &flux_j, const dealii::Tensor< 1, dim, Number > &scaled_c_ij, const Number beta_ij)
Definition: limiter.h:308
std::tuple< Number, bool > limit(const Bounds &bounds, const state_type &U, const state_type &P, const Number t_min=Number(0.), const Number t_max=Number(1.))
Limiter(const HyperbolicSystem &hyperbolic_system, const Parameters &parameters, const MultiComponentVector< ScalarNumber, n_precomputed_values > &precomputed_values)
Definition: limiter.h:173
std::array< Number, n_bounds > Bounds
Definition: limiter.h:168
Bounds bounds(const Number hd_i) const
Definition: limiter.h:387
LimiterParameters< ScalarNumber > Parameters
Definition: limiter.h:139
static bool is_in_invariant_domain(const HyperbolicSystem &hyperbolic_system, const Bounds &bounds, const state_type &U)
Definition: limiter.h:437
DEAL_II_ALWAYS_INLINE FT add(const FT &flux_left_ij, const FT &flux_right_ij)
DEAL_II_ALWAYS_INLINE dealii::Tensor< 1, problem_dim, T > contract(const FT &flux_ij, const TT &c_ij)