HybridADRSolver
Loading...
Searching...
No Matches
adr_operator.h
Go to the documentation of this file.
1#ifndef HYBRIDADRSOLVER_ADR_OPERATOR_H
2#define HYBRIDADRSOLVER_ADR_OPERATOR_H
3
5
6#include <deal.II/base/vectorization.h>
7#include <deal.II/lac/la_parallel_vector.h>
8#include <deal.II/matrix_free/fe_evaluation.h>
9#include <deal.II/matrix_free/matrix_free.h>
10#include <deal.II/matrix_free/operators.h>
11#include <deal.II/multigrid/mg_constrained_dofs.h>
12
13namespace HybridADRSolver {
14using namespace dealii;
15
34template <int dim, int fe_degree, typename Number = double>
35class ADROperator : public MatrixFreeOperators::Base<
36 dim, LinearAlgebra::distributed::Vector<Number>> {
37public:
38 using VectorType = LinearAlgebra::distributed::Vector<Number>;
39 using value_type = Number;
40 using size_type = types::global_dof_index;
41 using Base =
42 MatrixFreeOperators::Base<dim,
43 LinearAlgebra::distributed::Vector<Number>>;
44
48 ADROperator() : problem_ptr(nullptr), is_mg_level(false), mg_level(-1) {}
49
57 void initialize(std::shared_ptr<const MatrixFree<dim, Number>> data_in,
58 const ProblemInterface<dim>& problem) {
59 Base::initialize(data_in);
60 this->problem_ptr = &problem;
61 this->is_mg_level = false;
62 this->mg_level = -1;
63 precompute_coefficient_data();
64 }
65
74 void initialize(std::shared_ptr<const MatrixFree<dim, Number>> data_in,
75 const MGConstrainedDoFs& mg_constrained_dofs,
76 unsigned int level, const ProblemInterface<dim>& problem) {
77 Base::initialize(data_in, mg_constrained_dofs, level);
78 this->problem_ptr = &problem;
79 this->is_mg_level = true;
80 this->mg_level = level;
81 precompute_coefficient_data();
82 }
83
87 void clear() override {
88 Base::clear();
89 problem_ptr = nullptr;
90 diffusion_coefficients.clear();
91 advection_coefficients.clear();
92 reaction_coefficients.clear();
93 is_mg_level = false;
94 mg_level = -1;
95 }
96
102 void compute_diagonal() override {
103 this->inverse_diagonal_entries.reset(new DiagonalMatrix<VectorType>());
104 VectorType& inverse_diagonal =
105 this->inverse_diagonal_entries->get_vector();
106 this->data->initialize_dof_vector(inverse_diagonal);
107
108 MatrixFreeTools::compute_diagonal(*this->data, inverse_diagonal,
109 &ADROperator::local_compute_diagonal,
110 this);
111
112 this->set_constrained_entries_to_one(inverse_diagonal);
113
114 for (unsigned int i = 0; i < inverse_diagonal.locally_owned_size();
115 ++i) {
116 if (std::abs(inverse_diagonal.local_element(i)) > 1e-14)
117 inverse_diagonal.local_element(i) =
118 1.0 / inverse_diagonal.local_element(i);
119 else
120 inverse_diagonal.local_element(i) = 1.0;
121 }
122 }
123
127 [[nodiscard]] bool is_multigrid_level() const { return is_mg_level; }
128
132 [[nodiscard]] int get_mg_level() const { return mg_level; }
133
134private:
140 void apply_add(VectorType& dst, const VectorType& src) const override {
141 this->data->cell_loop(&ADROperator::local_apply, this, dst, src);
142 }
143
151 void precompute_coefficient_data() {
152 Assert(problem_ptr != nullptr, ExcNotInitialized());
153
154 const unsigned int n_cells = this->data->n_cell_batches();
155 const unsigned int n_q_points = Utilities::pow(fe_degree + 1, dim);
156
157 diffusion_coefficients.resize(n_cells);
158 advection_coefficients.resize(n_cells);
159 reaction_coefficients.resize(n_cells);
160
161 // Use FEEvaluation to get quadrature points
162 FEEvaluation<dim, fe_degree, fe_degree + 1, 1, Number> phi(*this->data);
163
164 for (unsigned int cell = 0; cell < n_cells; ++cell) {
165 phi.reinit(cell);
166
167 diffusion_coefficients[cell].resize(n_q_points);
168 advection_coefficients[cell].resize(n_q_points);
169 reaction_coefficients[cell].resize(n_q_points);
170
171 for (unsigned int q = 0; q < n_q_points; ++q) {
172 // Get the vectorized quadrature point
173 Point<dim, VectorizedArray<Number>> q_point =
174 phi.quadrature_point(q);
175
176 // Evaluate coefficients for each lane in the vector
177 VectorizedArray<Number> mu;
178 Tensor<1, dim, VectorizedArray<Number>> beta;
179 VectorizedArray<Number> gamma;
180
181 for (unsigned int v = 0; v < VectorizedArray<Number>::size();
182 ++v) {
183 Point<dim> p;
184 for (unsigned int d = 0; d < dim; ++d)
185 p[d] = q_point[d][v];
186
187 mu[v] = problem_ptr->diffusion_coefficient(p);
188 gamma[v] = problem_ptr->reaction_coefficient(p);
189
190 Tensor<1, dim> beta_scalar =
191 problem_ptr->advection_field(p);
192 for (unsigned int d = 0; d < dim; ++d)
193 beta[d][v] = beta_scalar[d];
194 }
195
196 diffusion_coefficients[cell][q] = mu;
197 advection_coefficients[cell][q] = beta;
198 reaction_coefficients[cell][q] = gamma;
199 }
200 }
201 }
202
213 void
214 local_apply(const MatrixFree<dim, Number>& /*mf_data*/, VectorType& dst,
215 const VectorType& src,
216 const std::pair<unsigned int, unsigned int>& cell_range) const {
217 FEEvaluation<dim, fe_degree, fe_degree + 1, 1, Number> phi(*this->data);
218
219 for (unsigned int cell = cell_range.first; cell < cell_range.second;
220 ++cell) {
221 phi.reinit(cell);
222 phi.gather_evaluate(src, EvaluationFlags::values |
223 EvaluationFlags::gradients);
224
225 for (unsigned int q = 0; q < phi.n_q_points; ++q) {
226 // use precomputed coefficients
227 const VectorizedArray<Number>& mu_val =
228 diffusion_coefficients[cell][q];
229 const Tensor<1, dim, VectorizedArray<Number>>& beta_val =
230 advection_coefficients[cell][q];
231 const VectorizedArray<Number>& gamma_val =
232 reaction_coefficients[cell][q];
233
234 const auto u_val = phi.get_value(q);
235 const auto grad_u = phi.get_gradient(q);
236
237 // Diffusion: mu * grad(u)
238 const auto flux = mu_val * grad_u;
239
240 // Advection + Reaction
241 // weak form: (beta . grad_u, v) + (gamma * u, v)
242 const auto val = gamma_val * u_val + beta_val * grad_u;
243
244 phi.submit_gradient(flux, q);
245 phi.submit_value(val, q);
246 }
247
248 phi.integrate_scatter(
249 EvaluationFlags::values | EvaluationFlags::gradients, dst);
250 }
251 }
252
259 void local_compute_diagonal(
260 FEEvaluation<dim, fe_degree, fe_degree + 1, 1, Number>& phi) const {
261 const unsigned int cell = phi.get_current_cell_index();
262
263 phi.evaluate(EvaluationFlags::values | EvaluationFlags::gradients);
264
265 for (unsigned int q = 0; q < phi.n_q_points; ++q) {
266 const VectorizedArray<Number> u_val = phi.get_value(q);
267 const Tensor<1, dim, VectorizedArray<Number>> grad_u =
268 phi.get_gradient(q);
269
270 // Use precomputed coefficients
271 const Tensor<1, dim, VectorizedArray<Number>> flux =
272 diffusion_coefficients[cell][q] * grad_u;
273
274 const VectorizedArray<Number> advection_val =
275 advection_coefficients[cell][q] * grad_u;
276
277 const VectorizedArray<Number> val =
278 reaction_coefficients[cell][q] * u_val + advection_val;
279
280 phi.submit_gradient(flux, q);
281 phi.submit_value(val, q);
282 }
283
284 phi.integrate(EvaluationFlags::values | EvaluationFlags::gradients);
285 }
286
287 // Data members
288 const ProblemInterface<dim>* problem_ptr;
289 bool is_mg_level;
290 unsigned int mg_level;
291
292 // Precomputed coefficients at quadrature points
293 // These are computed ONCE during initialization and reused for all
294 std::vector<std::vector<VectorizedArray<Number>>> diffusion_coefficients;
295 std::vector<std::vector<Tensor<1, dim, VectorizedArray<Number>>>>
296 advection_coefficients;
297 std::vector<std::vector<VectorizedArray<Number>>> reaction_coefficients;
298};
299
305template <int dim, int fe_degree, typename Number = double>
307public:
308 using VectorType = LinearAlgebra::distributed::Vector<Number>;
309
314 op.compute_diagonal();
315 inverse_diagonal = op.get_matrix_diagonal_inverse()->get_vector();
316 }
317
321 void vmult(VectorType& dst, const VectorType& src) const {
322 dst = src;
323 dst.scale(inverse_diagonal);
324 }
325
326private:
327 VectorType inverse_diagonal;
328};
329
330} // namespace HybridADRSolver
331
332#endif // HYBRIDADRSOLVER_ADR_OPERATOR_H
Matrix-free operator for the ADR problem with multigrid support.
Definition adr_operator.h:36
MatrixFreeOperators::Base< dim, LinearAlgebra::distributed::Vector< Number > > Base
Definition adr_operator.h:41
void compute_diagonal() override
Computes the diagonal of the operator (for preconditioning).
Definition adr_operator.h:102
bool is_multigrid_level() const
Check if this is a multigrid level operator.
Definition adr_operator.h:127
Number value_type
Definition adr_operator.h:39
types::global_dof_index size_type
Definition adr_operator.h:40
void initialize(std::shared_ptr< const MatrixFree< dim, Number > > data_in, const ProblemInterface< dim > &problem)
Initialize the operator with MatrixFree data and problem definition.
Definition adr_operator.h:57
void initialize(std::shared_ptr< const MatrixFree< dim, Number > > data_in, const MGConstrainedDoFs &mg_constrained_dofs, unsigned int level, const ProblemInterface< dim > &problem)
Initialize for a multigrid level.
Definition adr_operator.h:74
void clear() override
Clear all data.
Definition adr_operator.h:87
int get_mg_level() const
Get the multigrid level (-1 if not a level operator).
Definition adr_operator.h:132
ADROperator()
Default constructor.
Definition adr_operator.h:48
LinearAlgebra::distributed::Vector< Number > VectorType
Definition adr_operator.h:38
Jacobi preconditioner for the matrix-free operator.
Definition adr_operator.h:306
LinearAlgebra::distributed::Vector< Number > VectorType
Definition adr_operator.h:308
void initialize(const ADROperator< dim, fe_degree, Number > &op)
Initialize with the operator.
Definition adr_operator.h:313
void vmult(VectorType &dst, const VectorType &src) const
Apply the preconditioner: dst = M^{-1} * src.
Definition adr_operator.h:321
Abstract interface for defining a physical problem.
Definition problem_definition.h:39
Definition problem_definition.h:25
@ MatrixFree
Definition types.h:34
Defines the problem interface and a concrete Advection-Diffusion-Reaction (ADR) problem.