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