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