https://mooseframework.inl.gov
Loading...
Searching...
No Matches
RestartableEquationSystems.C
Go to the documentation of this file.
1//* This file is part of the MOOSE framework
2//* https://mooseframework.inl.gov
3//*
4//* All rights reserved, see COPYRIGHT for full restrictions
5//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6//*
7//* Licensed under LGPL 2.1, please see LICENSE for details
8//* https://www.gnu.org/licenses/lgpl-2.1.html
9
11
12#include "DataIO.h"
13
14#include "libmesh/dof_map.h"
15#include "libmesh/dof_object.h"
16#include "libmesh/elem.h"
17#include "libmesh/node.h"
18
20 "SYSTEM_SOLUTION";
21
23 : _es(mesh), _load_all_vectors(true)
24{
25}
26
29 const std::vector<const libMesh::DofObject *> & ordered_objects) const
30{
31 EquationSystemsHeader es_header;
32
33 // Systems
34 for (const auto sys_num : make_range(_es.n_systems()))
35 {
36 const auto & sys = _es.get_system(sys_num);
37
38 SystemHeader sys_header;
39 sys_header.name = sys.name();
40 sys_header.type = sys.system_type();
41
42 // Variables in the system
43 for (const auto var_num : make_range(sys.n_vars()))
44 {
45 const auto & var = sys.variable(var_num);
46
47 VariableHeader var_header;
48 var_header.name = var.name();
49 var_header.type = var.type();
50 var_header.size = 0;
51 var_header.variable = &var;
52
53 mooseAssert(_es.comm().verify("sys_" + sys.name() + "_var_" + var.name()),
54 "Out of order in parallel");
55 mooseAssert(!sys_header.variables.count(var.name()), "Already inserted");
56
57 // Non-SCALAR variable
58 if (var.type().family != SCALAR)
59 {
60 for (const auto & obj : ordered_objects)
61 var_header.size += sizeof(Real) * obj->n_comp(sys.number(), var.number());
62 }
63 // SCALAR variable on the last rank
64 else if (_es.processor_id() == _es.n_processors() - 1)
65 {
66 std::vector<dof_id_type> scalar_dofs;
67 sys.get_dof_map().SCALAR_dof_indices(scalar_dofs, var.number());
68 var_header.size += sizeof(Real) * scalar_dofs.size();
69 }
70
71 sys_header.variables.emplace(var.name(), var_header);
72 }
73
74 // System vector
75 auto & sys_vec_header = sys_header.vectors[SystemHeader::system_solution_name];
76 sys_vec_header.name = SystemHeader::system_solution_name;
77 sys_vec_header.vector = sys.solution.get();
78 sys_vec_header.type = sys_vec_header.vector->type();
79 for (const auto vec_num : make_range(sys.n_vectors()))
80 {
81 mooseAssert(_es.comm().verify("sys_" + sys.name() + "_vec_" + sys.vector_name(vec_num)),
82 "Out of order in parallel");
83 const auto & name = sys.vector_name(vec_num);
84 mooseAssert(!sys_header.vectors.count(name), "Already inserted");
85 auto & vec_header = sys_header.vectors[name];
86 vec_header.name = sys.vector_name(vec_num);
87 vec_header.projections = sys.vector_preservation(vec_header.name);
88 vec_header.vector = &sys.get_vector(vec_header.name);
89 vec_header.type = vec_header.vector->type();
90 }
91
92 // System in this EquationSystems
93 mooseAssert(!es_header.systems.count(sys.name()), "Already inserted");
94 es_header.systems.emplace(sys.name(), sys_header);
95 }
96
97 // Setup the positions in each vector for easy access later
98 std::size_t offset = 0;
99 for (auto & sys_name_header_pair : es_header.systems)
100 {
101 auto & sys_header = sys_name_header_pair.second;
102 for (auto & vec_name_header_pair : sys_header.vectors)
103 {
104 auto & vec_header = vec_name_header_pair.second;
105 for (const auto & var_name_header_pair : sys_header.variables)
106 {
107 const auto & var_header = var_name_header_pair.second;
108 mooseAssert(!vec_header.variable_offset.count(var_header.name), "Already inserted");
109 vec_header.variable_offset[var_header.name] = offset;
110 offset += var_header.size;
111 }
112 }
113 }
114
115 es_header.data_size = offset;
116
117 return es_header;
118}
119
120std::vector<const libMesh::DofObject *>
122{
123 std::vector<const libMesh::DofObject *> objects;
124 auto add = [&objects](const auto begin, const auto end)
125 {
126 std::set<const libMesh::DofObject *, libMesh::CompareDofObjectsByID> ordered(begin, end);
127 objects.insert(objects.end(), ordered.begin(), ordered.end());
128 };
129
130 const auto & mesh = _es.get_mesh();
131 add(mesh.local_elements_begin(), mesh.local_elements_end());
132 add(mesh.local_nodes_begin(), mesh.local_nodes_end());
133
134 return objects;
135}
136
137void
138RestartableEquationSystems::store(std::ostream & stream) const
139{
140 // Order objects (elements and then nodes) by ID for storing
141 const auto ordered_objects = orderDofObjects();
142
143 // Store the header (systems, variables, vectors)
144 EquationSystemsHeader es_header = buildHeader(ordered_objects);
145 dataStore(stream, es_header, nullptr);
146
147 // Store the ordered objects so we can do a sanity check on if we're
148 // loading the same thing
149 {
150 std::vector<dof_id_type> ordered_objects_ids(ordered_objects.size());
151 for (const auto i : index_range(ordered_objects))
152 ordered_objects_ids[i] = ordered_objects[i]->id();
153 dataStore(stream, ordered_objects_ids, nullptr);
154 }
155
156#ifndef NDEBUG
157 const std::size_t data_initial_position = static_cast<std::size_t>(stream.tellp());
158#endif
159
160 // Store each system
161 for (const auto & sys_name_header_pair : es_header.systems)
162 {
163 const auto & sys_header = sys_name_header_pair.second;
164 const auto & sys = _es.get_system(sys_header.name);
165
166 // Store each vector and variable
167 for (const auto & vec_name_header_pair : sys_header.vectors)
168 {
169 const auto & vec_header = vec_name_header_pair.second;
170 const auto & vec = *vec_header.vector;
171 for (const auto & var_name_header_pair : sys_header.variables)
172 {
173 const auto & var_header = var_name_header_pair.second;
174 const auto & var = *var_header.variable;
175
176#ifndef NDEBUG
177 const std::size_t var_initial_position = stream.tellp();
178#endif
179
180 // Non-SCALAR variable
181 if (var.type().family != SCALAR)
182 {
183 // Store for each component of each element and node
184 for (const auto & obj : ordered_objects)
185 for (const auto comp : make_range(obj->n_comp(sys.number(), var.number())))
186 {
187 auto val = vec(obj->dof_number(sys.number(), var.number(), comp));
188 dataStore(stream, val, nullptr);
189 }
190 }
191 // SCALAR variable on the last rank
192 else if (_es.processor_id() == _es.n_processors() - 1)
193 {
194 const auto & dof_map = sys.get_dof_map();
195 std::vector<dof_id_type> scalar_dofs;
196 dof_map.SCALAR_dof_indices(scalar_dofs, var.number());
197 for (const auto dof : scalar_dofs)
198 {
199 auto val = vec(dof);
200 dataStore(stream, val, nullptr);
201 }
202 }
203
204#ifndef NDEBUG
205 const std::size_t data_offset = var_initial_position - data_initial_position;
206 mooseAssert(vec_header.variable_offset.at(var_header.name) == data_offset,
207 "Invalid offset");
208
209 const std::size_t current_position = static_cast<std::size_t>(stream.tellp());
210 const std::size_t var_size = current_position - var_initial_position;
211 mooseAssert(var_size == sys_header.variables.at(var.name()).size, "Incorrect assumed size");
212#endif
213 }
214 }
215 }
216
217 mooseAssert((data_initial_position + es_header.data_size) ==
218 static_cast<std::size_t>(stream.tellp()),
219 "Incorrect assumed size");
220}
221
222void
224{
225 // Load the header (systems, variables, vectors)
226 // We do this first so that the loader can make informed decisions
227 // on what to put where based on everything that is available
228 _loaded_header.systems.clear();
229 dataLoad(stream, _loaded_header, nullptr);
230
231 // Order objects (elements and then node) by ID for storing
233
234 // Clear previously loaded variables to ensure a clean state
235 _loaded_variables.clear();
236
237 // Sanity check on if we're loading the same thing
238 {
239 const std::string mesh_mismatch_message =
240 ". This means that equation-system data is being restored onto a different mesh topology. "
241 "If this occurs while restoring a MultiApp sub-application that uses mesh adaptivity, the "
242 "backup may not contain mesh checkpoint data for the restored topology, or the "
243 "sub-application mesh may have changed after the backup was made. Use clone_parent_mesh = "
244 "true when the sub-application should share the parent application's mesh topology, or "
245 "avoid changing the sub-application mesh between backup and restore.";
246
247 std::vector<dof_id_type> from_ordered_objects_ids;
248 dataLoad(stream, from_ordered_objects_ids, nullptr);
249 if (_loaded_ordered_objects.size() != from_ordered_objects_ids.size())
250 mooseError("RestartableEquationSystems::load(): Number of previously stored elements/nodes (",
251 from_ordered_objects_ids.size(),
252 ") does not match the current number of elements/nodes (",
254 mesh_mismatch_message);
255 for (const auto i : index_range(_loaded_ordered_objects))
256 if (_loaded_ordered_objects[i]->id() != from_ordered_objects_ids[i])
257 mooseError("RestartableEquationSystems::load(): Id of previously stored element/node (",
258 from_ordered_objects_ids[i],
259 ") does not match the current element/node id (",
261 mesh_mismatch_message);
262 }
263
264 _loaded_stream_data_begin = static_cast<std::size_t>(stream.tellg());
265
266 // Load everything that we have available at the moment
267 for (const auto & sys_name_header_pair : _loaded_header.systems)
268 {
269 const auto & sys_header = sys_name_header_pair.second;
270 if (!_es.has_system(sys_header.name))
271 continue;
272 auto & sys = _es.get_system(sys_header.name);
273
274 bool modified_sys = false;
275
276 for (const auto & vec_name_header_pair : sys_header.vectors)
277 {
278 bool modified_vec = false;
279
280 const auto & vec_header = vec_name_header_pair.second;
281 const bool is_solution = vec_header.name == SystemHeader::system_solution_name;
282
283 if (!is_solution && !sys.have_vector(vec_header.name))
284 {
286 sys.add_vector(vec_header.name, vec_header.projections, vec_header.type);
287 else
288 continue;
289 }
290
291 auto & vec = is_solution ? *sys.solution : sys.get_vector(vec_header.name);
292
293 for (const auto & var_name_header_pair : sys_header.variables)
294 {
295 const auto & var_header = var_name_header_pair.second;
296 if (!sys.has_variable(var_header.name))
297 continue;
298 const auto & var = sys.variable(sys.variable_number(var_header.name));
299 if (var.type() != var_header.type)
300 continue;
301
302 restore(sys_header, vec_header, var_header, sys, vec, var, stream);
303 modified_vec = true;
304 }
305
306 if (modified_vec)
307 {
308 vec.close();
309 modified_sys = true;
310 }
311 }
312
313 if (modified_sys)
314 sys.update();
315 }
316
317 // Move the stream to the end of our data so that we make RestartableDataReader happy
319}
320
321bool
323 const std::string & vector_name,
324 const std::string & variable_name) const
325{
326 std::tuple<std::string, std::string, std::string> key(system_name, vector_name, variable_name);
327 return _loaded_variables.count(key);
328}
329
330void
332 const VectorHeader & from_vec_header,
333 const VariableHeader & from_var_header,
334 const libMesh::System & to_sys,
336 const libMesh::Variable & to_var,
337 std::istream & stream)
338{
339#ifndef NDEBUG
340 const auto sys_it = _loaded_header.systems.find(from_sys_header.name);
341 mooseAssert(sys_it != _loaded_header.systems.end(), "System does not exist");
342 const auto & sys_header = sys_it->second;
343 mooseAssert(sys_header == from_sys_header, "Not my system");
344 const auto vec_it = sys_header.vectors.find(from_vec_header.name);
345 mooseAssert(vec_it != sys_header.vectors.end(), "Vector does not exist");
346 const auto & vec_header = vec_it->second;
347 mooseAssert(vec_header == from_vec_header, "Not my vector");
348 const auto var_it = sys_header.variables.find(from_var_header.name);
349 mooseAssert(var_it != sys_header.variables.end(), "Variable does not exist");
350 const auto & var_header = var_it->second;
351 mooseAssert(var_header == from_var_header, "Not my variable");
352 mooseAssert(!isVariableRestored(from_sys_header.name, from_vec_header.name, from_var_header.name),
353 "Variable already restored");
354#endif
355
356 const auto error =
357 [&from_sys_header, &from_vec_header, &from_var_header, &to_sys, &to_var](auto... args)
358 {
359 mooseError("An error occured while restoring a system:\n",
360 args...,
361 "\n\nFrom system: ",
362 from_sys_header.name,
363 "\nFrom vector: ",
364 from_vec_header.name,
365 "\nFrom variable: ",
366 from_var_header.name,
367 "\nTo system: ",
368 to_sys.name(),
369 "\nTo variable: ",
370 to_var.name());
371 };
372
373 if (from_var_header.type != to_var.type())
374 error("Cannot restore to a variable of a different type");
375
376 const auto offset = from_vec_header.variable_offset.at(from_var_header.name);
377 stream.seekg(_loaded_stream_data_begin + offset);
378
379 // Non-SCALAR variable
380 if (to_var.type().family != SCALAR)
381 {
382 for (const auto & obj : _loaded_ordered_objects)
383 for (const auto comp : make_range(obj->n_comp(to_sys.number(), to_var.number())))
384 {
385 Real val;
386 dataLoad(stream, val, nullptr);
387 to_vec.set(obj->dof_number(to_sys.number(), to_var.number(), comp), val);
388 }
389 }
390 // SCALAR variable on the last rank
391 else if (_es.processor_id() == _es.n_processors() - 1)
392 {
393 const auto & dof_map = to_sys.get_dof_map();
394 std::vector<dof_id_type> scalar_dofs;
395 dof_map.SCALAR_dof_indices(scalar_dofs, to_var.number());
396 for (const auto dof : scalar_dofs)
397 {
398 Real val;
399 dataLoad(stream, val, nullptr);
400 to_vec.set(dof, val);
401 }
402 }
403
404 // insert into the member variable
405 std::tuple<std::string, std::string, std::string> _loaded_variable = {
406 from_sys_header.name, from_vec_header.name, from_var_header.name};
407
408 _loaded_variables.insert(_loaded_variable);
409
410 mooseAssert(isVariableRestored(from_sys_header.name, from_vec_header.name, from_var_header.name),
411 "Variable not marked as restored");
412}
413
414void
415dataStore(std::ostream & stream, RestartableEquationSystems & res, void *)
416{
417 res.store(stream);
418}
419
420void
421dataLoad(std::istream & stream, RestartableEquationSystems & res, void *)
422{
423 res.load(stream);
424}
425
426void
427dataStore(std::ostream & stream, RestartableEquationSystems::EquationSystemsHeader & header, void *)
428{
429 dataStore(stream, header.systems, nullptr);
430 dataStore(stream, header.data_size, nullptr);
431}
432
433void
434dataLoad(std::istream & stream, RestartableEquationSystems::EquationSystemsHeader & header, void *)
435{
436 dataLoad(stream, header.systems, nullptr);
437 dataLoad(stream, header.data_size, nullptr);
438}
439
440void
441dataStore(std::ostream & stream, RestartableEquationSystems::SystemHeader & header, void *)
442{
443 dataStore(stream, header.name, nullptr);
444 dataStore(stream, header.type, nullptr);
445 dataStore(stream, header.variables, nullptr);
446 dataStore(stream, header.vectors, nullptr);
447}
448
449void
450dataLoad(std::istream & stream, RestartableEquationSystems::SystemHeader & header, void *)
451{
452 dataLoad(stream, header.name, nullptr);
453 dataLoad(stream, header.type, nullptr);
454 dataLoad(stream, header.variables, nullptr);
455 dataLoad(stream, header.vectors, nullptr);
456}
457
458void
459dataStore(std::ostream & stream, RestartableEquationSystems::VariableHeader & header, void *)
460{
461 dataStore(stream, header.name, nullptr);
462 dataStore(stream, header.type, nullptr);
463}
464void
465dataLoad(std::istream & stream, RestartableEquationSystems::VariableHeader & header, void *)
466{
467 dataLoad(stream, header.name, nullptr);
468 dataLoad(stream, header.type, nullptr);
469}
470
471void
472dataStore(std::ostream & stream, RestartableEquationSystems::VectorHeader & header, void *)
473{
474 dataStore(stream, header.name, nullptr);
475 dataStore(stream, header.projections, nullptr);
476 dataStore(stream, header.type, nullptr);
477 dataStore(stream, header.variable_offset, nullptr);
478}
479void
480dataLoad(std::istream & stream, RestartableEquationSystems::VectorHeader & header, void *)
481{
482 dataLoad(stream, header.name, nullptr);
483 dataLoad(stream, header.projections, nullptr);
484 dataLoad(stream, header.type, nullptr);
485 dataLoad(stream, header.variable_offset, nullptr);
486}
487
488void
489to_json(nlohmann::json & json, const RestartableEquationSystems & res)
490{
491
492 nlohmann::json loaded_vars = nlohmann::json::array();
493
494 for (const auto & [system, vector, variable] : res.getLoadedVariables())
495 {
496 loaded_vars.push_back({{"system", system}, {"vector", vector}, {"variable", variable}});
497 }
498
499 json["loaded_variables"] = loaded_vars;
500}
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
Definition MooseError.h:311
void dataLoad(std::istream &stream, RestartableEquationSystems &res, void *)
void to_json(nlohmann::json &json, const RestartableEquationSystems &res)
void dataStore(std::ostream &stream, RestartableEquationSystems &res, void *)
void dataLoad(std::istream &stream, RestartableEquationSystems &res, void *)
void dataStore(std::ostream &stream, RestartableEquationSystems &res, void *)
Wrapper class that owns a libMesh EquationSystem and adds advanced restart capability to it.
bool isVariableRestored(const std::string &system_name, const std::string &vector_name, const std::string &variable_name) const
Checks whether variable was successfully restored from a restart file.
std::vector< const libMesh::DofObject * > orderDofObjects() const
Internal method for ordering the DofObjects by ID (elems and the nodes)
void restore(const SystemHeader &from_sys_header, const VectorHeader &from_vec_header, const VariableHeader &from_var_header, const libMesh::System &to_sys, libMesh::NumericVector< libMesh::Number > &to_vec, const libMesh::Variable &to_var, std::istream &stream)
std::set< std::tuple< std::string, std::string, std::string > > _loaded_variables
The variables that were loaded in load(); [system name, vector name, variable name].
void store(std::ostream &stream) const
Stores the EquationSystems to the given stream.
bool _load_all_vectors
Whether or not to load all of the vectors, including ones that haven't been added yet.
const std::set< std::tuple< std::string, std::string, std::string > > & getLoadedVariables() const
Returns the set of variables that were loaded during the load() function. Each set of variables conta...
std::size_t _loaded_stream_data_begin
The starting position for the vector data in the input stream.
EquationSystemsHeader _loaded_header
The loaded header.
void load(std::istream &stream)
Loads the EquationSystems from the given stream.
RestartableEquationSystems(libMesh::MeshBase &mesh)
libMesh::EquationSystems _es
The underlying EquationSystems.
EquationSystemsHeader buildHeader(const std::vector< const libMesh::DofObject * > &ordered_objects) const
Internal method for building the header struct.
std::vector< const libMesh::DofObject * > _loaded_ordered_objects
The object ordering for this data.
timpi_pure bool verify(const T &r) const
void SCALAR_dof_indices(std::vector< dof_id_type > &di, const unsigned int vn, const bool old_dofs=false) const
unsigned int n_systems() const
const MeshBase & get_mesh() const
bool has_system(std::string_view name) const
const T_sys & get_system(std::string_view name) const
virtual void set(const numeric_index_type i, const T value)=0
processor_id_type processor_id() const
const Parallel::Communicator & comm() const
processor_id_type n_processors() const
const std::string & name() const
const DofMap & get_dof_map() const
unsigned int number() const
const std::string & name() const
unsigned int number() const
const FEType & type() const
MeshBase & mesh
Represents a stored EquationSystems in restart.
std::map< std::string, RestartableEquationSystems::SystemHeader > systems
The stored systems in the equation systems.
std::size_t data_size
The total size of data for this EquationSystems.
Represents a stored system in restart.
std::map< std::string, RestartableEquationSystems::VariableHeader > variables
The stored variables in the system.
std::string type
The type of the stored system.
static const std::string system_solution_name
Special name for a vector that is the system solution vector.
std::string name
The name of the stored system.
std::map< std::string, RestartableEquationSystems::VectorHeader > vectors
The stored vectors in the system.
Represents a stored variable in restart.
const libMesh::Variable * variable
The underlying variable (only valid during store, not used in load)
std::size_t size
The size of this variable's data.
std::string name
The name of the stored variable.
libMesh::FEType type
The type of the stored variable.
Represents a stored variable in restart.
std::string name
The name of the stored vector.
bool projections
The projection flag (whether or not it should be projected or zeroed)
libMesh::ParallelType type
The type of the stored vector.
std::map< std::string, std::size_t > variable_offset
The position of each variable for this vector (relative to the start of the data)