PRISMS-PF Manual
Loading...
Searching...
No Matches
solve_block.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/base/exceptions.h>
7#include <deal.II/matrix_free/evaluation_flags.h>
8
11#include <prismspf/core/types.h>
12
15
16#include <prismspf/config.h>
17
18#include <set>
19#include <string>
20#include <vector>
21
23
51
52// NOLINTBEGIN(misc-non-private-member-variables-in-classes, hicpp-explicit-conversions)
53// readability-simplify-boolean-expr
54
59{
60public:
61 using EvalFlags = dealii::EvaluationFlags::EvaluationFlags;
63
64 explicit SolveBlock(int _id = -1,
65 SolveType _solve_type = Explicit,
66 SolveTiming _solve_timing = Primary,
67 std::set<Types::Index> _field_indices = {},
68 DependencyMap _dependencies_rhs = {},
69 DependencyMap _dependencies_lhs = {})
70 : id(_id)
71 , solve_type(_solve_type)
72 , solve_timing(_solve_timing)
73 , field_indices(std::move(_field_indices))
74 , dependencies_rhs(std::move(_dependencies_rhs))
75 , dependencies_lhs(std::move(_dependencies_lhs))
76 {}
77
82 int id;
83
88
94
98 std::set<Types::Index> field_indices;
99
108
114
120
121 bool
122 operator<(const SolveBlock &other) const
123 {
124 return id < other.id;
125 }
126
127 void
128 validate() const;
129};
130
131inline void
133{
134 try
135 {
136 AssertThrow(solve_type == SolveType::Constant ||
139 dealii::ExcMessage("A valid solve type must be selected (Constant | "
140 "Explicit | Linear | Newton)\n"));
141 AssertThrow(!field_indices.empty(),
142 dealii::ExcMessage("This solve block must manage at least 1 field.\n"));
144 {
145 for (unsigned int field_index : field_indices)
146 {
147 const auto &dep_it_rhs = dependencies_rhs.find(field_index);
148 AssertThrow(dep_it_rhs != dependencies_rhs.end(),
149 dealii::ExcMessage(
150 "Every field in a newton solve should appear "
151 "in the residual (RHS) expression.\n"));
152 AssertThrow(dep_it_rhs->second.flag != EvalFlags::nothing,
153 dealii::ExcMessage(
154 "Every field in a newton solve should appear "
155 "in the residual (RHS) expression.\n"));
156 const auto &dep_it_lhs = dependencies_lhs.find(field_index);
157 AssertThrow(dep_it_lhs != dependencies_lhs.end(),
158 dealii::ExcMessage(
159 "Every field in a newton solve should appear as a Delta term"
160 "in the residual Jacobian (LHS) expression.\n"));
161 AssertThrow(dep_it_lhs->second.src_flag != EvalFlags::nothing,
162 dealii::ExcMessage(
163 "Every field in a newton solve should appear as a Delta term"
164 "in the residual Jacobian (LHS) expression.\n"));
165 }
166 }
167 else
168 {
169 for (unsigned int field_index : field_indices)
170 {
171 const auto &dep_it_rhs = dependencies_rhs.find(field_index);
172 if (dep_it_rhs != dependencies_rhs.end())
173 {
174 AssertThrow(dep_it_rhs->second.flag == EvalFlags::nothing,
175 dealii::ExcMessage(
176 "The current value of a field should never appear "
177 "in the RHS of a solve that is not type Newton.\n"));
178 }
179 }
180 }
182 {
183 for (unsigned int field_index : field_indices)
184 {
185 const auto &dep_it_lhs = dependencies_lhs.find(field_index);
186 AssertThrow(dep_it_lhs != dependencies_lhs.end(),
187 dealii::ExcMessage(
188 "Every field in a linear solve should appear "
189 "in the (LHS) expression. Be sure to use the src_flag.\n"));
190 AssertThrow(dep_it_lhs->second.src_flag != EvalFlags::nothing,
191 dealii::ExcMessage(
192 "Every field in a linear solve should appear "
193 "in the (LHS) expression. Be sure to use the src_flag.\n"));
194 }
195 }
197 {
198 AssertThrow(dependencies_lhs.empty(),
199 dealii::ExcMessage("Explicit solves do not have an LHS, "
200 "and should have no LHS dependencies.\n"));
201 }
203 {
204 AssertThrow(dependencies_rhs.empty() && dependencies_lhs.empty(),
205 dealii::ExcMessage("Constant \"solves\" do not have an RHS or LHS, "
206 "and should have no dependencies.\n"));
207 }
208 for (const auto &[field_index, dependency] : dependencies_rhs)
209 {
210 AssertThrow(dependency.src_flag == EvalFlags::nothing,
211 dealii::ExcMessage(
212 "Trial/Change terms should not appear in RHS expressions.\n"));
213 }
214 }
215 catch (...)
216 {
218 << "Error found during validation of solve block with id " << id << "\n";
219 throw;
220 }
221}
222
223inline const std::vector<SolveBlock> &
224validate_solve_blocks(const std::vector<SolveBlock> &solve_blocks,
225 const std::vector<FieldAttributes> &field_attributes)
226{
227 // Check that field names are unique
228 {
229 std::set<std::string> field_names;
230 for (const auto &field_attribute : field_attributes)
231 {
232 AssertThrow(field_names.find(field_attribute.name) == field_names.end(),
233 dealii::ExcMessage("Each field must have a unique name.\n"));
234 field_names.insert(field_attribute.name);
235 }
236 }
237 // Validate each solve block individually
238 for (const auto &solve_block : solve_blocks)
239 {
240 solve_block.validate();
241 }
242 // Check for duplicate solve block ids
243 {
244 std::set<int> ids;
245 for (const auto &solve_block : solve_blocks)
246 {
247 AssertThrow(ids.find(solve_block.id) == ids.end(),
248 dealii::ExcMessage("Each solve block must have a unique id.\n"));
249 ids.insert(solve_block.id);
250 }
251 }
252 // Check that each field is in exactly one solve block
253 {
254 std::set<unsigned int> field_indices;
255 for (unsigned int i = 0; i < field_attributes.size(); ++i)
256 {
257 field_indices.insert(i);
258 }
259 for (const auto &solve_block : solve_blocks)
260 {
261 for (unsigned int field_index : solve_block.field_indices)
262 {
263 size_t erased = field_indices.erase(field_index);
264 AssertThrow(erased == 1,
265 dealii::ExcMessage("Each field should be managed by exactly one "
266 "solve block. The field with index " +
267 std::to_string(field_index) +
268 " is anomalously assigned to solve block " +
269 std::to_string(solve_block.id) + ".\n"));
270 }
271 }
272 std::string remaining_fields;
273 for (unsigned int field_index : field_indices)
274 {
275 remaining_fields.append(std::to_string(field_index) + ": " +
276 field_attributes[field_index].name + "\n");
277 }
278 AssertThrow(
279 field_indices.empty(),
280 dealii::ExcMessage(
281 "Every field should be managed by exactly one solve block. The following "
282 "fields are not managed by any solve block:\n" +
283 remaining_fields));
284 }
285 // Check that the dependencies of each solve block only refer to fields that are
286 // defined in the field attributes.
287 {
288 std::set<unsigned int> valid_field_indices;
289 for (unsigned int i = 0; i < field_attributes.size(); ++i)
290 {
291 valid_field_indices.insert(i);
292 }
293 for (const auto &solve_block : solve_blocks)
294 {
295 for (const auto &[field_index, dependency] : solve_block.dependencies_rhs)
296 {
297 AssertThrow(
298 valid_field_indices.find(field_index) != valid_field_indices.end(),
299 dealii::ExcMessage("The RHS dependencies of solve block with id " +
300 std::to_string(solve_block.id) +
301 " refer to a field index that is out of range.\n"));
302 }
303 for (const auto &[field_index, dependency] : solve_block.dependencies_lhs)
304 {
305 AssertThrow(
306 valid_field_indices.find(field_index) != valid_field_indices.end(),
307 dealii::ExcMessage("The LHS dependencies of solve block with id " +
308 std::to_string(solve_block.id) +
309 " refer to a field index that is out of range.\n"));
310 }
311 }
312 }
313 // Check that the order of the solve blocks is consistent with their solve timing.
314 // This will be non-exhaustive. Only checking that there are no dependencies for current
315 // value that doesn't exist yet.
316
317 std::set<unsigned int> solved_field_indices;
318 for (const auto &solve_block : solve_blocks)
319 {
320 for (const auto &[field_index, dependency] : solve_block.dependencies_rhs)
321 {
322 if (dependency.flag != EvalFlags::nothing &&
323 solve_block.solve_type != SolveType::Newton)
324 {
325 AssertThrow(solved_field_indices.find(field_index) !=
326 solved_field_indices.end(),
327 dealii::ExcMessage(
328 "Solve block with id " + std::to_string(solve_block.id) +
329 " has an rhs dependency on the current value of field \"" +
330 field_attributes[field_index].name + "\" with index " +
331 std::to_string(field_index) +
332 " which is not solved in a previous solve block. This is not "
333 "allowed.\n"));
334 }
335 }
336 for (const auto &[field_index, dependency] : solve_block.dependencies_lhs)
337 {
338 if (dependency.flag != EvalFlags::nothing &&
339 solve_block.solve_type != SolveType::Newton)
340 {
341 AssertThrow(solved_field_indices.find(field_index) !=
342 solved_field_indices.end(),
343 dealii::ExcMessage(
344 "Solve block with id " + std::to_string(solve_block.id) +
345 " has a lhs dependency on the current value of field \"" +
346 field_attributes[field_index].name + "\" with index " +
347 std::to_string(field_index) +
348 " which is not solved in a previous solve block. This is not "
349 "allowed.\n"));
350 }
351 }
352 for (unsigned int field_index : solve_block.field_indices)
353 {
354 solved_field_indices.insert(field_index);
355 }
356 }
357 return solve_blocks;
358}
359
361
362// NOLINTEND(misc-non-private-member-variables-in-classes, hicpp-explicit-conversions)
363
364PRISMS_PF_END_NAMESPACE
static dealii::ConditionalOStream & pout_base()
Generic parallel output stream. Used for essential information in release and debug mode.
Definition conditional_ostreams.cc:44
Structure to hold the attributes of a solve-block.
Definition solve_block.h:59
LinearSolverParameters linear_solver_parameters
Linear solver parameters. Only used for linear and newton solve blocks.
Definition solve_block.h:113
SolveType solve_type
PDE type (Constant | Explicit | Linear | Newton).
Definition solve_block.h:87
SolveTiming solve_timing
This is used to determine whether to initialize the solution vector with the initial conditions or ju...
Definition solve_block.h:93
int id
Unique identifier. Use this in 'if' statements or switch cases in equations lhs and rhs.
Definition solve_block.h:82
SolveBlock(int _id=-1, SolveType _solve_type=Explicit, SolveTiming _solve_timing=Primary, std::set< Types::Index > _field_indices={}, DependencyMap _dependencies_rhs={}, DependencyMap _dependencies_lhs={})
Definition solve_block.h:64
TensorRank FieldType
Definition solve_block.h:62
DependencyMap dependencies_rhs
Dependencies for the rhs equation(s)
Definition solve_block.h:103
dealii::EvaluationFlags::EvaluationFlags EvalFlags
Definition solve_block.h:61
DependencyMap dependencies_lhs
Dependencies for the lhs equation(s)
Definition solve_block.h:107
void validate() const
Definition solve_block.h:132
NonlinearSolverParameters nonlinear_solver_parameters
Linear solver parameters. Only used for linear and newton solve blocks.
Definition solve_block.h:119
bool operator<(const SolveBlock &other) const
Definition solve_block.h:122
std::set< Types::Index > field_indices
Indices of the fields to be solved in this block.
Definition solve_block.h:98
std::map< Types::Index, Dependency > DependencyMap
Definition dependencies.h:129
Definition conditional_ostreams.cc:20
SolveBlock SolveGroup
Definition solve_block.h:360
SolveTiming
Enum describing when each block of fields gets solved.
Definition solve_block.h:28
@ Uninitialized
Definition solve_block.h:40
@ Primary
Primary fields are initialized explicitly through initial conditions rather than through the solver o...
Definition solve_block.h:33
@ NucleationRate
NucleationRate fields are only solved on nucleation attempt and output increments.
Definition solve_block.h:49
@ PostProcess
PostProcess fields are only solved on output increments.
Definition solve_block.h:44
@ Initialized
Definition solve_block.h:34
@ Secondary
Secondary fields are only evaluated by the pde solver on every increment, not initialized by a separa...
Definition solve_block.h:39
const std::vector< SolveBlock > & validate_solve_blocks(const std::vector< SolveBlock > &solve_blocks, const std::vector< FieldAttributes > &field_attributes)
Definition solve_block.h:224
Struct that stores relevant linear solve information of a certain solve block.
Definition linear_solve_parameters.h:25
Struct that stores relevant nonlinear solve information of a certain field.
Definition nonlinear_solve_parameters.h:20
SolveType
Type of PDE that is being solved.
Definition type_enums.h:17
@ Linear
Definition type_enums.h:33
@ Newton
Definition type_enums.h:43
@ Constant
Definition type_enums.h:21
@ Explicit
Definition type_enums.h:26
TensorRank
Tensor rank of the field.
Definition type_enums.h:52