https://mooseframework.inl.gov
DataIO.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 
10 #include "DenseMatrix.h"
11 #include "DataIO.h"
12 #include "MooseMesh.h"
13 #include "FEProblemBase.h"
14 #include "NonlinearSystemBase.h"
15 
16 #include "libmesh/vector_value.h"
17 #include "libmesh/tensor_value.h"
18 
19 #include "libmesh/elem.h"
20 #include "libmesh/petsc_vector.h"
21 #include "libmesh/enum_solver_package.h"
22 #include "libmesh/petsc_solver_exception.h"
23 
24 using namespace libMesh;
25 
26 template <>
27 void
28 dataStore(std::ostream & stream, Real & v, void * /*context*/)
29 {
30  stream.write((char *)&v, sizeof(v));
31 }
32 
33 template <>
34 void
35 dataStore(std::ostream & stream, std::string & v, void * /*context*/)
36 {
37  // Write the size of the string
38  unsigned int size = v.size();
39  stream.write((char *)&size, sizeof(size));
40 
41  // Write the string (Do not store the null byte)
42  stream.write(v.c_str(), sizeof(char) * size);
43 }
44 
45 template <>
46 void
47 dataStore(std::ostream & stream, VariableName & v, void * context)
48 {
49  auto & name = static_cast<std::string &>(v);
50  dataStore(stream, name, context);
51 }
52 
53 template <>
54 void
55 dataStore(std::ostream & stream, UserObjectName & v, void * context)
56 {
57  auto & name = static_cast<std::string &>(v);
58  dataStore(stream, name, context);
59 }
60 
61 template <>
62 void
63 dataStore(std::ostream & stream, bool & v, void * /*context*/)
64 {
65  stream.write((char *)&v, sizeof(v));
66 }
67 
68 template <>
69 void
70 dataStore(std::ostream & stream, std::vector<bool> & v, void * context)
71 {
72  for (bool b : v)
73  dataStore(stream, b, context);
74 }
75 
76 template <>
77 void
78 dataStore(std::ostream & stream, RankTwoTensor & rtt, void * context)
79 {
80  dataStore(stream, rtt._coords, context);
81 }
82 
83 template <>
84 void
85 dataStore(std::ostream & stream, RankThreeTensor & rtht, void * context)
86 {
87  dataStore(stream, rtht._vals, context);
88 }
89 
90 template <>
91 void
92 dataStore(std::ostream & stream, RankFourTensor & rft, void * context)
93 {
94  dataStore(stream, rft._vals, context);
95 }
96 
97 template <>
98 void
99 dataStore(std::ostream & stream, ADReal & dn, void * context)
100 {
101  dataStore(stream, dn.value(), context);
102 
103  if (ADReal::do_derivatives)
104  {
105  auto & derivatives = dn.derivatives();
106  std::size_t size = derivatives.size();
107  dataStore(stream, size, context);
108  for (MooseIndex(size) i = 0; i < size; ++i)
109  {
110  dataStore(stream, derivatives.raw_index(i), context);
111  dataStore(stream, derivatives.raw_at(i), context);
112  }
113  }
114 }
115 
116 template <>
117 void
118 dataStore(std::ostream & stream, const Elem *& e, void * context)
119 {
120  // TODO: Write out the unique ID of this elem
122 
123  if (e)
124  {
125  id = e->id();
127  mooseError("Can't output Elems with invalid ids!");
128  }
129 
130  storeHelper(stream, id, context);
131 }
132 
133 template <>
134 void
135 dataStore(std::ostream & stream, const Node *& n, void * context)
136 {
137  // TODO: Write out the unique ID of this node
139 
140  if (n)
141  {
142  id = n->id();
144  mooseError("Can't output Nodes with invalid ids!");
145  }
146 
147  storeHelper(stream, id, context);
148 }
149 
150 template <>
151 void
152 dataStore(std::ostream & stream, Elem *& e, void * context)
153 {
154  // TODO: Write out the unique ID of this elem
156 
157  if (e)
158  {
159  id = e->id();
161  mooseError("Can't output Elems with invalid ids!");
162  }
163 
164  storeHelper(stream, id, context);
165 }
166 
167 template <>
168 void
169 dataStore(std::ostream & stream, Node *& n, void * context)
170 {
171  // TODO: Write out the unique ID of this node
173 
174  if (n)
175  {
176  id = n->id();
178  mooseError("Can't output Nodes with invalid ids!");
179  }
180 
181  storeHelper(stream, id, context);
182 }
183 
184 template <>
185 void
186 dataStore(std::ostream & stream, std::stringstream & s, void * /* context */)
187 {
188  const std::string & s_str = s.str();
189 
190  size_t s_size = s_str.size();
191  stream.write((char *)&s_size, sizeof(s_size));
192 
193  stream.write(s_str.c_str(), sizeof(char) * (s_str.size()));
194 }
195 
196 template <typename T>
197 void
198 dataStore(std::ostream & stream, TensorValue<T> & v, void * context)
199 {
200  for (const auto i : make_range(Moose::dim))
201  for (const auto j : make_range(Moose::dim))
202  {
203  T r = v(i, j);
204  dataStore(stream, r, context);
205  }
206 }
207 
208 template void dataStore(std::ostream & stream, TensorValue<Real> & v, void * context);
209 template void dataStore(std::ostream & stream, TensorValue<ADReal> & v, void * context);
210 
211 template <typename T>
212 void
213 dataStore(std::ostream & stream, DenseMatrix<T> & v, void * context)
214 {
215  unsigned int m = v.m();
216  unsigned int n = v.n();
217  stream.write((char *)&m, sizeof(m));
218  stream.write((char *)&n, sizeof(n));
219  for (unsigned int i = 0; i < m; i++)
220  for (unsigned int j = 0; j < n; j++)
221  {
222  T r = v(i, j);
223  dataStore(stream, r, context);
224  }
225 }
226 
227 template void dataStore(std::ostream & stream, DenseMatrix<Real> & v, void * context);
228 template void dataStore(std::ostream & stream, DenseMatrix<ADReal> & v, void * context);
229 
230 template <typename T>
231 void
232 dataStore(std::ostream & stream, VectorValue<T> & v, void * context)
233 {
234  // Obviously if someone loads data with different LIBMESH_DIM than was used for saving them, it
235  // won't work.
236  for (const auto i : make_range(Moose::dim))
237  {
238  T r = v(i);
239  dataStore(stream, r, context);
240  }
241 }
242 
243 template void dataStore(std::ostream & stream, VectorValue<Real> & v, void * context);
244 template void dataStore(std::ostream & stream, VectorValue<ADReal> & v, void * context);
245 
246 void
247 dataStore(std::ostream & stream, Point & p, void * context)
248 {
249  for (const auto i : make_range(Moose::dim))
250  {
251  Real r = p(i);
252  dataStore(stream, r, context);
253  }
254 }
255 
256 template <>
257 void
258 dataStore(std::ostream & stream, libMesh::Parameters & p, void * context)
259 {
260  // First store the size of the map
261  unsigned int size = p.n_parameters();
262  stream.write((char *)&size, sizeof(size));
263 
264  auto it = p.begin();
265  auto end = p.end();
266 
267  for (; it != end; ++it)
268  {
269  auto & key = const_cast<std::string &>(it->first);
270  auto type = it->second->type();
271 
272  storeHelper(stream, key, context);
273  storeHelper(stream, type, context);
274 
275 #define storescalar(ptype) \
276  else if (it->second->type() == demangle(typeid(ptype).name())) storeHelper( \
277  stream, \
278  (dynamic_cast<libMesh::Parameters::Parameter<ptype> *>(MooseUtils::get(it->second)))->get(), \
279  context)
280 
281  if (false)
282  ;
283  storescalar(Real);
284  storescalar(short);
285  storescalar(int);
286  storescalar(long);
287  storescalar(unsigned short);
288  storescalar(unsigned int);
289  storescalar(unsigned long);
290 
291 #undef storescalar
292  }
293 }
294 
295 template <>
296 void
297 dataStore(std::ostream & stream,
298  std::unique_ptr<libMesh::NumericVector<Number>> & v,
299  void * context)
300 {
301  // Classes may declare unique pointers to vectors as restartable data and never actually create
302  // vector instances. This happens for example in the `TimeIntegrator` class where subvector
303  // instances are only created if multiple time integrators are present
304  bool have_vector = v.get();
305  dataStore(stream, have_vector, context);
306  if (!have_vector)
307  return;
308 
309  mooseAssert(context, "Needs a context of the communicator");
310  const auto & comm = *static_cast<const libMesh::Parallel::Communicator *>(context);
311  mooseAssert(&comm == &v->comm(), "Inconsistent communicator");
312 
313  if (v->type() == GHOSTED)
314  mooseError("Cannot store ghosted numeric vectors");
315 
316  // Store the communicator size for sanity checking later
317  unsigned int comm_size = comm.size();
318  dataStore(stream, comm_size, nullptr);
319 
320  // Store the solver package so that we know what vector type to construct
321  libMesh::SolverPackage solver_package;
322  if (dynamic_cast<libMesh::PetscVector<Number> *>(v.get()))
323  solver_package = PETSC_SOLVERS;
324  else
325  mooseError("Can only store unique_ptrs of PetscVectors");
326  int solver_package_int = solver_package;
327  dataStore(stream, solver_package_int, nullptr);
328 
329  // Store the sizes
330  dof_id_type size = v->size();
331  dataStore(stream, size, nullptr);
332  dof_id_type local_size = v->local_size();
333  dataStore(stream, local_size, nullptr);
334 
335  // Store the vector itself
336  dataStore(stream, *v, nullptr);
337 }
338 
339 // global load functions
340 
341 template <>
342 void
343 dataLoad(std::istream & stream, Real & v, void * /*context*/)
344 {
345  stream.read((char *)&v, sizeof(v));
346 }
347 
348 template <>
349 void
350 dataLoad(std::istream & stream, std::string & v, void * /*context*/)
351 {
352  // Read the size of the string
353  unsigned int size = 0;
354  stream.read((char *)&size, sizeof(size));
355 
356  // Resize the string data
357  v.resize(size);
358 
359  // Read the string
360  stream.read(&v[0], sizeof(char) * size);
361 }
362 
363 template <>
364 void
365 dataLoad(std::istream & stream, VariableName & v, void * context)
366 {
367  auto & name = static_cast<std::string &>(v);
368  dataLoad(stream, name, context);
369 }
370 
371 template <>
372 void
373 dataLoad(std::istream & stream, UserObjectName & v, void * context)
374 {
375  auto & name = static_cast<std::string &>(v);
376  dataLoad(stream, name, context);
377 }
378 
379 template <>
380 void
381 dataLoad(std::istream & stream, bool & v, void * /*context*/)
382 {
383  stream.read((char *)&v, sizeof(v));
384 }
385 
386 template <>
387 void
388 dataLoad(std::istream & stream, std::vector<bool> & v, void * context)
389 {
390  for (bool b : v)
391  dataLoad(stream, b, context);
392 }
393 
394 template <>
395 void
396 dataLoad(std::istream & stream, ADReal & dn, void * context)
397 {
398  dataLoad(stream, dn.value(), context);
399 
400  if (ADReal::do_derivatives)
401  {
402  auto & derivatives = dn.derivatives();
403  std::size_t size = 0;
404  stream.read((char *)&size, sizeof(size));
405  derivatives.resize(size);
406 
407  for (MooseIndex(derivatives) i = 0; i < derivatives.size(); ++i)
408  {
409  dataLoad(stream, derivatives.raw_index(i), context);
410  dataLoad(stream, derivatives.raw_at(i), context);
411  }
412  }
413 }
414 
415 template <>
416 void
417 dataLoad(std::istream & stream, const Elem *& e, void * context)
418 {
419  if (!context)
420  mooseError("Can only load Elem objects using a MooseMesh context!");
421 
422  MooseMesh * mesh = static_cast<MooseMesh *>(context);
423 
424  // TODO: Write out the unique ID of this element
426 
427  loadHelper(stream, id, context);
428 
430  e = mesh->elemPtr(id);
431  else
432  e = NULL;
433 }
434 
435 template <>
436 void
437 dataLoad(std::istream & stream, const Node *& n, void * context)
438 {
439  if (!context)
440  mooseError("Can only load Node objects using a MooseMesh context!");
441 
442  MooseMesh * mesh = static_cast<MooseMesh *>(context);
443 
444  // TODO: Write out the unique ID of this nodeent
446 
447  loadHelper(stream, id, context);
448 
450  n = mesh->nodePtr(id);
451  else
452  n = NULL;
453 }
454 
455 template <>
456 void
457 dataLoad(std::istream & stream, Elem *& e, void * context)
458 {
459  if (!context)
460  mooseError("Can only load Elem objects using a MooseMesh context!");
461 
462  MooseMesh * mesh = static_cast<MooseMesh *>(context);
463 
464  // TODO: Write out the unique ID of this element
466 
467  loadHelper(stream, id, context);
468 
470  e = mesh->elemPtr(id);
471  else
472  e = NULL;
473 }
474 
475 template <>
476 void
477 dataLoad(std::istream & stream, Node *& n, void * context)
478 {
479  if (!context)
480  mooseError("Can only load Node objects using a MooseMesh context!");
481 
482  MooseMesh * mesh = static_cast<MooseMesh *>(context);
483 
484  // TODO: Write out the unique ID of this nodeent
486 
487  loadHelper(stream, id, context);
488 
490  n = mesh->nodePtr(id);
491  else
492  n = NULL;
493 }
494 
495 template <>
496 void
497 dataLoad(std::istream & stream, std::stringstream & s, void * /* context */)
498 {
499  size_t s_size = 0;
500  stream.read((char *)&s_size, sizeof(s_size));
501 
502  std::unique_ptr<char[]> s_s = std::make_unique<char[]>(s_size);
503  stream.read(s_s.get(), s_size);
504 
505  // Clear the stringstream before loading new data into it.
506  s.str(std::string());
507  s.write(s_s.get(), s_size);
508 }
509 
510 template <typename T>
511 void
512 dataLoad(std::istream & stream, TensorValue<T> & v, void * context)
513 {
514  // Obviously if someone loads data with different LIBMESH_DIM than was used for saving them, it
515  // won't work.
516  for (const auto i : make_range(Moose::dim))
517  for (const auto j : make_range(Moose::dim))
518  {
519  T r = 0;
520  dataLoad(stream, r, context);
521  v(i, j) = r;
522  }
523 }
524 
525 template void dataLoad(std::istream & stream, TensorValue<Real> & v, void * context);
526 template void dataLoad(std::istream & stream, TensorValue<ADReal> & v, void * context);
527 
528 template <typename T>
529 void
530 dataLoad(std::istream & stream, DenseMatrix<T> & v, void * context)
531 {
532  unsigned int m = 0, n = 0;
533  stream.read((char *)&m, sizeof(m));
534  stream.read((char *)&n, sizeof(n));
535  v.resize(m, n);
536  for (unsigned int i = 0; i < m; i++)
537  for (unsigned int j = 0; j < n; j++)
538  {
539  T r = 0;
540  dataLoad(stream, r, context);
541  v(i, j) = r;
542  }
543 }
544 
545 template void dataLoad(std::istream & stream, DenseMatrix<Real> & v, void * context);
546 template void dataLoad(std::istream & stream, DenseMatrix<ADReal> & v, void * context);
547 
548 template <typename T>
549 void
550 dataLoad(std::istream & stream, VectorValue<T> & v, void * context)
551 {
552  // Obviously if someone loads data with different LIBMESH_DIM than was used for saving them, it
553  // won't work.
554  for (const auto i : make_range(Moose::dim))
555  {
556  T r = 0;
557  dataLoad(stream, r, context);
558  v(i) = r;
559  }
560 }
561 
562 template void dataLoad(std::istream & stream, VectorValue<Real> & v, void * context);
563 template void dataLoad(std::istream & stream, VectorValue<ADReal> & v, void * context);
564 
565 void
566 dataLoad(std::istream & stream, Point & p, void * context)
567 {
568  for (const auto i : make_range(Moose::dim))
569  {
570  Real r = 0;
571  dataLoad(stream, r, context);
572  p(i) = r;
573  }
574 }
575 
576 template <>
577 void
578 dataLoad(std::istream & stream, libMesh::Parameters & p, void * context)
579 {
580  p.clear();
581 
582  // First read the size of the map
583  unsigned int size = 0;
584  stream.read((char *)&size, sizeof(size));
585 
586  for (unsigned int i = 0; i < size; i++)
587  {
588  std::string key, type;
589  loadHelper(stream, key, context);
590  loadHelper(stream, type, context);
591 
592 #define loadscalar(ptype) \
593  else if (type == demangle(typeid(ptype).name())) do \
594  { \
595  ptype & value = p.set<ptype>(key); \
596  loadHelper(stream, value, context); \
597  } \
598  while (0)
599 
600  if (false)
601  ;
602  loadscalar(Real);
603  loadscalar(short);
604  loadscalar(int);
605  loadscalar(long);
606  loadscalar(unsigned short);
607  loadscalar(unsigned int);
608  loadscalar(unsigned long);
609 
610 #undef loadscalar
611  }
612 }
613 
614 template <>
615 void
616 dataLoad(std::istream & stream, std::unique_ptr<libMesh::NumericVector<Number>> & v, void * context)
617 {
618  bool have_vector;
619  dataLoad(stream, have_vector, context);
620 
621  if (!have_vector)
622  return;
623 
624  mooseAssert(context, "Needs a context of the communicator");
625  const auto & comm = *static_cast<const libMesh::Parallel::Communicator *>(context);
626  if (v)
627  mooseAssert(&comm == &v->comm(), "Inconsistent communicator");
628 
629  // Load the communicator size for consistency checks
630  unsigned int comm_size;
631  dataLoad(stream, comm_size, nullptr);
632  mooseAssert(comm.size() == comm_size, "Inconsistent communicator size");
633 
634  // Load the solver package to build the vector
635  int solver_package_int;
636  dataLoad(stream, solver_package_int, nullptr);
637  libMesh::SolverPackage solver_package = static_cast<libMesh::SolverPackage>(solver_package_int);
638 
639  // Load the sizes
640  dof_id_type size, local_size;
641  dataLoad(stream, size, nullptr);
642  dataLoad(stream, local_size, nullptr);
643 
644  // Construct the vector given the type, only if we need to. v could be non-null here
645  // if we're advancing back and loading a backup
646  if (!v)
647  {
648  v = NumericVector<Number>::build(comm, solver_package);
649  v->init(size, local_size);
650  }
651  else
652  mooseAssert(v->type() != GHOSTED, "Cannot be ghosted");
653 
654  // Make sure that the sizes are consistent; this will happen if we're calling this
655  // on a vector that has already been loaded previously
656  mooseAssert(v->size() == size, "Inconsistent size");
657  mooseAssert(v->local_size() == local_size, "Inconsistent local size");
658 
659  // Now that we have an initialized vector, fill the entries
660  dataLoad(stream, *v, nullptr);
661 }
662 
663 template <>
664 void
665 dataLoad(std::istream & stream, Vec & v, void * context)
666 {
667  PetscInt local_size;
668  LibmeshPetscCallA(PETSC_COMM_WORLD, VecGetLocalSize(v, &local_size));
669  PetscScalar * array;
670  LibmeshPetscCallA(PETSC_COMM_WORLD, VecGetArray(v, &array));
671  for (PetscInt i = 0; i < local_size; i++)
672  dataLoad(stream, array[i], context);
673 
674  LibmeshPetscCallA(PETSC_COMM_WORLD, VecRestoreArray(v, &array));
675 }
676 
677 template <>
678 void
679 dataStore(std::ostream & stream, Vec & v, void * context)
680 {
681  PetscInt local_size;
682  LibmeshPetscCallA(PETSC_COMM_WORLD, VecGetLocalSize(v, &local_size));
683  PetscScalar * array;
684  LibmeshPetscCallA(PETSC_COMM_WORLD, VecGetArray(v, &array));
685  for (PetscInt i = 0; i < local_size; i++)
686  dataStore(stream, array[i], context);
687 
688  LibmeshPetscCallA(PETSC_COMM_WORLD, VecRestoreArray(v, &array));
689 }
std::string name(const ElemQuality q)
RankFourTensorTempl is designed to handle any N-dimensional fourth order tensor, C.
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:323
MeshBase & mesh
static constexpr std::size_t dim
This is the dimension of all vector and tensor datastructures used in MOOSE.
Definition: Moose.h:162
unsigned int m() const
The following methods are specializations for using the libMesh::Parallel::packed_range_* routines fo...
T _coords[LIBMESH_DIM *LIBMESH_DIM]
DualNumber< Real, DNDerivativeType, true > ADReal
Definition: ADRealForward.h:42
RankThreeTensor is designed to handle any N-dimensional third order tensor, r.
void storeHelper(std::ostream &stream, P &data, void *context)
Scalar helper routine.
Definition: DataIO.h:918
dof_id_type id() const
static constexpr dof_id_type invalid_id
void dataLoad(std::istream &stream, Real &v, void *)
Definition: DataIO.C:343
MooseMesh wraps a libMesh::Mesh object and enhances its capabilities by caching additional data and s...
Definition: MooseMesh.h:92
T _vals[N3]
The values of the rank-three tensor stored by index=((i * LIBMESH_DIM + j) * LIBMESH_DIM + k) ...
T _vals[N4]
The values of the rank-four tensor stored by index=(((i * LIBMESH_DIM + j) * LIBMESH_DIM + k) * LIBME...
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
virtual void clear()
void resize(const unsigned int new_m, const unsigned int new_n)
IntRange< T > make_range(T beg, T end)
static std::unique_ptr< NumericVector< T > > build(const Parallel::Communicator &comm, SolverPackage solver_package=libMesh::default_solver_package(), ParallelType parallel_type=AUTOMATIC)
std::size_t n_parameters() const
unsigned int n() const
void loadHelper(std::istream &stream, P &data, void *context)
Scalar helper routine.
Definition: DataIO.h:1010
void dataStore(std::ostream &stream, Real &v, void *)
Definition: DataIO.C:28
uint8_t dof_id_type