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