/home/runner/work/DiFfRG_current/DiFfRG_current/DiFfRG/include/DiFfRG/discretization/FV/wave_speed/max_eigenvalue_wave_speed.hh Source File#

DiFfRG: /home/runner/work/DiFfRG_current/DiFfRG_current/DiFfRG/include/DiFfRG/discretization/FV/wave_speed/max_eigenvalue_wave_speed.hh Source File
DiFfRG
Discretization Framework for functional Renormalization Group flows
max_eigenvalue_wave_speed.hh
Go to the documentation of this file.
1#pragma once
2
3#include <Eigen/Dense>
4#include <array>
5#include <cstddef>
6#include <utility>
7
9
10namespace DiFfRG
11{
12 namespace FV
13 {
14 namespace KurganovTadmor
15 {
17
26 template <typename NumberType, int dim, size_t n_components>
27 static std::array<NumberType, dim>
29 const std::array<internal::JacobianMatrix<NumberType, n_components>, dim> &J_minus)
30 {
31 const auto [spectral_radius_plus, spectral_radius_minus] =
33
34 std::array<NumberType, dim> a{};
35 for (size_t d = 0; d < dim; ++d)
36 a[d] = std::max(spectral_radius_plus[d], spectral_radius_minus[d]);
37 return a;
38 }
39
40 template <typename NumberType, int dim, size_t n_components>
41 static std::array<WaveSpeedBranch, dim>
43 const std::array<internal::JacobianMatrix<NumberType, n_components>, dim> &J_minus)
44 {
45 const auto [spectral_radius_plus, spectral_radius_minus] =
47
48 std::array<WaveSpeedBranch, dim> branches{};
49 for (size_t d = 0; d < dim; ++d) {
50 if (spectral_radius_plus[d] > spectral_radius_minus[d])
51 branches[d] = WaveSpeedBranch::plus;
52 else if (spectral_radius_minus[d] > spectral_radius_plus[d])
53 branches[d] = WaveSpeedBranch::minus;
54 else
55 branches[d] = WaveSpeedBranch::average;
56 }
57 return branches;
58 }
59
60 private:
61 template <typename NumberType, int dim, size_t n_components>
62 static std::pair<std::array<NumberType, dim>, std::array<NumberType, dim>>
64 const std::array<internal::JacobianMatrix<NumberType, n_components>, dim> &J_minus)
65 {
66 std::array<NumberType, dim> spectral_radius_plus{}, spectral_radius_minus{};
67 for (size_t d = 0; d < dim; ++d) {
68 NumberType max_eig_plus = 0.0;
69 NumberType max_eig_minus = 0.0;
70
71 if constexpr (n_components == 1) {
72 max_eig_plus = std::abs(J_plus[d][0][0]);
73 max_eig_minus = std::abs(J_minus[d][0][0]);
74 } else {
75 Eigen::Matrix<NumberType, n_components, n_components> J_plus_eigen, J_minus_eigen;
76 for (size_t i = 0; i < n_components; ++i)
77 for (size_t j = 0; j < n_components; ++j) {
78 J_plus_eigen(i, j) = J_plus[d][i][j];
79 J_minus_eigen(i, j) = J_minus[d][i][j];
80 }
81 Eigen::EigenSolver<Eigen::Matrix<NumberType, n_components, n_components>> es_plus(J_plus_eigen);
82 Eigen::EigenSolver<Eigen::Matrix<NumberType, n_components, n_components>> es_minus(J_minus_eigen);
83 max_eig_plus = es_plus.eigenvalues().cwiseAbs().maxCoeff();
84 max_eig_minus = es_minus.eigenvalues().cwiseAbs().maxCoeff();
85 }
86
87 spectral_radius_plus[d] = max_eig_plus;
88 spectral_radius_minus[d] = max_eig_minus;
89 }
90 return {spectral_radius_plus, spectral_radius_minus};
91 }
92
93 public:
110 template <typename NumberType, int dim, size_t n_components>
111 static std::pair<std::array<std::array<NumberType, n_components>, dim>,
112 std::array<std::array<NumberType, n_components>, dim>>
114 const std::array<internal::JacobianMatrix<NumberType, n_components>, dim> &J_minus,
117 {
118 std::array<std::array<NumberType, n_components>, dim> da_plus{}, da_minus{};
119 for (size_t d = 0; d < dim; ++d) {
120 if constexpr (n_components == 1) {
121 const NumberType sign_J_plus = (J_plus[d][0][0] >= NumberType(0)) ? NumberType(1) : NumberType(-1);
122 const NumberType sign_J_minus = (J_minus[d][0][0] >= NumberType(0)) ? NumberType(1) : NumberType(-1);
123 for (size_t c = 0; c < n_components; ++c) {
124 da_plus[d][c] = sign_J_plus * H_plus[d][0][0][c];
125 da_minus[d][c] = sign_J_minus * H_minus[d][0][0][c];
126 }
127 } else {
128 Eigen::Matrix<NumberType, n_components, n_components> Jp, Jm;
129 for (size_t i = 0; i < n_components; ++i)
130 for (size_t j = 0; j < n_components; ++j) {
131 Jp(i, j) = J_plus[d][i][j];
132 Jm(i, j) = J_minus[d][i][j];
133 }
134
135 // Helper lambda: fill da[d] from Jacobian eigen-decomposition and Hessian
136 auto fill_da = [&](const Eigen::Matrix<NumberType, n_components, n_components> &J, const auto &H_side,
137 std::array<std::array<NumberType, n_components>, dim> &da) {
138 using CplxVec = Eigen::Matrix<std::complex<NumberType>, n_components, 1>;
139 using CplxMat = Eigen::Matrix<std::complex<NumberType>, n_components, n_components>;
140
141 Eigen::EigenSolver<Eigen::Matrix<NumberType, n_components, n_components>> es(J);
142 // Find index of eigenvalue with largest absolute value
143 Eigen::Index idx;
144 es.eigenvalues().cwiseAbs().maxCoeff(&idx);
145
146 const NumberType sign_lam =
147 (es.eigenvalues()(idx).real() >= NumberType(0)) ? NumberType(1) : NumberType(-1);
148
149 // Materialize both eigenvectors to avoid dangling lazy-expression issues.
150 const CplxVec right_evec = es.eigenvectors().col(idx);
151 const CplxMat V_inv = es.eigenvectors().inverse();
152 const CplxVec left_evec = V_inv.row(idx).transpose();
153
154 // Bilinear form w^T * v (no conjugation) — this equals 1 by construction of V^{-1}.
155 const NumberType wdotv = (left_evec.transpose() * right_evec)(0, 0).real();
156
157 for (size_t c = 0; c < n_components; ++c) {
158 NumberType contraction = NumberType(0);
159 for (size_t i = 0; i < n_components; ++i)
160 for (size_t j = 0; j < n_components; ++j)
161 contraction += left_evec(i).real() * right_evec(j).real() * H_side[d][i][j][c];
162 da[d][c] = sign_lam * contraction / wdotv;
163 }
164 };
165
166 fill_da(Jp, H_plus, da_plus);
167 fill_da(Jm, H_minus, da_minus);
168 }
169 }
170 return {da_plus, da_minus};
171 }
172
173 template <typename NumberType, int dim, size_t n_components>
174 static std::pair<std::array<std::array<NumberType, n_components>, dim>,
175 std::array<std::array<NumberType, n_components>, dim>>
177 const std::array<internal::JacobianMatrix<NumberType, n_components>, dim> &J_plus,
178 const std::array<internal::JacobianMatrix<NumberType, n_components>, dim> &J_minus,
181 {
182 const auto [raw_da_plus, raw_da_minus] =
183 compute_speed_derivatives<NumberType, dim, n_components>(J_plus, J_minus, H_plus, H_minus);
184 const auto branches = select_speed_branches<NumberType, dim, n_components>(J_plus, J_minus);
185
186 std::array<std::array<NumberType, n_components>, dim> da_plus{}, da_minus{};
187 for (size_t d = 0; d < dim; ++d) {
188 if (branches[d] == WaveSpeedBranch::plus)
189 da_plus[d] = raw_da_plus[d];
190 else if (branches[d] == WaveSpeedBranch::minus)
191 da_minus[d] = raw_da_minus[d];
192 else {
193 for (size_t c = 0; c < n_components; ++c) {
194 da_plus[d][c] = NumberType(0.5) * raw_da_plus[d][c];
195 da_minus[d][c] = NumberType(0.5) * raw_da_minus[d][c];
196 }
197 }
198 }
199
200 return {da_plus, da_minus};
201 }
202 };
203
204 } // namespace KurganovTadmor
205 } // namespace FV
206} // namespace DiFfRG
std::array< std::array< std::array< std::array< NumberType, n_components >, n_components >, n_components >, dim > HessianTensor
Definition flux_jacobian_hessian.hh:24
std::array< std::array< NumberType, n_components >, n_components > JacobianMatrix
Definition flux_jacobian_hessian.hh:21
WaveSpeedBranch
Definition max_eigenvalue_wave_speed.hh:16
Definition complex_math.hh:10
KOKKOS_FORCEINLINE_FUNCTION auto real(const autodiff::Real< N, T > &a)
Definition complex_math.hh:96
Default wave-speed strategy.
Definition max_eigenvalue_wave_speed.hh:25
static std::pair< std::array< NumberType, dim >, std::array< NumberType, dim > > compute_spectral_radii(const std::array< internal::JacobianMatrix< NumberType, n_components >, dim > &J_plus, const std::array< internal::JacobianMatrix< NumberType, n_components >, dim > &J_minus)
Definition max_eigenvalue_wave_speed.hh:63
static std::pair< std::array< std::array< NumberType, n_components >, dim >, std::array< std::array< NumberType, n_components >, dim > > compute_selected_speed_derivatives(const std::array< internal::JacobianMatrix< NumberType, n_components >, dim > &J_plus, const std::array< internal::JacobianMatrix< NumberType, n_components >, dim > &J_minus, const internal::HessianTensor< NumberType, dim, n_components > &H_plus, const internal::HessianTensor< NumberType, dim, n_components > &H_minus)
Definition max_eigenvalue_wave_speed.hh:176
static std::array< NumberType, dim > compute_speeds(const std::array< internal::JacobianMatrix< NumberType, n_components >, dim > &J_plus, const std::array< internal::JacobianMatrix< NumberType, n_components >, dim > &J_minus)
Definition max_eigenvalue_wave_speed.hh:28
static std::array< WaveSpeedBranch, dim > select_speed_branches(const std::array< internal::JacobianMatrix< NumberType, n_components >, dim > &J_plus, const std::array< internal::JacobianMatrix< NumberType, n_components >, dim > &J_minus)
Definition max_eigenvalue_wave_speed.hh:42
static std::pair< std::array< std::array< NumberType, n_components >, dim >, std::array< std::array< NumberType, n_components >, dim > > compute_speed_derivatives(const std::array< internal::JacobianMatrix< NumberType, n_components >, dim > &J_plus, const std::array< internal::JacobianMatrix< NumberType, n_components >, dim > &J_minus, const internal::HessianTensor< NumberType, dim, n_components > &H_plus, const internal::HessianTensor< NumberType, dim, n_components > &H_minus)
Compute da[d]/du_c analytically from J and H: a[d] = spectral_radius(J[d]) da[d]/du_c = d(spectral_ra...
Definition max_eigenvalue_wave_speed.hh:113