95class InverseMassOperator
98 typedef dealii::LinearAlgebra::distributed::Vector<Number> VectorType;
100 typedef InverseMassOperator<dim, n_components, Number> This;
102 typedef CellIntegrator<dim, n_components, Number> Integrator;
105 typedef dealii::MatrixFreeOperators::CellwiseInverseMassMatrix<dim, -1, n_components, Number>
106 InverseMassAsMatrixFreeOperator;
108 typedef std::pair<unsigned int, unsigned int> Range;
111 InverseMassOperator() : matrix_free(
nullptr), dof_index(0), quad_index(0)
116 get_n_iter_global_last()
const
118 return this->n_iter_global_last;
122 initialize(dealii::MatrixFree<dim, Number>
const & matrix_free_in,
124 dealii::AffineConstraints<Number>
const * constraints =
nullptr)
126 this->matrix_free = &matrix_free_in;
127 dof_index = inverse_mass_operator_data.dof_index;
128 quad_index = inverse_mass_operator_data.quad_index;
130 data = inverse_mass_operator_data.parameters;
132 coefficient_is_variable = inverse_mass_operator_data.coefficient_is_variable;
133 consider_inverse_coefficient = inverse_mass_operator_data.consider_inverse_coefficient;
134 variable_coefficients = inverse_mass_operator_data.variable_coefficients;
137 AssertThrow(not coefficient_is_variable or variable_coefficients !=
nullptr,
138 dealii::ExcMessage(
"Pointer to variable coefficients not set properly."));
140 dealii::FiniteElement<dim>
const & fe = matrix_free->get_dof_handler(dof_index).get_fe();
145 if(data.implementation_type == InverseMassType::MatrixfreeOperator)
148 fe.base_element(0).dofs_per_cell == dealii::Utilities::pow(fe.degree + 1, dim),
150 "The matrix-free cell-wise inverse mass operator is currently only available for isotropic tensor-product elements."));
153 this->matrix_free->get_shape_info(0, quad_index).data[0].n_q_points_1d == fe.degree + 1,
155 "The matrix-free cell-wise inverse mass operator is currently only available if n_q_points_1d = n_nodes_1d."));
158 fe.conforms(dealii::FiniteElementData<dim>::L2),
160 "The matrix-free cell-wise inverse mass operator is only available for L2-conforming elements."));
167 mass_operator_data.dof_index = dof_index;
168 mass_operator_data.quad_index = quad_index;
169 mass_operator_data.coefficient_is_variable = coefficient_is_variable;
170 mass_operator_data.variable_coefficients = variable_coefficients;
171 mass_operator_data.consider_inverse_coefficient = consider_inverse_coefficient;
173 if(data.implementation_type == InverseMassType::ElementwiseKrylovSolver)
175 mass_operator_data.implement_block_diagonal_preconditioner_matrix_free =
true;
176 mass_operator_data.solver_block_diagonal = Elementwise::Solver::CG;
177 if(inverse_mass_operator_data.parameters.preconditioner == PreconditionerMass::None)
179 mass_operator_data.preconditioner_block_diagonal = Elementwise::Preconditioner::None;
181 else if(inverse_mass_operator_data.parameters.preconditioner ==
182 PreconditionerMass::PointJacobi)
184 mass_operator_data.preconditioner_block_diagonal =
185 Elementwise::Preconditioner::PointJacobi;
187 mass_operator_data.solver_data_block_diagonal =
188 inverse_mass_operator_data.parameters.solver_data;
192 if(constraints ==
nullptr)
194 dealii::AffineConstraints<Number> dummy_constraints;
195 dummy_constraints.close();
196 mass_operator.initialize(*matrix_free, dummy_constraints, mass_operator_data);
200 mass_operator.initialize(*matrix_free, *constraints, mass_operator_data);
203 if(data.implementation_type == InverseMassType::ElementwiseKrylovSolver or
204 data.implementation_type == InverseMassType::BlockMatrices)
209 fe.conforms(dealii::FiniteElementData<dim>::L2),
211 "The cell-wise inverse mass operator is only available for L2-conforming elements."));
213 block_jacobi_preconditioner =
214 std::make_shared<BlockJacobiPreconditioner<MassOperator<dim, n_components, Number>>>(
215 mass_operator,
true );
217 else if(data.implementation_type == InverseMassType::GlobalKrylovSolver)
220 solver_data.max_iter = inverse_mass_operator_data.parameters.solver_data.max_iter;
221 solver_data.solver_tolerance_abs =
222 inverse_mass_operator_data.parameters.solver_data.abs_tol;
223 solver_data.solver_tolerance_rel =
224 inverse_mass_operator_data.parameters.solver_data.rel_tol;
226 solver_data.use_preconditioner =
227 inverse_mass_operator_data.parameters.preconditioner != PreconditionerMass::None;
228 if(inverse_mass_operator_data.parameters.preconditioner == PreconditionerMass::None)
232 else if(inverse_mass_operator_data.parameters.preconditioner ==
233 PreconditionerMass::PointJacobi)
235 global_preconditioner =
236 std::make_shared<JacobiPreconditioner<MassOperator<dim, n_components, Number>>>(
237 mass_operator,
true );
239 else if(inverse_mass_operator_data.parameters.preconditioner ==
240 PreconditionerMass::BlockJacobi)
242 global_preconditioner =
243 std::make_shared<BlockJacobiPreconditioner<MassOperator<dim, n_components, Number>>>(
244 mass_operator,
true );
246 else if(inverse_mass_operator_data.parameters.preconditioner == PreconditionerMass::AMG)
248 global_preconditioner =
249 std::make_shared<PreconditionerAMG<MassOperator<dim, n_components, Number>, Number>>(
252 inverse_mass_operator_data.parameters.amg_data);
256 AssertThrow(
false, dealii::ExcMessage(
"This `PreconditionerMass` is not implemented."));
259 global_solver = std::make_shared<Krylov::SolverCG<MassOperator<dim, n_components, Number>,
261 VectorType>>(mass_operator,
262 *global_preconditioner,
268 dealii::ExcMessage(
"The specified `InverseMassType` is not implemented."));
280 if(data.implementation_type == InverseMassType::MatrixfreeOperator)
285 else if(data.implementation_type == InverseMassType::ElementwiseKrylovSolver or
286 data.implementation_type == InverseMassType::BlockMatrices)
292 block_jacobi_preconditioner->update();
294 else if(data.implementation_type == InverseMassType::GlobalKrylovSolver)
296 global_preconditioner->update();
300 AssertThrow(
false, dealii::ExcMessage(
"The specified InverseMassType is not implemented."));
308 if(data.implementation_type == InverseMassType::GlobalKrylovSolver)
310 AssertThrow(global_solver.get() != 0,
311 dealii::ExcMessage(
"Global mass solver has not been initialized."));
312 this->n_iter_global_last = global_solver->solve(dst, src);
316 dst.zero_out_ghost_values();
318 if(data.implementation_type == InverseMassType::MatrixfreeOperator)
320 matrix_free->cell_loop(&This::cell_loop_matrix_free_operator,
this, dst, src);
324 AssertThrow(block_jacobi_preconditioner.get() != 0,
326 "Cell-wise iterative/direct block-Jacobi solver has not been initialized."));
327 block_jacobi_preconditioner->vmult(dst, src);
334 apply_scale(VectorType & dst,
double const scaling_factor, VectorType
const & src)
const
336 if(data.implementation_type == InverseMassType::MatrixfreeOperator)
342 dst.zero_out_ghost_values();
344 matrix_free->cell_loop(
345 &This::cell_loop_matrix_free_operator,
350 [&](
const unsigned int start_range,
const unsigned int end_range) {
351 for(
unsigned int i = start_range; i < end_range; ++i)
352 dst.local_element(i) *= scaling_factor;
359 dst *= scaling_factor;
366 cell_loop_matrix_free_operator(dealii::MatrixFree<dim, Number>
const &,
368 VectorType
const & src,
369 Range
const & cell_range)
const
371 Integrator integrator(*matrix_free, dof_index, quad_index);
372 InverseMassAsMatrixFreeOperator inverse_mass(integrator);
374 if(coefficient_is_variable)
376 for(
unsigned int cell = cell_range.first; cell < cell_range.second; ++cell)
378 integrator.reinit(cell);
379 integrator.read_dof_values(src, 0);
381 dealii::AlignedVector<dealii::VectorizedArray<Number>> inverse_JxW_times_coefficient(
382 integrator.n_q_points);
383 inverse_mass.fill_inverse_JxW_values(inverse_JxW_times_coefficient);
385 if(consider_inverse_coefficient)
390 for(
unsigned int q = 0; q < integrator.n_q_points; ++q)
392 inverse_JxW_times_coefficient[q] *=
393 this->variable_coefficients->get_coefficient_cell(cell, q);
401 for(
unsigned int q = 0; q < integrator.n_q_points; ++q)
403 inverse_JxW_times_coefficient[q] /=
404 this->variable_coefficients->get_coefficient_cell(cell, q);
408 inverse_mass.apply(inverse_JxW_times_coefficient,
410 integrator.begin_dof_values(),
411 integrator.begin_dof_values());
413 integrator.set_dof_values(dst, 0);
418 for(
unsigned int cell = cell_range.first; cell < cell_range.second; ++cell)
420 integrator.reinit(cell);
421 integrator.read_dof_values(src, 0);
423 inverse_mass.apply(integrator.begin_dof_values(), integrator.begin_dof_values());
425 integrator.set_dof_values(dst, 0);
430 dealii::MatrixFree<dim, Number>
const * matrix_free;
432 unsigned int dof_index, quad_index;
434 InverseMassParameters data;
437 bool coefficient_is_variable;
438 bool consider_inverse_coefficient;
440 VariableCoefficients<dealii::VectorizedArray<Number>>
const * variable_coefficients;
444 std::shared_ptr<PreconditionerBase<Number>> global_preconditioner;
445 std::shared_ptr<Krylov::SolverBase<VectorType>> global_solver;
448 mutable unsigned int n_iter_global_last = dealii::numbers::invalid_unsigned_int;
454 std::shared_ptr<BlockJacobiPreconditioner<MassOperator<dim, n_components, Number>>>
455 block_jacobi_preconditioner;
458 MassOperator<dim, n_components, Number> mass_operator;