OGS
FluxCorrectedTransport.h
Go to the documentation of this file.
1
10#pragma once
11
12#include <Eigen/Core>
13#include <Eigen/Sparse>
14
18
19namespace NumLib
20{
21namespace detail
22{
23
24template <typename MatrixVectorType>
25std::unique_ptr<MatrixVectorType> newZeroedInstance(
26 MathLib::MatrixSpecifications const& matrix_specification)
27{
29 matrix_specification);
30 result->setZero();
31 return result;
32}
33
35 [[maybe_unused]] const double t, [[maybe_unused]] const double dt,
36 [[maybe_unused]] std::vector<GlobalVector*> const& x,
37 [[maybe_unused]] std::vector<GlobalVector*> const& x_prev,
38 [[maybe_unused]] int const process_id,
39 [[maybe_unused]] const MathLib::MatrixSpecifications& matrix_specification,
40 [[maybe_unused]] GlobalMatrix& M, [[maybe_unused]] GlobalMatrix& K,
41 [[maybe_unused]] GlobalVector& b)
42{
43#ifndef USE_PETSC
44 auto D = newZeroedInstance<GlobalMatrix>(matrix_specification);
45 auto F = newZeroedInstance<GlobalMatrix>(matrix_specification);
46
47 // compute artificial diffusion operator D
48 using RawMatrixType = Eigen::SparseMatrix<double, Eigen::RowMajor>;
49 auto& K_raw = K.getRawMatrix();
50 K_raw *= -1;
51 for (int k = 0; k < K_raw.outerSize(); ++k)
52 {
53 for (RawMatrixType::InnerIterator it(K_raw, k); it; ++it)
54 {
55 if (it.row() != it.col())
56 {
57 double const kij = it.value();
58 double const kji = K.get(it.col(), it.row());
59 double const dij = std::max({-kij, 0., -kji});
60 D->setValue(it.row(), it.col(), dij);
61 }
62 }
63 }
64 auto& D_raw = D->getRawMatrix();
65 D_raw -= (D_raw * Eigen::VectorXd::Ones(D_raw.cols())).eval().asDiagonal();
66
67 // compute F
68 for (int k = 0; k < D_raw.outerSize(); ++k)
69 {
70 for (RawMatrixType::InnerIterator it(D_raw, k); it; ++it)
71 {
72 double const dij = it.value();
73 double const xj = x[process_id]->get(it.col());
74 double const xi = x[process_id]->get(it.row());
75 double const fij = -dij * (xj - xi);
76 F->setValue(it.row(), it.col(), fij);
77 }
78 }
79
80 auto& M_raw = M.getRawMatrix();
81 for (int k = 0; k < M_raw.outerSize(); ++k)
82 {
83 for (RawMatrixType::InnerIterator it(M_raw, k); it; ++it)
84 {
85 double const mij = it.value();
86 double const xdotj = (x[process_id]->get(it.col()) -
87 x_prev[process_id]->get(it.col())) /
88 dt;
89 double const xdoti = (x[process_id]->get(it.row()) -
90 x_prev[process_id]->get(it.row())) /
91 dt;
92 double const fij = -mij * (xdotj - xdoti);
93 F->add(it.row(), it.col(), fij);
94 }
95 }
96
97 auto P_plus = newZeroedInstance<GlobalVector>(matrix_specification);
98 auto P_minus = newZeroedInstance<GlobalVector>(matrix_specification);
99 auto Q_plus = newZeroedInstance<GlobalVector>(matrix_specification);
100 auto Q_minus = newZeroedInstance<GlobalVector>(matrix_specification);
101 auto R_plus = newZeroedInstance<GlobalVector>(matrix_specification);
102 auto R_minus = newZeroedInstance<GlobalVector>(matrix_specification);
103
104 auto& F_raw = F->getRawMatrix();
105 for (int k = 0; k < F_raw.outerSize(); ++k)
106 {
107 for (RawMatrixType::InnerIterator it(F_raw, k); it; ++it)
108 {
109 if (it.row() != it.col())
110 {
111 double const fij = it.value();
112 P_plus->add(it.row(), std::max(0., fij));
113 P_minus->add(it.row(), std::min(0., fij));
114
115 double const x_prev_i = x_prev[process_id]->get(it.row());
116 double const x_prev_j = x_prev[process_id]->get(it.col());
117
118 double const Q_plus_i = Q_plus->get(it.row());
119 double Q_plus_i_tmp =
120 std::max({Q_plus_i, 0., x_prev_j - x_prev_i});
121 Q_plus->set(it.row(), Q_plus_i_tmp);
122
123 double const Q_minus_i = Q_minus->get(it.row());
124 double Q_minus_i_tmp =
125 std::min({Q_minus_i, 0., x_prev_j - x_prev_i});
126 Q_minus->set(it.row(), Q_minus_i_tmp);
127 }
128 }
129 }
130
131 Eigen::VectorXd const M_L =
132 (M_raw * Eigen::VectorXd::Ones(M_raw.cols())).eval();
133 for (auto k = R_plus->getRangeBegin(); k < R_plus->getRangeEnd(); ++k)
134 {
135 double const mi = M_L(k);
136 double const Q_plus_i = Q_plus->get(k);
137 double const P_plus_i = P_plus->get(k);
138
139 double const tmp =
140 P_plus_i == 0. ? 0.0 : std::min(1.0, mi * Q_plus_i / dt / P_plus_i);
141
142 R_plus->set(k, tmp);
143 }
144
145 for (auto k = R_minus->getRangeBegin(); k < R_minus->getRangeEnd(); ++k)
146 {
147 double const mi = M_L(k);
148 double const Q_minus_i = Q_minus->get(k);
149 double const P_minus_i = P_minus->get(k);
150
151 double const tmp = P_minus_i == 0.
152 ? 0.0
153 : std::min(1.0, mi * Q_minus_i / dt / P_minus_i);
154 R_minus->set(k, tmp);
155 }
156
157 auto alpha = newZeroedInstance<GlobalMatrix>(matrix_specification);
158 for (int k = 0; k < F_raw.outerSize(); ++k)
159 {
160 for (RawMatrixType::InnerIterator it(F_raw, k); it; ++it)
161 {
162 double const fij = it.value();
163 if (fij > 0.)
164 {
165 double const R_plus_i = R_plus->get(it.row());
166 double const R_minus_j = R_minus->get(it.col());
167 double const alpha_ij = std::min(R_plus_i, R_minus_j);
168
169 alpha->setValue(it.row(), it.col(), alpha_ij);
170 }
171 else
172 {
173 double const R_minus_i = R_minus->get(it.row());
174 double const R_plus_j = R_plus->get(it.col());
175 double const alpha_ij = std::min(R_minus_i, R_plus_j);
176
177 alpha->setValue(it.row(), it.col(), alpha_ij);
178 }
179 }
180 }
181
182 // compute limited antidiffusive fluxes
183 for (int k = 0; k < F_raw.outerSize(); ++k)
184 {
185 for (RawMatrixType::InnerIterator it(F_raw, k); it; ++it)
186 {
187 if (it.row() != it.col())
188 {
189 double const fij = it.value();
190 double const alpha_ij = alpha->get(it.row(), it.col());
191
192 b.add(it.row(), alpha_ij * fij);
193 }
194 }
195 }
196
197 // compute low-order operator
198 K_raw += D_raw;
199 K_raw *= -1;
200
201 // overwrite with the lumped mass matrix
202 M.setZero();
203 for (int k = 0; k < M.getNumberOfRows(); ++k)
204 {
205 M.setValue(k, k, M_L(k));
206 }
207#endif // end of ifndef USE_PETSC
208}
209} // namespace detail
210
212 NumericalStabilization const& stabilizer, const double t, const double dt,
213 std::vector<GlobalVector*> const& x,
214 std::vector<GlobalVector*> const& x_prev, int const process_id,
215 const MathLib::MatrixSpecifications& matrix_specification, GlobalMatrix& M,
217{
218 // if needed, calling the Flux-Corrected-Transport function
219 return std::visit(
220 [&](auto&& stabilizer)
221 {
222 using Stabilizer = std::decay_t<decltype(stabilizer)>;
223 if constexpr (std::is_same_v<Stabilizer,
225 {
227 t, dt, x, x_prev, process_id, matrix_specification, M, K,
228 b);
229 }
230 },
231 stabilizer);
232}
233} // namespace NumLib
Global vector based on Eigen vector.
Definition EigenVector.h:25
void calculateFluxCorrectedTransport(const double t, const double dt, std::vector< GlobalVector * > const &x, std::vector< GlobalVector * > const &x_prev, int const process_id, const MathLib::MatrixSpecifications &matrix_specification, GlobalMatrix &M, GlobalMatrix &K, GlobalVector &b)
std::unique_ptr< MatrixVectorType > newZeroedInstance(MathLib::MatrixSpecifications const &matrix_specification)
void computeFluxCorrectedTransport(NumericalStabilization const &stabilizer, const double t, const double dt, std::vector< GlobalVector * > const &x, std::vector< GlobalVector * > const &x_prev, int const process_id, const MathLib::MatrixSpecifications &matrix_specification, GlobalMatrix &M, GlobalMatrix &K, GlobalVector &b)
std::variant< NoStabilization, IsotropicDiffusionStabilization, FullUpwind, FluxCorrectedTransport > NumericalStabilization