PRISMS-PF Manual
Loading...
Searching...
No Matches
linear_solver.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: © 2025 PRISMS Center at the University of Michigan
2// SPDX-License-Identifier: GNU Lesser General Public Version 2.1
3
4#pragma once
5
6#include <deal.II/lac/precondition.h>
7#include <deal.II/lac/solver_cg.h>
8#include <deal.II/lac/solver_control.h>
9
13#include <prismspf/core/timer.h>
15#include <prismspf/core/types.h>
16
19
21
22#include <prismspf/config.h>
23
25
26template <unsigned int dim, unsigned int degree, typename number>
27class SolveContext;
28
32template <unsigned int dim, unsigned int degree, typename number>
33class LinearSolver : public SolverBase<dim, degree, number>
34{
35protected:
36 using SolverBase<dim, degree, number>::solutions;
37 using SolverBase<dim, degree, number>::solve_context;
38 using SolverBase<dim, degree, number>::solve_block;
39
40public:
45 const SolveContext<dim, degree, number> &_solve_context)
46 : SolverBase<dim, degree, number>(_solve_block, _solve_context)
47 , lin_params(
48 solve_context->get_user_inputs().linear_solve_parameters.linear_solvers.at(
49 solve_block.id))
50 {}
51
55 void
56 init(const std::list<DependencyMap> &all_dependeny_sets) override
57 {
58 SolverBase<dim, degree, number>::init(all_dependeny_sets);
59 unsigned int num_levels = solve_context->get_dof_manager().get_dof_handlers().size();
60 rhs_vector.resize(num_levels);
61 for (unsigned int relative_level = 0; relative_level < num_levels; ++relative_level)
62 {
63 rhs_vector[relative_level].reinit(
64 solutions.get_solution_full_vector(relative_level));
65 }
66 // Initialize rhs_operators
67 rhs_operators.reserve(num_levels);
68 for (unsigned int relative_level = 0; relative_level < num_levels; ++relative_level)
69 {
70 rhs_operators.emplace_back(solve_context->get_pde_operator(),
72 solve_context->get_field_attributes(),
73 solve_context->get_solution_indexer(),
74 relative_level,
75 solve_block.dependencies_rhs,
76 solve_context->get_simulation_timer());
77 rhs_operators[relative_level].initialize(solutions);
78 rhs_operators[relative_level].set_scaling_diagonal(
79 lin_params.tolerance_type != AbsoluteResidual,
80 solve_context->get_invm_manager().get_invm_sqrt(
81 solve_context->get_field_attributes(),
82 solve_block.field_indices,
83 relative_level));
84 }
85 // Initialize lhs_operators
86 lhs_operators.reserve(num_levels);
87 for (unsigned int relative_level = 0; relative_level < num_levels; ++relative_level)
88 {
89 lhs_operators.emplace_back(solve_context->get_pde_operator(),
91 solve_context->get_field_attributes(),
92 solve_context->get_solution_indexer(),
93 relative_level,
94 solve_block.dependencies_lhs,
95 solve_context->get_simulation_timer());
96 lhs_operators[relative_level].initialize(solutions);
97 lhs_operators[relative_level].set_scaling_diagonal(
98 lin_params.tolerance_type != AbsoluteResidual,
99 solve_context->get_invm_manager().get_invm_sqrt(
100 solve_context->get_field_attributes(),
101 solve_block.field_indices,
102 relative_level));
103 }
104 linear_solver_control.set_max_steps(lin_params.max_iterations);
105 linear_solver_control.set_tolerance(lin_params.tolerance * normalization_value());
106 inhomogenous_values.reinit(solutions.get_solution_full_vector(0));
107 solutions.apply_constraints(inhomogenous_values, 0);
108 inhomogenous_rhs.reinit(solutions.get_solution_full_vector(0));
109 }
110
114 void
115 reinit() override
116 {
118 const unsigned int num_levels = rhs_vector.size();
119 for (unsigned int relative_level = 0; relative_level < num_levels; ++relative_level)
120 {
121 rhs_vector[relative_level].reinit(
122 solutions.get_solution_full_vector(relative_level));
123 }
124 inhomogenous_values.reinit(solutions.get_solution_full_vector(0));
125 solutions.apply_constraints(inhomogenous_values, 0);
126 inhomogenous_rhs.reinit(solutions.get_solution_full_vector(0));
127 }
128
132 void
133 solve_level(unsigned int relative_level) override
134 {
135 // Zero out the ghosts
136 Timer::start_section("Zero ghosts");
137 solutions.zero_out_ghosts(relative_level);
138 Timer::end_section("Zero ghosts");
139
140 // Set up rhs vector
141 rhs_operators[relative_level].compute_operator(rhs_vector[relative_level]);
142 if (relative_level == 0)
143 {
144 lhs_operators[0].read_plain = true;
146 lhs_operators[0].read_plain = false;
148 }
149 // Linear solve
150 do_linear_solve(rhs_vector[relative_level],
151 lhs_operators[relative_level],
152 solutions.get_solution_full_vector(relative_level));
153
154 if (relative_level == 0)
155 {
156 solutions.get_solution_full_vector(0) += inhomogenous_values;
157 }
158 // Apply constraints
159 solutions.apply_constraints(relative_level);
160
161 // Update the ghosts
162 Timer::start_section("Update ghosts");
163 solutions.update_ghosts(relative_level);
164 Timer::end_section("Update ghosts");
165 }
166
167 int
170 BlockVector<number> &x_vector)
171 {
172 // Linear solve
173 try
174 {
175 dealii::SolverCG<BlockVector<number>> cg_solver(linear_solver_control);
176 cg_solver.solve(lhs_operator, x_vector, b_vector, dealii::PreconditionIdentity());
177 if (solve_context->get_user_inputs().output_parameters.should_output(
178 solve_context->get_simulation_timer().get_increment()))
179 {
181 << " Linear solve final residual : "
183 << " Linear steps: " << linear_solver_control.last_step() << "\n"
184 << std::flush;
185 }
186 }
187 catch (...) // TODO: more specific catch
188 {
190 << "[Increment " << solve_context->get_simulation_timer().get_increment()
191 << "] "
192 << "Warning: linear solver did not converge as per set tolerances before "
193 << lin_params.max_iterations << " iterations.\n";
194 }
195 return linear_solver_control.last_step();
196 }
197
198protected:
202 std::vector<MFOperator<dim, degree, number>> rhs_operators;
203
204 std::vector<MFOperator<dim, degree, number>> lhs_operators;
205 std::vector<BlockVector<number>> rhs_vector;
206
207 double
209 {
210 SolverToleranceType type = lin_params.tolerance_type;
211 double value = 1.0;
212 if (type == RMSEPerField || type == RMSETotal)
213 {
214 value *= std::sqrt(solve_context->get_triangulation_manager().get_volume());
215 }
216 if (type == RMSEPerField || type == IntegratedPerField)
217 {
218 value *= std::sqrt(double(solve_block.field_indices.size()));
219 }
220 return value;
221 }
222
223private:
228
232 dealii::SolverControl linear_solver_control;
233
239
244};
245
246PRISMS_PF_END_NAMESPACE
static dealii::ConditionalOStream & pout_summary()
Log output stream for writing a summary.log file.
Definition conditional_ostreams.cc:35
static dealii::ConditionalOStream & pout_base()
Generic parallel output stream. Used for essential information in release and debug mode.
Definition conditional_ostreams.cc:44
std::vector< MFOperator< dim, degree, number > > rhs_operators
Matrix free operators for each level.
Definition linear_solver.h:202
BlockVector< number > inhomogenous_rhs
Result of the linear operator applied to the inhomogeneous values.
Definition linear_solver.h:243
int do_linear_solve(BlockVector< number > &b_vector, MFOperator< dim, degree, number > &lhs_operator, BlockVector< number > &x_vector)
Definition linear_solver.h:168
LinearSolverParameters lin_params
Linear solver parameters.
Definition linear_solver.h:227
double normalization_value()
Definition linear_solver.h:208
void init(const std::list< DependencyMap > &all_dependeny_sets) override
Initialize the solver.
Definition linear_solver.h:56
BlockVector< number > inhomogenous_values
Vector containing only the inhomogeneous constraints (namely, non-zero Dirichlet values)
Definition linear_solver.h:238
std::vector< BlockVector< number > > rhs_vector
Definition linear_solver.h:205
std::vector< MFOperator< dim, degree, number > > lhs_operators
Definition linear_solver.h:204
dealii::SolverControl linear_solver_control
Solver control. Contains max iterations and tolerance.
Definition linear_solver.h:232
LinearSolver(SolveBlock _solve_block, const SolveContext< dim, degree, number > &_solve_context)
Constructor.
Definition linear_solver.h:44
void solve_level(unsigned int relative_level) override
Solve for a single update step.
Definition linear_solver.h:133
void reinit() override
Reinitialize the solver.
Definition linear_solver.h:115
This class exists to evaluate a single user-defined operator for the matrix-free implementation of so...
Definition mf_operator.h:50
virtual void compute_rhs(FieldContainer< dim, degree, number > &variable_list, const SimulationTimer &sim_timer, unsigned int solver_id) const
User-implemented class for the RHS of explicit equations.
Definition pde_operator_base.h:76
virtual void compute_lhs(FieldContainer< dim, degree, number > &variable_list, const SimulationTimer &sim_timer, unsigned int solver_id) const
User-implemented class for the RHS of nonexplicit equations.
Definition pde_operator_base.h:85
Structure to hold the attributes of a solve-block.
Definition solve_block.h:56
This class provides context for a solver with ptrs to all the relevant dependencies.
Definition solve_context.h:36
virtual void reinit()
Reinitialize the solution vectors & apply constraints.
Definition solver_base.h:98
SolverBase(SolveBlock _solve_block, const SolveContext< dim, degree, number > &_solve_context)
Constructor.
Definition solver_base.h:37
virtual void init(const std::list< DependencyMap > &all_dependeny_sets)
Initialize the solver.
Definition solver_base.h:83
GroupSolutionHandler< dim, number > solutions
Solution vectors for fields handled by this solver.
Definition solver_base.h:274
const SolveContext< dim, degree, number > * solve_context
Solver context provides access to external information.
Definition solver_base.h:269
SolveBlock solve_block
Information about the solve block this handler is responsible for.
Definition solver_base.h:264
static void start_section(const char *name)
Start a new timer section.
Definition timer.cc:116
static void end_section(const char *name)
End the timer section.
Definition timer.cc:127
dealii::LinearAlgebra::distributed::BlockVector< number > BlockVector
Typedef for solution block vector.
Definition group_solution_handler.h:29
Definition conditional_ostreams.cc:20
Struct that stores relevant linear solve information of a certain field.
Definition linear_solve_parameters.h:22
SolverToleranceType
Solver tolerance type.
Definition type_enums.h:91
@ RMSEPerField
The mean local error averaged over each field is lower than the tolerance.
Definition type_enums.h:103
@ AbsoluteResidual
Legacy.
Definition type_enums.h:95
@ RMSETotal
The sum of the average local errors of each field is lower than the tolerance.
Definition type_enums.h:111
@ IntegratedPerField
The integrated error averaged over each field is lower than the tolerance.
Definition type_enums.h:107