Line data Source code
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 :
10 : #include "RestartableEquationSystems.h"
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 :
19 : const std::string RestartableEquationSystems::SystemHeader::system_solution_name =
20 : "SYSTEM_SOLUTION";
21 :
22 64512 : RestartableEquationSystems::RestartableEquationSystems(libMesh::MeshBase & mesh)
23 64512 : : _es(mesh), _load_all_vectors(true)
24 : {
25 64512 : }
26 :
27 : RestartableEquationSystems::EquationSystemsHeader
28 45777 : RestartableEquationSystems::buildHeader(
29 : const std::vector<const libMesh::DofObject *> & ordered_objects) const
30 : {
31 45777 : EquationSystemsHeader es_header;
32 :
33 : // Systems
34 138374 : for (const auto sys_num : make_range(_es.n_systems()))
35 : {
36 92597 : const auto & sys = _es.get_system(sys_num);
37 :
38 92597 : SystemHeader sys_header;
39 92597 : sys_header.name = sys.name();
40 92597 : sys_header.type = sys.system_type();
41 :
42 : // Variables in the system
43 184855 : for (const auto var_num : make_range(sys.n_vars()))
44 : {
45 92258 : const auto & var = sys.variable(var_num);
46 :
47 92258 : VariableHeader var_header;
48 92258 : var_header.name = var.name();
49 92258 : var_header.type = var.type();
50 92258 : var_header.size = 0;
51 92258 : 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 92258 : if (var.type().family != SCALAR)
59 : {
60 18673938 : for (const auto & obj : ordered_objects)
61 18583372 : var_header.size += sizeof(Real) * obj->n_comp(sys.number(), var.number());
62 : }
63 : // SCALAR variable on the last rank
64 1692 : else if (_es.processor_id() == _es.n_processors() - 1)
65 : {
66 1655 : std::vector<dof_id_type> scalar_dofs;
67 1655 : sys.get_dof_map().SCALAR_dof_indices(scalar_dofs, var.number());
68 1655 : var_header.size += sizeof(Real) * scalar_dofs.size();
69 1655 : }
70 :
71 92258 : sys_header.variables.emplace(var.name(), var_header);
72 92258 : }
73 :
74 : // System vector
75 92597 : auto & sys_vec_header = sys_header.vectors[SystemHeader::system_solution_name];
76 92597 : sys_vec_header.name = SystemHeader::system_solution_name;
77 92597 : sys_vec_header.vector = sys.solution.get();
78 92597 : sys_vec_header.type = sys_vec_header.vector->type();
79 435235 : 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 342638 : const auto & name = sys.vector_name(vec_num);
84 : mooseAssert(!sys_header.vectors.count(name), "Already inserted");
85 342638 : auto & vec_header = sys_header.vectors[name];
86 342638 : vec_header.name = sys.vector_name(vec_num);
87 342638 : vec_header.projections = sys.vector_preservation(vec_header.name);
88 342638 : vec_header.vector = &sys.get_vector(vec_header.name);
89 342638 : 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 92597 : es_header.systems.emplace(sys.name(), sys_header);
95 92597 : }
96 :
97 : // Setup the positions in each vector for easy access later
98 45777 : std::size_t offset = 0;
99 138374 : for (auto & sys_name_header_pair : es_header.systems)
100 : {
101 92597 : auto & sys_header = sys_name_header_pair.second;
102 527832 : for (auto & vec_name_header_pair : sys_header.vectors)
103 : {
104 435235 : auto & vec_header = vec_name_header_pair.second;
105 869500 : for (const auto & var_name_header_pair : sys_header.variables)
106 : {
107 434265 : const auto & var_header = var_name_header_pair.second;
108 : mooseAssert(!vec_header.variable_offset.count(var_header.name), "Already inserted");
109 434265 : vec_header.variable_offset[var_header.name] = offset;
110 434265 : offset += var_header.size;
111 : }
112 : }
113 : }
114 :
115 45777 : es_header.data_size = offset;
116 :
117 45777 : return es_header;
118 0 : }
119 :
120 : std::vector<const libMesh::DofObject *>
121 60315 : RestartableEquationSystems::orderDofObjects() const
122 : {
123 60315 : std::vector<const libMesh::DofObject *> objects;
124 120630 : auto add = [&objects](const auto begin, const auto end)
125 : {
126 120630 : std::set<const libMesh::DofObject *, libMesh::CompareDofObjectsByID> ordered(begin, end);
127 120630 : objects.insert(objects.end(), ordered.begin(), ordered.end());
128 180945 : };
129 :
130 60315 : const auto & mesh = _es.get_mesh();
131 60315 : add(mesh.local_elements_begin(), mesh.local_elements_end());
132 60315 : add(mesh.local_nodes_begin(), mesh.local_nodes_end());
133 :
134 120630 : return objects;
135 0 : }
136 :
137 : void
138 45777 : RestartableEquationSystems::store(std::ostream & stream) const
139 : {
140 : // Order objects (elements and then nodes) by ID for storing
141 45777 : const auto ordered_objects = orderDofObjects();
142 :
143 : // Store the header (systems, variables, vectors)
144 45777 : EquationSystemsHeader es_header = buildHeader(ordered_objects);
145 45777 : 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 45777 : std::vector<dof_id_type> ordered_objects_ids(ordered_objects.size());
151 9889680 : for (const auto i : index_range(ordered_objects))
152 9843903 : ordered_objects_ids[i] = ordered_objects[i]->id();
153 45777 : dataStore(stream, ordered_objects_ids, nullptr);
154 45777 : }
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 138374 : for (const auto & sys_name_header_pair : es_header.systems)
162 : {
163 92597 : const auto & sys_header = sys_name_header_pair.second;
164 92597 : const auto & sys = _es.get_system(sys_header.name);
165 :
166 : // Store each vector and variable
167 527832 : for (const auto & vec_name_header_pair : sys_header.vectors)
168 : {
169 435235 : const auto & vec_header = vec_name_header_pair.second;
170 435235 : const auto & vec = *vec_header.vector;
171 869500 : for (const auto & var_name_header_pair : sys_header.variables)
172 : {
173 434265 : const auto & var_header = var_name_header_pair.second;
174 434265 : 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 434265 : if (var.type().family != SCALAR)
182 : {
183 : // Store for each component of each element and node
184 82534626 : for (const auto & obj : ordered_objects)
185 124067433 : for (const auto comp : make_range(obj->n_comp(sys.number(), var.number())))
186 : {
187 41958934 : auto val = vec(obj->dof_number(sys.number(), var.number(), comp));
188 41958934 : dataStore(stream, val, nullptr);
189 : }
190 : }
191 : // SCALAR variable on the last rank
192 8138 : else if (_es.processor_id() == _es.n_processors() - 1)
193 : {
194 8027 : const auto & dof_map = sys.get_dof_map();
195 8027 : std::vector<dof_id_type> scalar_dofs;
196 8027 : dof_map.SCALAR_dof_indices(scalar_dofs, var.number());
197 17420 : for (const auto dof : scalar_dofs)
198 : {
199 9393 : auto val = vec(dof);
200 9393 : dataStore(stream, val, nullptr);
201 : }
202 8027 : }
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 45777 : }
221 :
222 : void
223 14538 : RestartableEquationSystems::load(std::istream & stream)
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 14538 : _loaded_header.systems.clear();
229 14538 : dataLoad(stream, _loaded_header, nullptr);
230 :
231 : // Order objects (elements and then node) by ID for storing
232 14538 : _loaded_ordered_objects = orderDofObjects();
233 :
234 : // Clear previously loaded variables to ensure a clean state
235 14538 : _loaded_variables.clear();
236 :
237 : // Sanity check on if we're loading the same thing
238 : {
239 14538 : std::vector<dof_id_type> from_ordered_objects_ids;
240 14538 : dataLoad(stream, from_ordered_objects_ids, nullptr);
241 14538 : if (_loaded_ordered_objects.size() != from_ordered_objects_ids.size())
242 0 : mooseError("RestartableEquationSystems::load(): Number of previously stored elements/nodes (",
243 0 : _loaded_ordered_objects.size(),
244 : ") does not "
245 : "match the current number of elements/nodes (",
246 0 : from_ordered_objects_ids.size(),
247 : ")");
248 3713327 : for (const auto i : index_range(_loaded_ordered_objects))
249 3698789 : if (_loaded_ordered_objects[i]->id() != from_ordered_objects_ids[i])
250 0 : mooseError("RestartableEquationSystems::load(): Id of previously stored element/node (",
251 0 : _loaded_ordered_objects[i]->id(),
252 : ") does not "
253 : "match the current element/node id (",
254 0 : from_ordered_objects_ids[i],
255 : ")");
256 14538 : }
257 :
258 14538 : _loaded_stream_data_begin = static_cast<std::size_t>(stream.tellg());
259 :
260 : // Load everything that we have available at the moment
261 43750 : for (const auto & sys_name_header_pair : _loaded_header.systems)
262 : {
263 29212 : const auto & sys_header = sys_name_header_pair.second;
264 29212 : if (!_es.has_system(sys_header.name))
265 62 : continue;
266 29150 : auto & sys = _es.get_system(sys_header.name);
267 :
268 29150 : bool modified_sys = false;
269 :
270 151520 : for (const auto & vec_name_header_pair : sys_header.vectors)
271 : {
272 122370 : bool modified_vec = false;
273 :
274 122370 : const auto & vec_header = vec_name_header_pair.second;
275 122370 : const bool is_solution = vec_header.name == SystemHeader::system_solution_name;
276 :
277 122370 : if (!is_solution && !sys.have_vector(vec_header.name))
278 : {
279 341 : if (_load_all_vectors)
280 257 : sys.add_vector(vec_header.name, vec_header.projections, vec_header.type);
281 : else
282 84 : continue;
283 : }
284 :
285 122286 : auto & vec = is_solution ? *sys.solution : sys.get_vector(vec_header.name);
286 :
287 242706 : for (const auto & var_name_header_pair : sys_header.variables)
288 : {
289 120420 : const auto & var_header = var_name_header_pair.second;
290 120420 : if (!sys.has_variable(var_header.name))
291 14 : continue;
292 120406 : const auto & var = sys.variable(sys.variable_number(var_header.name));
293 120406 : if (var.type() != var_header.type)
294 0 : continue;
295 :
296 120406 : restore(sys_header, vec_header, var_header, sys, vec, var, stream);
297 120406 : modified_vec = true;
298 : }
299 :
300 122286 : if (modified_vec)
301 : {
302 98374 : vec.close();
303 98374 : modified_sys = true;
304 : }
305 : }
306 :
307 29150 : if (modified_sys)
308 22258 : sys.update();
309 : }
310 :
311 : // Move the stream to the end of our data so that we make RestartableDataReader happy
312 14538 : stream.seekg(_loaded_stream_data_begin + _loaded_header.data_size);
313 14538 : }
314 :
315 : bool
316 0 : RestartableEquationSystems::isVariableRestored(const std::string & system_name,
317 : const std::string & vector_name,
318 : const std::string & variable_name) const
319 : {
320 0 : std::tuple<std::string, std::string, std::string> key(system_name, vector_name, variable_name);
321 0 : return _loaded_variables.count(key);
322 0 : }
323 :
324 : void
325 120406 : RestartableEquationSystems::restore(const SystemHeader & from_sys_header,
326 : const VectorHeader & from_vec_header,
327 : const VariableHeader & from_var_header,
328 : const libMesh::System & to_sys,
329 : libMesh::NumericVector<libMesh::Number> & to_vec,
330 : const libMesh::Variable & to_var,
331 : std::istream & stream)
332 : {
333 : #ifndef NDEBUG
334 : const auto sys_it = _loaded_header.systems.find(from_sys_header.name);
335 : mooseAssert(sys_it != _loaded_header.systems.end(), "System does not exist");
336 : const auto & sys_header = sys_it->second;
337 : mooseAssert(sys_header == from_sys_header, "Not my system");
338 : const auto vec_it = sys_header.vectors.find(from_vec_header.name);
339 : mooseAssert(vec_it != sys_header.vectors.end(), "Vector does not exist");
340 : const auto & vec_header = vec_it->second;
341 : mooseAssert(vec_header == from_vec_header, "Not my vector");
342 : const auto var_it = sys_header.variables.find(from_var_header.name);
343 : mooseAssert(var_it != sys_header.variables.end(), "Variable does not exist");
344 : const auto & var_header = var_it->second;
345 : mooseAssert(var_header == from_var_header, "Not my variable");
346 : mooseAssert(!isVariableRestored(from_sys_header.name, from_vec_header.name, from_var_header.name),
347 : "Variable already restored");
348 : #endif
349 :
350 : const auto error =
351 0 : [&from_sys_header, &from_vec_header, &from_var_header, &to_sys, &to_var](auto... args)
352 : {
353 0 : mooseError("An error occured while restoring a system:\n",
354 : args...,
355 : "\n\nFrom system: ",
356 0 : from_sys_header.name,
357 : "\nFrom vector: ",
358 0 : from_vec_header.name,
359 : "\nFrom variable: ",
360 0 : from_var_header.name,
361 : "\nTo system: ",
362 0 : to_sys.name(),
363 : "\nTo variable: ",
364 0 : to_var.name());
365 120406 : };
366 :
367 120406 : if (from_var_header.type != to_var.type())
368 0 : error("Cannot restore to a variable of a different type");
369 :
370 120406 : const auto offset = from_vec_header.variable_offset.at(from_var_header.name);
371 120406 : stream.seekg(_loaded_stream_data_begin + offset);
372 :
373 : // Non-SCALAR variable
374 120406 : if (to_var.type().family != SCALAR)
375 : {
376 27581028 : for (const auto & obj : _loaded_ordered_objects)
377 41693776 : for (const auto comp : make_range(obj->n_comp(to_sys.number(), to_var.number())))
378 : {
379 : Real val;
380 14232453 : dataLoad(stream, val, nullptr);
381 14232453 : to_vec.set(obj->dof_number(to_sys.number(), to_var.number(), comp), val);
382 : }
383 : }
384 : // SCALAR variable on the last rank
385 701 : else if (_es.processor_id() == _es.n_processors() - 1)
386 : {
387 698 : const auto & dof_map = to_sys.get_dof_map();
388 698 : std::vector<dof_id_type> scalar_dofs;
389 698 : dof_map.SCALAR_dof_indices(scalar_dofs, to_var.number());
390 1639 : for (const auto dof : scalar_dofs)
391 : {
392 : Real val;
393 941 : dataLoad(stream, val, nullptr);
394 941 : to_vec.set(dof, val);
395 : }
396 698 : }
397 :
398 : // insert into the member variable
399 : std::tuple<std::string, std::string, std::string> _loaded_variable = {
400 120406 : from_sys_header.name, from_vec_header.name, from_var_header.name};
401 :
402 120406 : _loaded_variables.insert(_loaded_variable);
403 :
404 : mooseAssert(isVariableRestored(from_sys_header.name, from_vec_header.name, from_var_header.name),
405 : "Variable not marked as restored");
406 120406 : }
407 :
408 : void
409 45777 : dataStore(std::ostream & stream, RestartableEquationSystems & res, void *)
410 : {
411 45777 : res.store(stream);
412 45777 : }
413 :
414 : void
415 14538 : dataLoad(std::istream & stream, RestartableEquationSystems & res, void *)
416 : {
417 14538 : res.load(stream);
418 14538 : }
419 :
420 : void
421 45777 : dataStore(std::ostream & stream, RestartableEquationSystems::EquationSystemsHeader & header, void *)
422 : {
423 45777 : dataStore(stream, header.systems, nullptr);
424 45777 : dataStore(stream, header.data_size, nullptr);
425 45777 : }
426 :
427 : void
428 14538 : dataLoad(std::istream & stream, RestartableEquationSystems::EquationSystemsHeader & header, void *)
429 : {
430 14538 : dataLoad(stream, header.systems, nullptr);
431 14538 : dataLoad(stream, header.data_size, nullptr);
432 14538 : }
433 :
434 : void
435 92597 : dataStore(std::ostream & stream, RestartableEquationSystems::SystemHeader & header, void *)
436 : {
437 92597 : dataStore(stream, header.name, nullptr);
438 92597 : dataStore(stream, header.type, nullptr);
439 92597 : dataStore(stream, header.variables, nullptr);
440 92597 : dataStore(stream, header.vectors, nullptr);
441 92597 : }
442 :
443 : void
444 29212 : dataLoad(std::istream & stream, RestartableEquationSystems::SystemHeader & header, void *)
445 : {
446 29212 : dataLoad(stream, header.name, nullptr);
447 29212 : dataLoad(stream, header.type, nullptr);
448 29212 : dataLoad(stream, header.variables, nullptr);
449 29212 : dataLoad(stream, header.vectors, nullptr);
450 29212 : }
451 :
452 : void
453 92258 : dataStore(std::ostream & stream, RestartableEquationSystems::VariableHeader & header, void *)
454 : {
455 92258 : dataStore(stream, header.name, nullptr);
456 92258 : dataStore(stream, header.type, nullptr);
457 92258 : }
458 : void
459 29544 : dataLoad(std::istream & stream, RestartableEquationSystems::VariableHeader & header, void *)
460 : {
461 29544 : dataLoad(stream, header.name, nullptr);
462 29544 : dataLoad(stream, header.type, nullptr);
463 29544 : }
464 :
465 : void
466 435235 : dataStore(std::ostream & stream, RestartableEquationSystems::VectorHeader & header, void *)
467 : {
468 435235 : dataStore(stream, header.name, nullptr);
469 435235 : dataStore(stream, header.projections, nullptr);
470 435235 : dataStore(stream, header.type, nullptr);
471 435235 : dataStore(stream, header.variable_offset, nullptr);
472 435235 : }
473 : void
474 122498 : dataLoad(std::istream & stream, RestartableEquationSystems::VectorHeader & header, void *)
475 : {
476 122498 : dataLoad(stream, header.name, nullptr);
477 122498 : dataLoad(stream, header.projections, nullptr);
478 122498 : dataLoad(stream, header.type, nullptr);
479 122498 : dataLoad(stream, header.variable_offset, nullptr);
480 122498 : }
481 :
482 : void
483 24 : to_json(nlohmann::json & json, const RestartableEquationSystems & res)
484 : {
485 :
486 24 : nlohmann::json loaded_vars = nlohmann::json::array();
487 :
488 240 : for (const auto & [system, vector, variable] : res.getLoadedVariables())
489 : {
490 2160 : loaded_vars.push_back({{"system", system}, {"vector", vector}, {"variable", variable}});
491 : }
492 :
493 24 : json["loaded_variables"] = loaded_vars;
494 1752 : }
|