DataIO
The DataIO.h/.C files contain the declaration and definitions for MOOSE's templated dataLoad/dataStore
methods. These methods are scattered around the framework, modules and user applications and are used to store stateful information that cannot be recalculated during a restore operation. These methods enable MOOSE's checkpointing and restarting operations which enable several key capabilities in the MOOSE framework including:
Checkpointing -> the ability to terminate an application and restart it where you left off (useful for batch cluster systems).
Picard Iteration -> The ability to converge a "tightly" coupled multiApp simulation.
Restart -> the ability to save stateful data for a restart type simulation when using checkpoint format
What is stateful data?
Stateful data is any value, container of values, or complex data structure that cannot be recomputed from other available information such as coupled values or field variables. Additionally, it's not any data that is not directly owned by your object.
Here are a couple of examples to consider before defining a dataLoad/dataStore routine:
If you have an object that produces a value based on an "old" value of a coupled variable, your object does not contain any stateful data because it is a simple calculation based on a piece of information not owned by your object. No action is necessary for your object to be "restartable".
If your object has a data structure consisting of a vector of pairs of IDs and Real numbers that are computed from a Material property, your object does not contain any stateful data and no action is necessary for your object to be "restartable".
If your object has a simple Boolean used to indicate whether or not you have calculated some quantity before, that you set when you run some routine. Your object does contain stateful information since the state of that value depends on internal logic in your object. For this scenario, you will need to ask Moose to store your Boolean as "restartableData". See declareRestartableData.
If your object contains a dataStructure of some custom type that you produce internally and retrieve existing values from over the coarse of the simulation, you have a stateful data and may need to define the dataLoad and dataStore functions in your object. See declareRestartableData, and dataStore/dataLoad routines.
declareRestartableData
The declareRestartableData method is used to tell MOOSE that you would like to save some part of your object in a Backup object. This method is templated and declared here:
protected:
/**
* Declare a piece of data as "restartable" and initialize it.
* This means that in the event of a restart this piece of data
* will be restored back to its previous value.
*
* NOTE: This returns a _reference_! Make sure you store it in a _reference_!
*
* @param data_name The name of the data (usually just use the same name as the member variable)
* @param args Arguments to forward to the constructor of the data
*/
template <typename T, typename... Args>
T & declareRestartableData(const std::string & data_name, Args &&... args);
(moose/framework/include/restart/Restartable.h)This method is templated, so MOOSE will return a reference to the type that you request and manage the data storage for you. For all built-in types and combinations of containers and built-in types. This is all that needs to be done. If your type or your container of types is custom, you will have to define the dataLoad and dataStore routines to tell MOOSE how to serialize your new type.
dataStore/dataLoad routines
If any object has requested a restartable piece of data that contains or is a custom type, both the dataStore and dataLoad will need to be defined. These functions describe how to serialize a custom type.
The declarations for the two methods that may need to be specialized for your application take on a form similar to this:
// *************** Global Load Declarations *****************
template <typename T>
inline void
dataLoad(std::istream & stream, T & v, void * /*context*/)
{
stream.read((char *)&v, sizeof(v));
mooseAssert(!stream.bad(), "Failed to load");
}
(moose/framework/include/restart/DataIO.h)// *************** Global Store Declarations *****************
template <typename T>
inline void
dataStore(std::ostream & stream, T & v, void * /*context*/)
{
#ifdef LIBMESH_HAVE_CXX11_TYPE_TRAITS
static_assert(std::is_polymorphic<T>::value == false,
"Cannot serialize a class that has virtual "
"members!\nWrite a custom dataStore() "
"template specialization!\n\n");
static_assert(std::is_trivially_copyable<T>::value,
"Cannot serialize a class that is not trivially copyable!\nWrite a custom "
"dataStore() template specialization!\n\n");
#endif
(moose/framework/include/restart/DataIO.h)Example
Typically, the serialization routine can be defined in terms of serializing the individual fields in your custom type. For example. If you had a class Foo
that contained a few plain old data types, you'd just define the load and store terms in terms of the combination of those POD types in order.
class Foo
{
int bar;
std::string baz;
std::vector<unsigned int> qux;
};
// Definition
template <>
void
dataStore(std::ostream & stream, Foo & foo, void * context)
{
// Defined in terms of the simple types that MOOSE already knows how to store
storeHelper(stream, foo.bar, context);
storeHelper(stream, foo.baz, context);
storeHelper(stream, foo.qux, context);
}
template <>
void
dataLoad(std::istream & stream, Foo & foo, void * context)
{
// Defined in terms of the simple types that MOOSE already knows how to read.
// Note the order of the calls, they should match the dataStore routine since each
// type is being read from the stream.
loadHelper(stream, foo.bar, context);
loadHelper(stream, foo.baz, context);
loadHelper(stream, foo.qux, context);
}
(moose/framework/include/restart/Restartable.h)
// This file is part of the MOOSE framework
// https://www.mooseframework.org
//
// All rights reserved, see COPYRIGHT for full restrictions
// https://github.com/idaholab/moose/blob/master/COPYRIGHT
//
// Licensed under LGPL 2.1, please see LICENSE for details
// https://www.gnu.org/licenses/lgpl-2.1.html
#pragma once
// MOOSE includes
#include "MooseTypes.h"
#include "RestartableData.h"
// Forward declarations
class PostprocessorData;
class SubProblem;
class InputParameters;
class MooseObject;
class MooseApp;
class MooseMesh;
/**
* A class for creating restricted objects
* \see BlockRestartable BoundaryRestartable
*/
class Restartable
{
public:
/**
* Wrapper class for restartable data that is "managed.'
*
* Managed here means that the destruction of the data
* is managed by the reciever and not the app.
*
* When this wrapper is destructed, the underlying
* restartable data is also destructed. This allows for
* proper construction ordered destruction.
*/
template <typename T>
class ManagedValue
{
public:
ManagedValue<T>(RestartableData<T> & value) : _value(value) {}
/**
* Destructor.
*
* Destructs the managed restartable data.
*/
~ManagedValue<T>() { _value.reset(); }
/**
* Get the restartable value.
*/
///@{
const T & get() const { return _value.get(); }
T & set() { return _value.set(); }
///@}
private:
/// The underlying data
RestartableData<T> & _value;
};
/**
* Class constructor
*
* @param moose_object The MooseObject that this interface is being implemented on.
* @param system_name The name of the MOOSE system. ie "Kernel", "BCs", etc. Should roughly
* correspond to the section in the input file so errors are easy to understand.
*
* This method will forward the thread id if it exists in the moose_object parameters. Delegates
* to the "MooseApp &" constructor.
*/
Restartable(const MooseObject * moose_object, const std::string & system_name);
/**
* Class constructor
*
* Similar to the other class constructor but also accepts an individual thread ID. If this
* method is used, no thread ID in the parameters object is used. Delegates to the "MooseApp &"
* constructor.
*/
Restartable(const MooseObject * moose_object, const std::string & system_name, THREAD_ID tid);
/**
* This class constructor is used for non-Moose-based objects like interfaces. A name for the
* storage as well as a system name must be passed in along with the thread ID explicitly.
* @param moose_app Reference to the application
* @param name The name which is used when constructing the full-names of the restartable data.
* It is used with the following logic: `system_name/name/data_name`.
* (e.g. UserObjects/diffusion_kernel/coefficient). In most of the cases this is the
* name of the moose object.
* @param system_name The name of the system where this object belongs to.
* @param tid The thread ID.
* @param read_only Switch to restrict the data for read-only.
* @param metaname The name of the datamap where the restartable objects should be registered to.
*/
Restartable(MooseApp & moose_app,
const std::string & name,
const std::string & system_name,
THREAD_ID tid,
const bool read_only = false,
const RestartableDataMapName & metaname = "");
protected:
/**
* Declare a piece of data as "restartable" and initialize it.
* This means that in the event of a restart this piece of data
* will be restored back to its previous value.
*
* NOTE: This returns a _reference_! Make sure you store it in a _reference_!
*
* @param data_name The name of the data (usually just use the same name as the member variable)
* @param args Arguments to forward to the constructor of the data
*/
template <typename T, typename... Args>
T & declareRestartableData(const std::string & data_name, Args &&... args);
/**
* Declares a piece of "managed" restartable data and initialize it.
*
* Here, "managed" restartable data means that the caller can destruct this data
* upon destruction of the return value of this method. Therefore, this
* ManagedValue<T> wrapper should survive after the final calls to dataStore()
* for it. That is... at the very end.
*
* This is needed for objects whose destruction ordering is important, and
* enables natural c++ destruction in reverse construction order of the object
* that declares it.
*
* See delcareRestartableData and declareRestartableDataWithContext for more information.
*/
template <typename T, typename... Args>
ManagedValue<T> declareManagedRestartableDataWithContext(const std::string & data_name,
void * context,
Args &&... args);
/**
* Declare a piece of data as "restartable" and initialize it
* Similar to `declareRestartableData` but returns a const reference to the object.
* Forwarded arguments are not allowed in this case because we assume that the
* object is restarted and we won't need different constructors to initialize it.
*
* NOTE: This returns a _const reference_! Make sure you store it in a _const reference_!
*
* @param data_name The name of the data (usually just use the same name as the member variable)
*/
template <typename T, typename... Args>
const T & getRestartableData(const std::string & data_name) const;
/**
* Declare a piece of data as "restartable" and initialize it.
* This means that in the event of a restart this piece of data
* will be restored back to its previous value.
*
* NOTE: This returns a _reference_! Make sure you store it in a _reference_!
*
* @param data_name The name of the data (usually just use the same name as the member variable)
* @param context Context pointer that will be passed to the load and store functions
* @param args Arguments to forward to the constructor of the data
*/
template <typename T, typename... Args>
T &
declareRestartableDataWithContext(const std::string & data_name, void * context, Args &&... args);
/**
* Declare a piece of data as "recoverable" and initialize it.
* This means that in the event of a restart this piece of data
* will be restored back to its previous value.
*
* Note - this data will NOT be restored on _Restart_!
*
* NOTE: This returns a _reference_! Make sure you store it in a _reference_!
*
* @param data_name The name of the data (usually just use the same name as the member variable)
* @param args Arguments to forward to the constructor of the data
*/
template <typename T, typename... Args>
T & declareRecoverableData(const std::string & data_name, Args &&... args);
/**
* Declare a piece of data as "restartable".
* This means that in the event of a restart this piece of data
* will be restored back to its previous value.
*
* NOTE: This returns a _reference_! Make sure you store it in a _reference_!
*
* @param data_name The name of the data (usually just use the same name as the member variable)
* @param object_name A supplied name for the object that is declaring this data.
* @param args Arguments to forward to the constructor of the data
*/
template <typename T, typename... Args>
T & declareRestartableDataWithObjectName(const std::string & data_name,
const std::string & object_name,
Args &&... args);
/**
* Declare a piece of data as "restartable".
* This means that in the event of a restart this piece of data
* will be restored back to its previous value.
*
* NOTE: This returns a _reference_! Make sure you store it in a _reference_!
*
* @param data_name The name of the data (usually just use the same name as the member variable)
* @param object_name A supplied name for the object that is declaring this data.
* @param context Context pointer that will be passed to the load and store functions
* @param args Arguments to forward to the constructor of the data
*/
template <typename T, typename... Args>
T & declareRestartableDataWithObjectNameWithContext(const std::string & data_name,
const std::string & object_name,
void * context,
Args &&... args);
/**
* Gets the name of a piece of restartable data given a data name, adding
* the system name and object name prefix.
*
* This should only be used in this interface and in testing.
*/
std::string restartableName(const std::string & data_name) const;
/// Reference to the application
MooseApp & _restartable_app;
/// The system name this object is in
const std::string _restartable_system_name;
/// The thread ID for this object
const THREAD_ID _restartable_tid;
/// Flag for toggling read only status (see ReporterData)
const bool _restartable_read_only;
private:
/// Restartable metadata name
const RestartableDataMapName _metaname;
/// The name of the object
std::string _restartable_name;
/// Helper function for actually registering the restartable data.
RestartableDataValue & registerRestartableDataOnApp(std::unique_ptr<RestartableDataValue> data,
THREAD_ID tid) const;
/// Helper function for actually registering the restartable data.
void registerRestartableNameWithFilterOnApp(const std::string & name,
Moose::RESTARTABLE_FILTER filter);
/**
* Helper function for declaring restartable data. We use this function to reduce code duplication
* when returning const/nonconst references to the data.
*
* @param data_name The name of the data (usually just use the same name as the member variable)
* @param context Context pointer that will be passed to the load and store functions
* @param args Arguments to forward to the constructor of the data
*/
template <typename T, typename... Args>
RestartableData<T> & declareRestartableDataHelper(const std::string & data_name,
void * context,
Args &&... args) const;
};
template <typename T, typename... Args>
T &
Restartable::declareRestartableData(const std::string & data_name, Args &&... args)
{
return declareRestartableDataWithContext<T>(data_name, nullptr, std::forward<Args>(args)...);
}
template <typename T, typename... Args>
Restartable::ManagedValue<T>
Restartable::declareManagedRestartableDataWithContext(const std::string & data_name,
void * context,
Args &&... args)
{
auto & data_ptr =
declareRestartableDataHelper<T>(data_name, context, std::forward<Args>(args)...);
return Restartable::ManagedValue<T>(data_ptr);
}
template <typename T, typename... Args>
const T &
Restartable::getRestartableData(const std::string & data_name) const
{
return declareRestartableDataHelper<T>(data_name, nullptr).get();
}
template <typename T, typename... Args>
T &
Restartable::declareRestartableDataWithContext(const std::string & data_name,
void * context,
Args &&... args)
{
return declareRestartableDataHelper<T>(data_name, context, std::forward<Args>(args)...).set();
}
template <typename T, typename... Args>
RestartableData<T> &
Restartable::declareRestartableDataHelper(const std::string & data_name,
void * context,
Args &&... args) const
{
const auto full_name = restartableName(data_name);
// Here we will create the RestartableData even though we may not use this instance.
// If it's already in use, the App will return a reference to the existing instance and we'll
// return that one instead. We might refactor this to have the app create the RestartableData
// at a later date.
auto data_ptr =
std::make_unique<RestartableData<T>>(full_name, context, std::forward<Args>(args)...);
auto & restartable_data_ref = static_cast<RestartableData<T> &>(
registerRestartableDataOnApp(std::move(data_ptr), _restartable_tid));
return restartable_data_ref;
}
template <typename T, typename... Args>
T &
Restartable::declareRestartableDataWithObjectName(const std::string & data_name,
const std::string & object_name,
Args &&... args)
{
return declareRestartableDataWithObjectNameWithContext<T>(
data_name, object_name, nullptr, std::forward<Args>(args)...);
}
template <typename T, typename... Args>
T &
Restartable::declareRestartableDataWithObjectNameWithContext(const std::string & data_name,
const std::string & object_name,
void * context,
Args &&... args)
{
std::string old_name = _restartable_name;
_restartable_name = object_name;
T & value = declareRestartableDataWithContext<T>(data_name, context, std::forward<Args>(args)...);
_restartable_name = old_name;
return value;
}
template <typename T, typename... Args>
T &
Restartable::declareRecoverableData(const std::string & data_name, Args &&... args)
{
const auto full_name = restartableName(data_name);
registerRestartableNameWithFilterOnApp(full_name, Moose::RESTARTABLE_FILTER::RECOVERABLE);
return declareRestartableDataWithContext<T>(data_name, nullptr, std::forward<Args>(args)...);
}
(moose/framework/include/restart/DataIO.h)
// This file is part of the MOOSE framework
// https://www.mooseframework.org
//
// All rights reserved, see COPYRIGHT for full restrictions
// https://github.com/idaholab/moose/blob/master/COPYRIGHT
//
// Licensed under LGPL 2.1, please see LICENSE for details
// https://www.gnu.org/licenses/lgpl-2.1.html
#pragma once
// MOOSE includes
#include "ADReal.h"
#include "MooseTypes.h"
#include "HashMap.h"
#include "MooseError.h"
#include "RankTwoTensor.h"
#include "RankThreeTensor.h"
#include "RankFourTensor.h"
#include "ColumnMajorMatrix.h"
#include "UniqueStorage.h"
#include "libmesh/parallel.h"
#include "libmesh/parameters.h"
#include "libmesh/numeric_vector.h"
#ifdef LIBMESH_HAVE_CXX11_TYPE_TRAITS
#include <type_traits>
#endif
// C++ includes
#include <string>
#include <vector>
#include <list>
#include <iostream>
#include <map>
#include <unordered_map>
#include <unordered_set>
#include <memory>
#include <optional>
namespace libMesh
{
template <typename T>
class DenseMatrix;
template <typename T>
class DenseVector;
template <typename T>
class VectorValue;
template <typename T>
class TensorValue;
class Elem;
class Point;
}
/**
* Scalar helper routine
*/
template <typename P>
inline void storeHelper(std::ostream & stream, P & data, void * context);
/**
* Vector helper routine
*/
template <typename P>
inline void storeHelper(std::ostream & stream, std::vector<P> & data, void * context);
/**
* Shared pointer helper routine
*/
template <typename P>
inline void storeHelper(std::ostream & stream, std::shared_ptr<P> & data, void * context);
/**
* Unique pointer helper routine
*/
template <typename P>
inline void storeHelper(std::ostream & stream, std::unique_ptr<P> & data, void * context);
/**
* Set helper routine
*/
template <typename P>
inline void storeHelper(std::ostream & stream, std::set<P> & data, void * context);
/**
* Map helper routine
*/
template <typename P, typename Q>
inline void storeHelper(std::ostream & stream, std::map<P, Q> & data, void * context);
/**
* Unordered_map helper routine
*/
template <typename P, typename Q>
inline void storeHelper(std::ostream & stream, std::unordered_map<P, Q> & data, void * context);
/**
* Optional helper routine
*/
template <typename P>
inline void storeHelper(std::ostream & stream, std::optional<P> & data, void * context);
/**
* HashMap helper routine
*/
template <typename P, typename Q>
inline void storeHelper(std::ostream & stream, HashMap<P, Q> & data, void * context);
/**
* UniqueStorage helper routine
*/
template <typename T>
inline void storeHelper(std::ostream & stream, UniqueStorage<T> & data, void * context);
/**
* Scalar helper routine
*/
template <typename P>
inline void loadHelper(std::istream & stream, P & data, void * context);
/**
* Vector helper routine
*/
template <typename P>
inline void loadHelper(std::istream & stream, std::vector<P> & data, void * context);
/**
* Shared Pointer helper routine
*/
template <typename P>
inline void loadHelper(std::istream & stream, std::shared_ptr<P> & data, void * context);
/**
* Unique Pointer helper routine
*/
template <typename P>
inline void loadHelper(std::istream & stream, std::unique_ptr<P> & data, void * context);
/**
* Set helper routine
*/
template <typename P>
inline void loadHelper(std::istream & stream, std::set<P> & data, void * context);
/**
* Map helper routine
*/
template <typename P, typename Q>
inline void loadHelper(std::istream & stream, std::map<P, Q> & data, void * context);
/**
* Unordered_map helper routine
*/
template <typename P, typename Q>
inline void loadHelper(std::istream & stream, std::unordered_map<P, Q> & data, void * context);
/**
* Optional helper routine
*/
template <typename P>
inline void loadHelper(std::istream & stream, std::optional<P> & data, void * context);
/**
* Hashmap helper routine
*/
template <typename P, typename Q>
inline void loadHelper(std::istream & stream, HashMap<P, Q> & data, void * context);
/**
* UniqueStorage helper routine
*/
template <typename T>
inline void loadHelper(std::istream & stream, UniqueStorage<T> & data, void * context);
template <typename T>
inline void dataStore(std::ostream & stream, T & v, void * /*context*/);
// DO NOT MODIFY THE NEXT LINE - It is used by MOOSEDocs
// *************** Global Store Declarations *****************
template <typename T>
inline void
dataStore(std::ostream & stream, T & v, void * /*context*/)
{
#ifdef LIBMESH_HAVE_CXX11_TYPE_TRAITS
static_assert(std::is_polymorphic<T>::value == false,
"Cannot serialize a class that has virtual "
"members!\nWrite a custom dataStore() "
"template specialization!\n\n");
static_assert(std::is_trivially_copyable<T>::value,
"Cannot serialize a class that is not trivially copyable!\nWrite a custom "
"dataStore() template specialization!\n\n");
#endif
// Moose::out<<"Generic dataStore"<<std::endl;
stream.write((char *)&v, sizeof(v));
mooseAssert(!stream.bad(), "Failed to store");
}
template <typename T>
inline void
dataStore(std::ostream & /*stream*/, T *& /*v*/, void * /*context*/)
{
mooseError("Attempting to store a raw pointer type: \"",
demangle(typeid(T).name()),
" *\" as restartable data!\nWrite a custom dataStore() template specialization!\n\n");
}
void dataStore(std::ostream & stream, Point & p, void * context);
template <typename T, typename U>
inline void
dataStore(std::ostream & stream, std::pair<T, U> & p, void * context)
{
storeHelper(stream, p.first, context);
storeHelper(stream, p.second, context);
}
template <typename T>
inline void
dataStore(std::ostream & stream, std::vector<T> & v, void * context)
{
// First store the size of the vector
unsigned int size = v.size();
dataStore(stream, size, nullptr);
for (unsigned int i = 0; i < size; i++)
storeHelper(stream, v[i], context);
}
template <typename T>
inline void
dataStore(std::ostream & stream, std::shared_ptr<T> & v, void * context)
{
T * tmp = v.get();
storeHelper(stream, tmp, context);
}
template <typename T>
inline void
dataStore(std::ostream & stream, std::unique_ptr<T> & v, void * context)
{
T * tmp = v.get();
storeHelper(stream, tmp, context);
}
template <typename T>
inline void
dataStore(std::ostream & stream, std::set<T> & s, void * context)
{
// First store the size of the set
unsigned int size = s.size();
dataStore(stream, size, nullptr);
typename std::set<T>::iterator it = s.begin();
typename std::set<T>::iterator end = s.end();
for (; it != end; ++it)
{
T & x = const_cast<T &>(*it);
storeHelper(stream, x, context);
}
}
template <typename T>
inline void
dataStore(std::ostream & stream, std::list<T> & l, void * context)
{
// First store the size of the set
unsigned int size = l.size();
dataStore(stream, size, nullptr);
typename std::list<T>::iterator it = l.begin();
typename std::list<T>::iterator end = l.end();
for (; it != end; ++it)
{
T & x = const_cast<T &>(*it);
storeHelper(stream, x, context);
}
}
template <typename T>
inline void
dataStore(std::ostream & stream, std::deque<T> & l, void * context)
{
// First store the size of the container
unsigned int size = l.size();
dataStore(stream, size, nullptr);
typename std::deque<T>::iterator it = l.begin();
typename std::deque<T>::iterator end = l.end();
for (; it != end; ++it)
{
T & x = const_cast<T &>(*it);
storeHelper(stream, x, context);
}
}
template <typename T, typename U>
inline void
dataStore(std::ostream & stream, std::map<T, U> & m, void * context)
{
// First store the size of the map
unsigned int size = m.size();
dataStore(stream, size, nullptr);
typename std::map<T, U>::iterator it = m.begin();
typename std::map<T, U>::iterator end = m.end();
for (; it != end; ++it)
{
T & key = const_cast<T &>(it->first);
storeHelper(stream, key, context);
storeHelper(stream, it->second, context);
}
}
template <typename T, typename U>
inline void
dataStore(std::ostream & stream, std::unordered_map<T, U> & m, void * context)
{
// First store the size of the map
unsigned int size = m.size();
dataStore(stream, size, nullptr);
typename std::unordered_map<T, U>::iterator it = m.begin();
typename std::unordered_map<T, U>::iterator end = m.end();
for (; it != end; ++it)
{
T & key = const_cast<T &>(it->first);
storeHelper(stream, key, context);
storeHelper(stream, it->second, context);
}
}
template <typename T>
inline void
dataStore(std::ostream & stream, std::unordered_set<T> & s, void * context)
{
// First store the size of the set
std::size_t size = s.size();
dataStore(stream, size, nullptr);
for (auto & element : s)
dataStore(stream, element, context);
}
template <typename T>
inline void
dataStore(std::ostream & stream, std::optional<T> & m, void * context)
{
bool has_value = m.has_value();
dataStore(stream, has_value, nullptr);
if (has_value)
storeHelper(stream, *m, context);
}
template <typename T, typename U>
inline void
dataStore(std::ostream & stream, HashMap<T, U> & m, void * context)
{
// First store the size of the map
unsigned int size = m.size();
dataStore(stream, size, nullptr);
typename HashMap<T, U>::iterator it = m.begin();
typename HashMap<T, U>::iterator end = m.end();
for (; it != end; ++it)
{
T & key = const_cast<T &>(it->first);
storeHelper(stream, key, context);
storeHelper(stream, it->second, context);
}
}
// Specializations (defined in .C)
template <>
void dataStore(std::ostream & stream, Real & v, void * context);
template <>
void dataStore(std::ostream & stream, std::string & v, void * context);
template <>
void dataStore(std::ostream & stream, VariableName & v, void * context);
template <>
void dataStore(std::ostream & stream, UserObjectName & v, void * context);
template <>
void dataStore(std::ostream & stream, bool & v, void * context);
// Vectors of bools are special
// https://en.wikipedia.org/w/index.php?title=Sequence_container_(C%2B%2B)&oldid=767869909#Specialization_for_bool
template <>
void dataStore(std::ostream & stream, std::vector<bool> & v, void * context);
template <>
void dataStore(std::ostream & stream, const Elem *& e, void * context);
template <>
void dataStore(std::ostream & stream, const Node *& n, void * context);
template <>
void dataStore(std::ostream & stream, Elem *& e, void * context);
template <>
void dataStore(std::ostream & stream, Node *& n, void * context);
template <>
void dataStore(std::ostream & stream, std::stringstream & s, void * context);
template <>
void dataStore(std::ostream & stream, ADReal & dn, void * context);
template <>
void dataStore(std::ostream & stream, RealEigenVector & v, void * context);
template <>
void dataStore(std::ostream & stream, RealEigenMatrix & v, void * context);
template <>
void dataStore(std::ostream & stream, libMesh::Parameters & p, void * context);
template <>
/**
* Stores an owned numeric vector.
*
* This should be used in lieu of the NumericVector<Number> & implementation
* when the vector may not necessarily be initialized yet on the loading of
* the data. It stores the partitioning (total and local number of entries).
*
* Requirements: the unique_ptr must exist (cannot be null), the vector
* cannot be ghosted, and the provided context must be the Communicator.
*/
void dataStore(std::ostream & stream,
std::unique_ptr<libMesh::NumericVector<Number>> & v,
void * context);
template <std::size_t N>
inline void
dataStore(std::ostream & stream, std::array<ADReal, N> & dn, void * context)
{
for (std::size_t i = 0; i < N; ++i)
dataStore(stream, dn[i], context);
}
template <std::size_t N>
inline void
dataStore(std::ostream & stream, ADReal (&dn)[N], void * context)
{
for (std::size_t i = 0; i < N; ++i)
dataStore(stream, dn[i], context);
}
template <typename T>
void
dataStore(std::ostream & stream, NumericVector<T> & v, void * context)
{
v.close();
numeric_index_type size = v.local_size();
for (numeric_index_type i = v.first_local_index(); i < v.first_local_index() + size; i++)
{
T r = v(i);
dataStore(stream, r, context);
}
}
template <>
void dataStore(std::ostream & stream, Vec & v, void * context);
template <typename T>
void
dataStore(std::ostream & stream, DenseVector<T> & v, void * context)
{
unsigned int m = v.size();
dataStore(stream, m, nullptr);
for (unsigned int i = 0; i < v.size(); i++)
{
T r = v(i);
dataStore(stream, r, context);
}
}
template <typename T>
void dataStore(std::ostream & stream, TensorValue<T> & v, void * context);
template <typename T>
void dataStore(std::ostream & stream, DenseMatrix<T> & v, void * context);
template <typename T>
void dataStore(std::ostream & stream, VectorValue<T> & v, void * context);
template <typename T>
void
dataStore(std::ostream & stream, RankTwoTensorTempl<T> & rtt, void * context)
{
dataStore(stream, rtt._coords, context);
}
template <typename T>
void
dataStore(std::ostream & stream, RankThreeTensorTempl<T> & rtt, void * context)
{
dataStore(stream, rtt._vals, context);
}
template <typename T>
void
dataStore(std::ostream & stream, RankFourTensorTempl<T> & rft, void * context)
{
dataStore(stream, rft._vals, context);
}
template <typename T>
void
dataStore(std::ostream & stream, SymmetricRankTwoTensorTempl<T> & srtt, void * context)
{
dataStore(stream, srtt._vals, context);
}
template <typename T>
void
dataStore(std::ostream & stream, SymmetricRankFourTensorTempl<T> & srft, void * context)
{
dataStore(stream, srft._vals, context);
}
template <typename T>
void
dataStore(std::ostream & stream, ColumnMajorMatrixTempl<T> & cmm, void * context)
{
dataStore(stream, cmm._values, context);
}
// DO NOT MODIFY THE NEXT LINE - It is used by MOOSEDocs
// *************** Global Load Declarations *****************
template <typename T>
inline void
dataLoad(std::istream & stream, T & v, void * /*context*/)
{
stream.read((char *)&v, sizeof(v));
mooseAssert(!stream.bad(), "Failed to load");
}
template <typename T>
void
dataLoad(std::istream & /*stream*/, T *& /*v*/, void * /*context*/)
{
mooseError("Attempting to load a raw pointer type: \"",
demangle(typeid(T).name()),
" *\" as restartable data!\nWrite a custom dataLoad() template specialization!\n\n");
}
template <typename T, typename U>
inline void
dataLoad(std::istream & stream, std::pair<T, U> & p, void * context)
{
loadHelper(stream, p.first, context);
loadHelper(stream, p.second, context);
}
template <typename T>
inline void
dataLoad(std::istream & stream, std::vector<T> & v, void * context)
{
// First read the size of the vector
unsigned int size = 0;
dataLoad(stream, size, nullptr);
v.resize(size);
for (unsigned int i = 0; i < size; i++)
loadHelper(stream, v[i], context);
}
template <typename T>
inline void
dataLoad(std::istream & stream, std::shared_ptr<T> & v, void * context)
{
T * tmp = v.get();
loadHelper(stream, tmp, context);
}
template <typename T>
inline void
dataLoad(std::istream & stream, std::unique_ptr<T> & v, void * context)
{
T * tmp = v.get();
loadHelper(stream, tmp, context);
}
template <typename T>
inline void
dataLoad(std::istream & stream, std::set<T> & s, void * context)
{
// First read the size of the set
unsigned int size = 0;
dataLoad(stream, size, nullptr);
for (unsigned int i = 0; i < size; i++)
{
T data;
loadHelper(stream, data, context);
s.insert(std::move(data));
}
}
template <typename T>
inline void
dataLoad(std::istream & stream, std::list<T> & l, void * context)
{
// First read the size of the set
unsigned int size = 0;
dataLoad(stream, size, nullptr);
for (unsigned int i = 0; i < size; i++)
{
T data;
loadHelper(stream, data, context);
l.push_back(std::move(data));
}
}
template <typename T>
inline void
dataLoad(std::istream & stream, std::deque<T> & l, void * context)
{
// First read the size of the container
unsigned int size = 0;
dataLoad(stream, size, nullptr);
for (unsigned int i = 0; i < size; i++)
{
T data;
loadHelper(stream, data, context);
l.push_back(std::move(data));
}
}
template <typename T, typename U>
inline void
dataLoad(std::istream & stream, std::map<T, U> & m, void * context)
{
m.clear();
// First read the size of the map
unsigned int size = 0;
dataLoad(stream, size, nullptr);
for (unsigned int i = 0; i < size; i++)
{
T key;
loadHelper(stream, key, context);
U & value = m[key];
loadHelper(stream, value, context);
}
}
template <typename T, typename U>
inline void
dataLoad(std::istream & stream, std::unordered_map<T, U> & m, void * context)
{
m.clear();
// First read the size of the map
unsigned int size = 0;
dataLoad(stream, size, nullptr);
for (unsigned int i = 0; i < size; i++)
{
T key;
loadHelper(stream, key, context);
U & value = m[key];
loadHelper(stream, value, context);
}
}
template <typename T>
inline void
dataLoad(std::istream & stream, std::unordered_set<T> & s, void * context)
{
s.clear();
// First read the size of the set
std::size_t size = 0;
dataLoad(stream, size, nullptr);
s.reserve(size);
for (std::size_t i = 0; i < size; i++)
{
T element;
dataLoad(stream, element, context);
s.insert(element);
}
}
template <typename T>
inline void
dataLoad(std::istream & stream, std::optional<T> & m, void * context)
{
bool has_value;
dataLoad(stream, has_value, nullptr);
if (has_value)
{
m = T{};
loadHelper(stream, *m, context);
}
else
m.reset();
}
template <typename T, typename U>
inline void
dataLoad(std::istream & stream, HashMap<T, U> & m, void * context)
{
// First read the size of the map
unsigned int size = 0;
dataLoad(stream, size, nullptr);
for (unsigned int i = 0; i < size; i++)
{
T key;
loadHelper(stream, key, context);
U & value = m[key];
loadHelper(stream, value, context);
}
}
// Specializations (defined in .C)
template <>
void dataLoad(std::istream & stream, Real & v, void * /*context*/);
template <>
void dataLoad(std::istream & stream, std::string & v, void * /*context*/);
template <>
void dataLoad(std::istream & stream, VariableName & v, void * /*context*/);
template <>
void dataLoad(std::istream & stream, UserObjectName & v, void * /*context*/);
template <>
void dataLoad(std::istream & stream, bool & v, void * /*context*/);
// Vectors of bools are special
// https://en.wikipedia.org/w/index.php?title=Sequence_container_(C%2B%2B)&oldid=767869909#Specialization_for_bool
template <>
void dataLoad(std::istream & stream, std::vector<bool> & v, void * /*context*/);
template <>
void dataLoad(std::istream & stream, const Elem *& e, void * context);
template <>
void dataLoad(std::istream & stream, const Node *& e, void * context);
template <>
void dataLoad(std::istream & stream, Elem *& e, void * context);
template <>
void dataLoad(std::istream & stream, Node *& e, void * context);
template <>
void dataLoad(std::istream & stream, std::stringstream & s, void * context);
template <>
void dataLoad(std::istream & stream, ADReal & dn, void * context);
template <>
void dataLoad(std::istream & stream, RealEigenVector & v, void * context);
template <>
void dataLoad(std::istream & stream, RealEigenMatrix & v, void * context);
template <>
void dataLoad(std::istream & stream, libMesh::Parameters & p, void * context);
template <>
/**
* Loads an owned numeric vector.
*
* This is used in lieu of the NumericVector<double> & implementation when
* the vector may not necessarily be initialized yet on the loading of the data.
*
* If \p is not null, it must have the same global and local sizes that it
* was stored with. In this case, the data is simply filled into the vector.
*
* If \p is null, it will be constructed with the type (currently just a
* PetscVector) stored and initialized with the global and local sizes stored.
* The data will then be filled after initialization.
*
* Requirements: the vector cannot be ghosted, the provided context must be
* the Communicator, and if \p v is initialized, it must have the same global
* and local sizes that the vector was stored with.
*/
void dataLoad(std::istream & stream,
std::unique_ptr<libMesh::NumericVector<Number>> & v,
void * context);
template <std::size_t N>
inline void
dataLoad(std::istream & stream, std::array<ADReal, N> & dn, void * context)
{
for (std::size_t i = 0; i < N; ++i)
dataLoad(stream, dn[i], context);
}
template <std::size_t N>
inline void
dataLoad(std::istream & stream, ADReal (&dn)[N], void * context)
{
for (std::size_t i = 0; i < N; ++i)
dataLoad(stream, dn[i], context);
}
template <typename T>
void
dataLoad(std::istream & stream, NumericVector<T> & v, void * context)
{
numeric_index_type size = v.local_size();
for (numeric_index_type i = v.first_local_index(); i < v.first_local_index() + size; i++)
{
T r = 0;
dataLoad(stream, r, context);
v.set(i, r);
}
v.close();
}
template <>
void dataLoad(std::istream & stream, Vec & v, void * context);
template <typename T>
void
dataLoad(std::istream & stream, DenseVector<T> & v, void * context)
{
unsigned int n = 0;
dataLoad(stream, n, nullptr);
v.resize(n);
for (unsigned int i = 0; i < n; i++)
{
T r = 0;
dataLoad(stream, r, context);
v(i) = r;
}
}
template <typename T>
void dataLoad(std::istream & stream, TensorValue<T> & v, void * context);
template <typename T>
void dataLoad(std::istream & stream, DenseMatrix<T> & v, void * context);
template <typename T>
void dataLoad(std::istream & stream, VectorValue<T> & v, void * context);
template <typename T>
void
dataLoad(std::istream & stream, RankTwoTensorTempl<T> & rtt, void * context)
{
dataLoad(stream, rtt._coords, context);
}
template <typename T>
void
dataLoad(std::istream & stream, RankThreeTensorTempl<T> & rtt, void * context)
{
dataLoad(stream, rtt._vals, context);
}
template <typename T>
void
dataLoad(std::istream & stream, RankFourTensorTempl<T> & rft, void * context)
{
dataLoad(stream, rft._vals, context);
}
template <typename T>
void
dataLoad(std::istream & stream, SymmetricRankTwoTensorTempl<T> & rtt, void * context)
{
dataLoad(stream, rtt._vals, context);
}
template <typename T>
void
dataLoad(std::istream & stream, SymmetricRankFourTensorTempl<T> & rft, void * context)
{
dataLoad(stream, rft._vals, context);
}
template <typename T>
void
dataLoad(std::istream & stream, ColumnMajorMatrixTempl<T> & cmm, void * context)
{
dataLoad(stream, cmm._values, context);
}
// Scalar Helper Function
template <typename P>
inline void
storeHelper(std::ostream & stream, P & data, void * context)
{
dataStore(stream, data, context);
}
// Vector Helper Function
template <typename P>
inline void
storeHelper(std::ostream & stream, std::vector<P> & data, void * context)
{
dataStore(stream, data, context);
}
// std::shared_ptr Helper Function
template <typename P>
inline void
storeHelper(std::ostream & stream, std::shared_ptr<P> & data, void * context)
{
dataStore(stream, data, context);
}
// std::unique Helper Function
template <typename P>
inline void
storeHelper(std::ostream & stream, std::unique_ptr<P> & data, void * context)
{
dataStore(stream, data, context);
}
// Set Helper Function
template <typename P>
inline void
storeHelper(std::ostream & stream, std::set<P> & data, void * context)
{
dataStore(stream, data, context);
}
// Map Helper Function
template <typename P, typename Q>
inline void
storeHelper(std::ostream & stream, std::map<P, Q> & data, void * context)
{
dataStore(stream, data, context);
}
// Unordered_map Helper Function
template <typename P, typename Q>
inline void
storeHelper(std::ostream & stream, std::unordered_map<P, Q> & data, void * context)
{
dataStore(stream, data, context);
}
// Optional Helper Function
template <typename P>
inline void
storeHelper(std::ostream & stream, std::optional<P> & data, void * context)
{
dataStore(stream, data, context);
}
// HashMap Helper Function
template <typename P, typename Q>
inline void
storeHelper(std::ostream & stream, HashMap<P, Q> & data, void * context)
{
dataStore(stream, data, context);
}
/**
* UniqueStorage helper routine
*
* The data within the UniqueStorage object cannot be null. The helper
* for unique_ptr<T> is called to store the data.
*/
template <typename T>
inline void
storeHelper(std::ostream & stream, UniqueStorage<T> & data, void * context)
{
std::size_t size = data.size();
dataStore(stream, size, nullptr);
for (const auto i : index_range(data))
{
mooseAssert(data.hasValue(i), "Data doesn't have a value");
storeHelper(stream, data.pointerValue(i), context);
}
}
// Scalar Helper Function
template <typename P>
inline void
loadHelper(std::istream & stream, P & data, void * context)
{
dataLoad(stream, data, context);
}
// Vector Helper Function
template <typename P>
inline void
loadHelper(std::istream & stream, std::vector<P> & data, void * context)
{
dataLoad(stream, data, context);
}
// std::shared_ptr Helper Function
template <typename P>
inline void
loadHelper(std::istream & stream, std::shared_ptr<P> & data, void * context)
{
dataLoad(stream, data, context);
}
// Unique Pointer Helper Function
template <typename P>
inline void
loadHelper(std::istream & stream, std::unique_ptr<P> & data, void * context)
{
dataLoad(stream, data, context);
}
// Set Helper Function
template <typename P>
inline void
loadHelper(std::istream & stream, std::set<P> & data, void * context)
{
dataLoad(stream, data, context);
}
// Map Helper Function
template <typename P, typename Q>
inline void
loadHelper(std::istream & stream, std::map<P, Q> & data, void * context)
{
dataLoad(stream, data, context);
}
// Unordered_map Helper Function
template <typename P, typename Q>
inline void
loadHelper(std::istream & stream, std::unordered_map<P, Q> & data, void * context)
{
dataLoad(stream, data, context);
}
// Optional Helper Function
template <typename P>
inline void
loadHelper(std::istream & stream, std::optional<P> & data, void * context)
{
dataLoad(stream, data, context);
}
// HashMap Helper Function
template <typename P, typename Q>
inline void
loadHelper(std::istream & stream, HashMap<P, Q> & data, void * context)
{
dataLoad(stream, data, context);
}
/**
* UniqueStorage Helper Function
*
* The unique_ptr<T> loader is called to load the data. That is,
* you will likely need a specialization of unique_ptr<T> that will
* appropriately construct and then fill the piece of data.
*/
template <typename T>
inline void
loadHelper(std::istream & stream, UniqueStorage<T> & data, void * context)
{
std::size_t size;
dataLoad(stream, size, nullptr);
data.resize(size);
for (const auto i : index_range(data))
loadHelper(stream, data.pointerValue(i), context);
}
void dataLoad(std::istream & stream, Point & p, void * context);
#ifndef TIMPI_HAVE_STRING_PACKING
/**
* The following methods are specializations for using the libMesh::Parallel::packed_range_*
* routines
* for std::strings. These are here because the dataLoad/dataStore routines create raw string
* buffers that can be communicated in a standard way using packed ranges.
*/
namespace libMesh
{
namespace Parallel
{
template <typename T>
class Packing<std::basic_string<T>>
{
public:
static const unsigned int size_bytes = 4;
typedef T buffer_type;
static unsigned int get_string_len(typename std::vector<T>::const_iterator in)
{
unsigned int string_len = reinterpret_cast<const unsigned char &>(in[size_bytes - 1]);
for (signed int i = size_bytes - 2; i >= 0; --i)
{
string_len *= 256;
string_len += reinterpret_cast<const unsigned char &>(in[i]);
}
return string_len;
}
static unsigned int packed_size(typename std::vector<T>::const_iterator in)
{
return get_string_len(in) + size_bytes;
}
static unsigned int packable_size(const std::basic_string<T> & s, const void *)
{
return s.size() + size_bytes;
}
template <typename Iter>
static void pack(const std::basic_string<T> & b, Iter data_out, const void *)
{
unsigned int string_len = b.size();
for (unsigned int i = 0; i != size_bytes; ++i)
{
*data_out++ = (string_len % 256);
string_len /= 256;
}
std::copy(b.begin(), b.end(), data_out);
}
static std::basic_string<T> unpack(typename std::vector<T>::const_iterator in, void *)
{
unsigned int string_len = get_string_len(in);
std::ostringstream oss;
for (unsigned int i = 0; i < string_len; ++i)
oss << reinterpret_cast<const unsigned char &>(in[i + size_bytes]);
in += size_bytes + string_len;
return oss.str();
}
};
} // namespace Parallel
} // namespace libMesh
#endif
(moose/framework/include/restart/DataIO.h)
// This file is part of the MOOSE framework
// https://www.mooseframework.org
//
// All rights reserved, see COPYRIGHT for full restrictions
// https://github.com/idaholab/moose/blob/master/COPYRIGHT
//
// Licensed under LGPL 2.1, please see LICENSE for details
// https://www.gnu.org/licenses/lgpl-2.1.html
#pragma once
// MOOSE includes
#include "ADReal.h"
#include "MooseTypes.h"
#include "HashMap.h"
#include "MooseError.h"
#include "RankTwoTensor.h"
#include "RankThreeTensor.h"
#include "RankFourTensor.h"
#include "ColumnMajorMatrix.h"
#include "UniqueStorage.h"
#include "libmesh/parallel.h"
#include "libmesh/parameters.h"
#include "libmesh/numeric_vector.h"
#ifdef LIBMESH_HAVE_CXX11_TYPE_TRAITS
#include <type_traits>
#endif
// C++ includes
#include <string>
#include <vector>
#include <list>
#include <iostream>
#include <map>
#include <unordered_map>
#include <unordered_set>
#include <memory>
#include <optional>
namespace libMesh
{
template <typename T>
class DenseMatrix;
template <typename T>
class DenseVector;
template <typename T>
class VectorValue;
template <typename T>
class TensorValue;
class Elem;
class Point;
}
/**
* Scalar helper routine
*/
template <typename P>
inline void storeHelper(std::ostream & stream, P & data, void * context);
/**
* Vector helper routine
*/
template <typename P>
inline void storeHelper(std::ostream & stream, std::vector<P> & data, void * context);
/**
* Shared pointer helper routine
*/
template <typename P>
inline void storeHelper(std::ostream & stream, std::shared_ptr<P> & data, void * context);
/**
* Unique pointer helper routine
*/
template <typename P>
inline void storeHelper(std::ostream & stream, std::unique_ptr<P> & data, void * context);
/**
* Set helper routine
*/
template <typename P>
inline void storeHelper(std::ostream & stream, std::set<P> & data, void * context);
/**
* Map helper routine
*/
template <typename P, typename Q>
inline void storeHelper(std::ostream & stream, std::map<P, Q> & data, void * context);
/**
* Unordered_map helper routine
*/
template <typename P, typename Q>
inline void storeHelper(std::ostream & stream, std::unordered_map<P, Q> & data, void * context);
/**
* Optional helper routine
*/
template <typename P>
inline void storeHelper(std::ostream & stream, std::optional<P> & data, void * context);
/**
* HashMap helper routine
*/
template <typename P, typename Q>
inline void storeHelper(std::ostream & stream, HashMap<P, Q> & data, void * context);
/**
* UniqueStorage helper routine
*/
template <typename T>
inline void storeHelper(std::ostream & stream, UniqueStorage<T> & data, void * context);
/**
* Scalar helper routine
*/
template <typename P>
inline void loadHelper(std::istream & stream, P & data, void * context);
/**
* Vector helper routine
*/
template <typename P>
inline void loadHelper(std::istream & stream, std::vector<P> & data, void * context);
/**
* Shared Pointer helper routine
*/
template <typename P>
inline void loadHelper(std::istream & stream, std::shared_ptr<P> & data, void * context);
/**
* Unique Pointer helper routine
*/
template <typename P>
inline void loadHelper(std::istream & stream, std::unique_ptr<P> & data, void * context);
/**
* Set helper routine
*/
template <typename P>
inline void loadHelper(std::istream & stream, std::set<P> & data, void * context);
/**
* Map helper routine
*/
template <typename P, typename Q>
inline void loadHelper(std::istream & stream, std::map<P, Q> & data, void * context);
/**
* Unordered_map helper routine
*/
template <typename P, typename Q>
inline void loadHelper(std::istream & stream, std::unordered_map<P, Q> & data, void * context);
/**
* Optional helper routine
*/
template <typename P>
inline void loadHelper(std::istream & stream, std::optional<P> & data, void * context);
/**
* Hashmap helper routine
*/
template <typename P, typename Q>
inline void loadHelper(std::istream & stream, HashMap<P, Q> & data, void * context);
/**
* UniqueStorage helper routine
*/
template <typename T>
inline void loadHelper(std::istream & stream, UniqueStorage<T> & data, void * context);
template <typename T>
inline void dataStore(std::ostream & stream, T & v, void * /*context*/);
// DO NOT MODIFY THE NEXT LINE - It is used by MOOSEDocs
// *************** Global Store Declarations *****************
template <typename T>
inline void
dataStore(std::ostream & stream, T & v, void * /*context*/)
{
#ifdef LIBMESH_HAVE_CXX11_TYPE_TRAITS
static_assert(std::is_polymorphic<T>::value == false,
"Cannot serialize a class that has virtual "
"members!\nWrite a custom dataStore() "
"template specialization!\n\n");
static_assert(std::is_trivially_copyable<T>::value,
"Cannot serialize a class that is not trivially copyable!\nWrite a custom "
"dataStore() template specialization!\n\n");
#endif
// Moose::out<<"Generic dataStore"<<std::endl;
stream.write((char *)&v, sizeof(v));
mooseAssert(!stream.bad(), "Failed to store");
}
template <typename T>
inline void
dataStore(std::ostream & /*stream*/, T *& /*v*/, void * /*context*/)
{
mooseError("Attempting to store a raw pointer type: \"",
demangle(typeid(T).name()),
" *\" as restartable data!\nWrite a custom dataStore() template specialization!\n\n");
}
void dataStore(std::ostream & stream, Point & p, void * context);
template <typename T, typename U>
inline void
dataStore(std::ostream & stream, std::pair<T, U> & p, void * context)
{
storeHelper(stream, p.first, context);
storeHelper(stream, p.second, context);
}
template <typename T>
inline void
dataStore(std::ostream & stream, std::vector<T> & v, void * context)
{
// First store the size of the vector
unsigned int size = v.size();
dataStore(stream, size, nullptr);
for (unsigned int i = 0; i < size; i++)
storeHelper(stream, v[i], context);
}
template <typename T>
inline void
dataStore(std::ostream & stream, std::shared_ptr<T> & v, void * context)
{
T * tmp = v.get();
storeHelper(stream, tmp, context);
}
template <typename T>
inline void
dataStore(std::ostream & stream, std::unique_ptr<T> & v, void * context)
{
T * tmp = v.get();
storeHelper(stream, tmp, context);
}
template <typename T>
inline void
dataStore(std::ostream & stream, std::set<T> & s, void * context)
{
// First store the size of the set
unsigned int size = s.size();
dataStore(stream, size, nullptr);
typename std::set<T>::iterator it = s.begin();
typename std::set<T>::iterator end = s.end();
for (; it != end; ++it)
{
T & x = const_cast<T &>(*it);
storeHelper(stream, x, context);
}
}
template <typename T>
inline void
dataStore(std::ostream & stream, std::list<T> & l, void * context)
{
// First store the size of the set
unsigned int size = l.size();
dataStore(stream, size, nullptr);
typename std::list<T>::iterator it = l.begin();
typename std::list<T>::iterator end = l.end();
for (; it != end; ++it)
{
T & x = const_cast<T &>(*it);
storeHelper(stream, x, context);
}
}
template <typename T>
inline void
dataStore(std::ostream & stream, std::deque<T> & l, void * context)
{
// First store the size of the container
unsigned int size = l.size();
dataStore(stream, size, nullptr);
typename std::deque<T>::iterator it = l.begin();
typename std::deque<T>::iterator end = l.end();
for (; it != end; ++it)
{
T & x = const_cast<T &>(*it);
storeHelper(stream, x, context);
}
}
template <typename T, typename U>
inline void
dataStore(std::ostream & stream, std::map<T, U> & m, void * context)
{
// First store the size of the map
unsigned int size = m.size();
dataStore(stream, size, nullptr);
typename std::map<T, U>::iterator it = m.begin();
typename std::map<T, U>::iterator end = m.end();
for (; it != end; ++it)
{
T & key = const_cast<T &>(it->first);
storeHelper(stream, key, context);
storeHelper(stream, it->second, context);
}
}
template <typename T, typename U>
inline void
dataStore(std::ostream & stream, std::unordered_map<T, U> & m, void * context)
{
// First store the size of the map
unsigned int size = m.size();
dataStore(stream, size, nullptr);
typename std::unordered_map<T, U>::iterator it = m.begin();
typename std::unordered_map<T, U>::iterator end = m.end();
for (; it != end; ++it)
{
T & key = const_cast<T &>(it->first);
storeHelper(stream, key, context);
storeHelper(stream, it->second, context);
}
}
template <typename T>
inline void
dataStore(std::ostream & stream, std::unordered_set<T> & s, void * context)
{
// First store the size of the set
std::size_t size = s.size();
dataStore(stream, size, nullptr);
for (auto & element : s)
dataStore(stream, element, context);
}
template <typename T>
inline void
dataStore(std::ostream & stream, std::optional<T> & m, void * context)
{
bool has_value = m.has_value();
dataStore(stream, has_value, nullptr);
if (has_value)
storeHelper(stream, *m, context);
}
template <typename T, typename U>
inline void
dataStore(std::ostream & stream, HashMap<T, U> & m, void * context)
{
// First store the size of the map
unsigned int size = m.size();
dataStore(stream, size, nullptr);
typename HashMap<T, U>::iterator it = m.begin();
typename HashMap<T, U>::iterator end = m.end();
for (; it != end; ++it)
{
T & key = const_cast<T &>(it->first);
storeHelper(stream, key, context);
storeHelper(stream, it->second, context);
}
}
// Specializations (defined in .C)
template <>
void dataStore(std::ostream & stream, Real & v, void * context);
template <>
void dataStore(std::ostream & stream, std::string & v, void * context);
template <>
void dataStore(std::ostream & stream, VariableName & v, void * context);
template <>
void dataStore(std::ostream & stream, UserObjectName & v, void * context);
template <>
void dataStore(std::ostream & stream, bool & v, void * context);
// Vectors of bools are special
// https://en.wikipedia.org/w/index.php?title=Sequence_container_(C%2B%2B)&oldid=767869909#Specialization_for_bool
template <>
void dataStore(std::ostream & stream, std::vector<bool> & v, void * context);
template <>
void dataStore(std::ostream & stream, const Elem *& e, void * context);
template <>
void dataStore(std::ostream & stream, const Node *& n, void * context);
template <>
void dataStore(std::ostream & stream, Elem *& e, void * context);
template <>
void dataStore(std::ostream & stream, Node *& n, void * context);
template <>
void dataStore(std::ostream & stream, std::stringstream & s, void * context);
template <>
void dataStore(std::ostream & stream, ADReal & dn, void * context);
template <>
void dataStore(std::ostream & stream, RealEigenVector & v, void * context);
template <>
void dataStore(std::ostream & stream, RealEigenMatrix & v, void * context);
template <>
void dataStore(std::ostream & stream, libMesh::Parameters & p, void * context);
template <>
/**
* Stores an owned numeric vector.
*
* This should be used in lieu of the NumericVector<Number> & implementation
* when the vector may not necessarily be initialized yet on the loading of
* the data. It stores the partitioning (total and local number of entries).
*
* Requirements: the unique_ptr must exist (cannot be null), the vector
* cannot be ghosted, and the provided context must be the Communicator.
*/
void dataStore(std::ostream & stream,
std::unique_ptr<libMesh::NumericVector<Number>> & v,
void * context);
template <std::size_t N>
inline void
dataStore(std::ostream & stream, std::array<ADReal, N> & dn, void * context)
{
for (std::size_t i = 0; i < N; ++i)
dataStore(stream, dn[i], context);
}
template <std::size_t N>
inline void
dataStore(std::ostream & stream, ADReal (&dn)[N], void * context)
{
for (std::size_t i = 0; i < N; ++i)
dataStore(stream, dn[i], context);
}
template <typename T>
void
dataStore(std::ostream & stream, NumericVector<T> & v, void * context)
{
v.close();
numeric_index_type size = v.local_size();
for (numeric_index_type i = v.first_local_index(); i < v.first_local_index() + size; i++)
{
T r = v(i);
dataStore(stream, r, context);
}
}
template <>
void dataStore(std::ostream & stream, Vec & v, void * context);
template <typename T>
void
dataStore(std::ostream & stream, DenseVector<T> & v, void * context)
{
unsigned int m = v.size();
dataStore(stream, m, nullptr);
for (unsigned int i = 0; i < v.size(); i++)
{
T r = v(i);
dataStore(stream, r, context);
}
}
template <typename T>
void dataStore(std::ostream & stream, TensorValue<T> & v, void * context);
template <typename T>
void dataStore(std::ostream & stream, DenseMatrix<T> & v, void * context);
template <typename T>
void dataStore(std::ostream & stream, VectorValue<T> & v, void * context);
template <typename T>
void
dataStore(std::ostream & stream, RankTwoTensorTempl<T> & rtt, void * context)
{
dataStore(stream, rtt._coords, context);
}
template <typename T>
void
dataStore(std::ostream & stream, RankThreeTensorTempl<T> & rtt, void * context)
{
dataStore(stream, rtt._vals, context);
}
template <typename T>
void
dataStore(std::ostream & stream, RankFourTensorTempl<T> & rft, void * context)
{
dataStore(stream, rft._vals, context);
}
template <typename T>
void
dataStore(std::ostream & stream, SymmetricRankTwoTensorTempl<T> & srtt, void * context)
{
dataStore(stream, srtt._vals, context);
}
template <typename T>
void
dataStore(std::ostream & stream, SymmetricRankFourTensorTempl<T> & srft, void * context)
{
dataStore(stream, srft._vals, context);
}
template <typename T>
void
dataStore(std::ostream & stream, ColumnMajorMatrixTempl<T> & cmm, void * context)
{
dataStore(stream, cmm._values, context);
}
// DO NOT MODIFY THE NEXT LINE - It is used by MOOSEDocs
// *************** Global Load Declarations *****************
template <typename T>
inline void
dataLoad(std::istream & stream, T & v, void * /*context*/)
{
stream.read((char *)&v, sizeof(v));
mooseAssert(!stream.bad(), "Failed to load");
}
template <typename T>
void
dataLoad(std::istream & /*stream*/, T *& /*v*/, void * /*context*/)
{
mooseError("Attempting to load a raw pointer type: \"",
demangle(typeid(T).name()),
" *\" as restartable data!\nWrite a custom dataLoad() template specialization!\n\n");
}
template <typename T, typename U>
inline void
dataLoad(std::istream & stream, std::pair<T, U> & p, void * context)
{
loadHelper(stream, p.first, context);
loadHelper(stream, p.second, context);
}
template <typename T>
inline void
dataLoad(std::istream & stream, std::vector<T> & v, void * context)
{
// First read the size of the vector
unsigned int size = 0;
dataLoad(stream, size, nullptr);
v.resize(size);
for (unsigned int i = 0; i < size; i++)
loadHelper(stream, v[i], context);
}
template <typename T>
inline void
dataLoad(std::istream & stream, std::shared_ptr<T> & v, void * context)
{
T * tmp = v.get();
loadHelper(stream, tmp, context);
}
template <typename T>
inline void
dataLoad(std::istream & stream, std::unique_ptr<T> & v, void * context)
{
T * tmp = v.get();
loadHelper(stream, tmp, context);
}
template <typename T>
inline void
dataLoad(std::istream & stream, std::set<T> & s, void * context)
{
// First read the size of the set
unsigned int size = 0;
dataLoad(stream, size, nullptr);
for (unsigned int i = 0; i < size; i++)
{
T data;
loadHelper(stream, data, context);
s.insert(std::move(data));
}
}
template <typename T>
inline void
dataLoad(std::istream & stream, std::list<T> & l, void * context)
{
// First read the size of the set
unsigned int size = 0;
dataLoad(stream, size, nullptr);
for (unsigned int i = 0; i < size; i++)
{
T data;
loadHelper(stream, data, context);
l.push_back(std::move(data));
}
}
template <typename T>
inline void
dataLoad(std::istream & stream, std::deque<T> & l, void * context)
{
// First read the size of the container
unsigned int size = 0;
dataLoad(stream, size, nullptr);
for (unsigned int i = 0; i < size; i++)
{
T data;
loadHelper(stream, data, context);
l.push_back(std::move(data));
}
}
template <typename T, typename U>
inline void
dataLoad(std::istream & stream, std::map<T, U> & m, void * context)
{
m.clear();
// First read the size of the map
unsigned int size = 0;
dataLoad(stream, size, nullptr);
for (unsigned int i = 0; i < size; i++)
{
T key;
loadHelper(stream, key, context);
U & value = m[key];
loadHelper(stream, value, context);
}
}
template <typename T, typename U>
inline void
dataLoad(std::istream & stream, std::unordered_map<T, U> & m, void * context)
{
m.clear();
// First read the size of the map
unsigned int size = 0;
dataLoad(stream, size, nullptr);
for (unsigned int i = 0; i < size; i++)
{
T key;
loadHelper(stream, key, context);
U & value = m[key];
loadHelper(stream, value, context);
}
}
template <typename T>
inline void
dataLoad(std::istream & stream, std::unordered_set<T> & s, void * context)
{
s.clear();
// First read the size of the set
std::size_t size = 0;
dataLoad(stream, size, nullptr);
s.reserve(size);
for (std::size_t i = 0; i < size; i++)
{
T element;
dataLoad(stream, element, context);
s.insert(element);
}
}
template <typename T>
inline void
dataLoad(std::istream & stream, std::optional<T> & m, void * context)
{
bool has_value;
dataLoad(stream, has_value, nullptr);
if (has_value)
{
m = T{};
loadHelper(stream, *m, context);
}
else
m.reset();
}
template <typename T, typename U>
inline void
dataLoad(std::istream & stream, HashMap<T, U> & m, void * context)
{
// First read the size of the map
unsigned int size = 0;
dataLoad(stream, size, nullptr);
for (unsigned int i = 0; i < size; i++)
{
T key;
loadHelper(stream, key, context);
U & value = m[key];
loadHelper(stream, value, context);
}
}
// Specializations (defined in .C)
template <>
void dataLoad(std::istream & stream, Real & v, void * /*context*/);
template <>
void dataLoad(std::istream & stream, std::string & v, void * /*context*/);
template <>
void dataLoad(std::istream & stream, VariableName & v, void * /*context*/);
template <>
void dataLoad(std::istream & stream, UserObjectName & v, void * /*context*/);
template <>
void dataLoad(std::istream & stream, bool & v, void * /*context*/);
// Vectors of bools are special
// https://en.wikipedia.org/w/index.php?title=Sequence_container_(C%2B%2B)&oldid=767869909#Specialization_for_bool
template <>
void dataLoad(std::istream & stream, std::vector<bool> & v, void * /*context*/);
template <>
void dataLoad(std::istream & stream, const Elem *& e, void * context);
template <>
void dataLoad(std::istream & stream, const Node *& e, void * context);
template <>
void dataLoad(std::istream & stream, Elem *& e, void * context);
template <>
void dataLoad(std::istream & stream, Node *& e, void * context);
template <>
void dataLoad(std::istream & stream, std::stringstream & s, void * context);
template <>
void dataLoad(std::istream & stream, ADReal & dn, void * context);
template <>
void dataLoad(std::istream & stream, RealEigenVector & v, void * context);
template <>
void dataLoad(std::istream & stream, RealEigenMatrix & v, void * context);
template <>
void dataLoad(std::istream & stream, libMesh::Parameters & p, void * context);
template <>
/**
* Loads an owned numeric vector.
*
* This is used in lieu of the NumericVector<double> & implementation when
* the vector may not necessarily be initialized yet on the loading of the data.
*
* If \p is not null, it must have the same global and local sizes that it
* was stored with. In this case, the data is simply filled into the vector.
*
* If \p is null, it will be constructed with the type (currently just a
* PetscVector) stored and initialized with the global and local sizes stored.
* The data will then be filled after initialization.
*
* Requirements: the vector cannot be ghosted, the provided context must be
* the Communicator, and if \p v is initialized, it must have the same global
* and local sizes that the vector was stored with.
*/
void dataLoad(std::istream & stream,
std::unique_ptr<libMesh::NumericVector<Number>> & v,
void * context);
template <std::size_t N>
inline void
dataLoad(std::istream & stream, std::array<ADReal, N> & dn, void * context)
{
for (std::size_t i = 0; i < N; ++i)
dataLoad(stream, dn[i], context);
}
template <std::size_t N>
inline void
dataLoad(std::istream & stream, ADReal (&dn)[N], void * context)
{
for (std::size_t i = 0; i < N; ++i)
dataLoad(stream, dn[i], context);
}
template <typename T>
void
dataLoad(std::istream & stream, NumericVector<T> & v, void * context)
{
numeric_index_type size = v.local_size();
for (numeric_index_type i = v.first_local_index(); i < v.first_local_index() + size; i++)
{
T r = 0;
dataLoad(stream, r, context);
v.set(i, r);
}
v.close();
}
template <>
void dataLoad(std::istream & stream, Vec & v, void * context);
template <typename T>
void
dataLoad(std::istream & stream, DenseVector<T> & v, void * context)
{
unsigned int n = 0;
dataLoad(stream, n, nullptr);
v.resize(n);
for (unsigned int i = 0; i < n; i++)
{
T r = 0;
dataLoad(stream, r, context);
v(i) = r;
}
}
template <typename T>
void dataLoad(std::istream & stream, TensorValue<T> & v, void * context);
template <typename T>
void dataLoad(std::istream & stream, DenseMatrix<T> & v, void * context);
template <typename T>
void dataLoad(std::istream & stream, VectorValue<T> & v, void * context);
template <typename T>
void
dataLoad(std::istream & stream, RankTwoTensorTempl<T> & rtt, void * context)
{
dataLoad(stream, rtt._coords, context);
}
template <typename T>
void
dataLoad(std::istream & stream, RankThreeTensorTempl<T> & rtt, void * context)
{
dataLoad(stream, rtt._vals, context);
}
template <typename T>
void
dataLoad(std::istream & stream, RankFourTensorTempl<T> & rft, void * context)
{
dataLoad(stream, rft._vals, context);
}
template <typename T>
void
dataLoad(std::istream & stream, SymmetricRankTwoTensorTempl<T> & rtt, void * context)
{
dataLoad(stream, rtt._vals, context);
}
template <typename T>
void
dataLoad(std::istream & stream, SymmetricRankFourTensorTempl<T> & rft, void * context)
{
dataLoad(stream, rft._vals, context);
}
template <typename T>
void
dataLoad(std::istream & stream, ColumnMajorMatrixTempl<T> & cmm, void * context)
{
dataLoad(stream, cmm._values, context);
}
// Scalar Helper Function
template <typename P>
inline void
storeHelper(std::ostream & stream, P & data, void * context)
{
dataStore(stream, data, context);
}
// Vector Helper Function
template <typename P>
inline void
storeHelper(std::ostream & stream, std::vector<P> & data, void * context)
{
dataStore(stream, data, context);
}
// std::shared_ptr Helper Function
template <typename P>
inline void
storeHelper(std::ostream & stream, std::shared_ptr<P> & data, void * context)
{
dataStore(stream, data, context);
}
// std::unique Helper Function
template <typename P>
inline void
storeHelper(std::ostream & stream, std::unique_ptr<P> & data, void * context)
{
dataStore(stream, data, context);
}
// Set Helper Function
template <typename P>
inline void
storeHelper(std::ostream & stream, std::set<P> & data, void * context)
{
dataStore(stream, data, context);
}
// Map Helper Function
template <typename P, typename Q>
inline void
storeHelper(std::ostream & stream, std::map<P, Q> & data, void * context)
{
dataStore(stream, data, context);
}
// Unordered_map Helper Function
template <typename P, typename Q>
inline void
storeHelper(std::ostream & stream, std::unordered_map<P, Q> & data, void * context)
{
dataStore(stream, data, context);
}
// Optional Helper Function
template <typename P>
inline void
storeHelper(std::ostream & stream, std::optional<P> & data, void * context)
{
dataStore(stream, data, context);
}
// HashMap Helper Function
template <typename P, typename Q>
inline void
storeHelper(std::ostream & stream, HashMap<P, Q> & data, void * context)
{
dataStore(stream, data, context);
}
/**
* UniqueStorage helper routine
*
* The data within the UniqueStorage object cannot be null. The helper
* for unique_ptr<T> is called to store the data.
*/
template <typename T>
inline void
storeHelper(std::ostream & stream, UniqueStorage<T> & data, void * context)
{
std::size_t size = data.size();
dataStore(stream, size, nullptr);
for (const auto i : index_range(data))
{
mooseAssert(data.hasValue(i), "Data doesn't have a value");
storeHelper(stream, data.pointerValue(i), context);
}
}
// Scalar Helper Function
template <typename P>
inline void
loadHelper(std::istream & stream, P & data, void * context)
{
dataLoad(stream, data, context);
}
// Vector Helper Function
template <typename P>
inline void
loadHelper(std::istream & stream, std::vector<P> & data, void * context)
{
dataLoad(stream, data, context);
}
// std::shared_ptr Helper Function
template <typename P>
inline void
loadHelper(std::istream & stream, std::shared_ptr<P> & data, void * context)
{
dataLoad(stream, data, context);
}
// Unique Pointer Helper Function
template <typename P>
inline void
loadHelper(std::istream & stream, std::unique_ptr<P> & data, void * context)
{
dataLoad(stream, data, context);
}
// Set Helper Function
template <typename P>
inline void
loadHelper(std::istream & stream, std::set<P> & data, void * context)
{
dataLoad(stream, data, context);
}
// Map Helper Function
template <typename P, typename Q>
inline void
loadHelper(std::istream & stream, std::map<P, Q> & data, void * context)
{
dataLoad(stream, data, context);
}
// Unordered_map Helper Function
template <typename P, typename Q>
inline void
loadHelper(std::istream & stream, std::unordered_map<P, Q> & data, void * context)
{
dataLoad(stream, data, context);
}
// Optional Helper Function
template <typename P>
inline void
loadHelper(std::istream & stream, std::optional<P> & data, void * context)
{
dataLoad(stream, data, context);
}
// HashMap Helper Function
template <typename P, typename Q>
inline void
loadHelper(std::istream & stream, HashMap<P, Q> & data, void * context)
{
dataLoad(stream, data, context);
}
/**
* UniqueStorage Helper Function
*
* The unique_ptr<T> loader is called to load the data. That is,
* you will likely need a specialization of unique_ptr<T> that will
* appropriately construct and then fill the piece of data.
*/
template <typename T>
inline void
loadHelper(std::istream & stream, UniqueStorage<T> & data, void * context)
{
std::size_t size;
dataLoad(stream, size, nullptr);
data.resize(size);
for (const auto i : index_range(data))
loadHelper(stream, data.pointerValue(i), context);
}
void dataLoad(std::istream & stream, Point & p, void * context);
#ifndef TIMPI_HAVE_STRING_PACKING
/**
* The following methods are specializations for using the libMesh::Parallel::packed_range_*
* routines
* for std::strings. These are here because the dataLoad/dataStore routines create raw string
* buffers that can be communicated in a standard way using packed ranges.
*/
namespace libMesh
{
namespace Parallel
{
template <typename T>
class Packing<std::basic_string<T>>
{
public:
static const unsigned int size_bytes = 4;
typedef T buffer_type;
static unsigned int get_string_len(typename std::vector<T>::const_iterator in)
{
unsigned int string_len = reinterpret_cast<const unsigned char &>(in[size_bytes - 1]);
for (signed int i = size_bytes - 2; i >= 0; --i)
{
string_len *= 256;
string_len += reinterpret_cast<const unsigned char &>(in[i]);
}
return string_len;
}
static unsigned int packed_size(typename std::vector<T>::const_iterator in)
{
return get_string_len(in) + size_bytes;
}
static unsigned int packable_size(const std::basic_string<T> & s, const void *)
{
return s.size() + size_bytes;
}
template <typename Iter>
static void pack(const std::basic_string<T> & b, Iter data_out, const void *)
{
unsigned int string_len = b.size();
for (unsigned int i = 0; i != size_bytes; ++i)
{
*data_out++ = (string_len % 256);
string_len /= 256;
}
std::copy(b.begin(), b.end(), data_out);
}
static std::basic_string<T> unpack(typename std::vector<T>::const_iterator in, void *)
{
unsigned int string_len = get_string_len(in);
std::ostringstream oss;
for (unsigned int i = 0; i < string_len; ++i)
oss << reinterpret_cast<const unsigned char &>(in[i + size_bytes]);
in += size_bytes + string_len;
return oss.str();
}
};
} // namespace Parallel
} // namespace libMesh
#endif