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