-
Notifications
You must be signed in to change notification settings - Fork 247
How to use Serialization
The serialization consists of storing the state of an object into a storage format like data file or memory buffer and also retrieving the object from such a media. The idea of serialization is based on saving all object's data consecutively in the file or buffer and then load it in the same order. In Kratos a serialization mechanism is used for creating the restart file. So for storing an object into a restart file and retrieving it afterward one must add the necessary components used by serialization. In the following section we will specify the necessary steps for making an object serializable in Kratos.
- Preparing a Class for Serialization
- Serialization of a Non-polymorphic Class
- Serialization of a Polymorphic Class
- Debugging
- Examples
The following steps are necessary in order to prepare a class for serialization:
- Including the
includes/serializer.h
// Project includes #include "includes/define.h" #include "includes/serializer.h"
- Adding a doxygen statement for documentation of the serialization methods by adding the following comment in the private section of the class: (A good option is after the Member Variables section)
private: ///@name Static Member Variables ///@{ ///@} ///@name Member Variables ///@{ ///@} ///@name Serialization ///@{ ///@} ///@name Private Operators ///@{
- making the Serializer a friend of the class by adding a friend statement in the private part of the class
private: ///@name Static Member Variables ///@{ ///@} ///@name Member Variables ///@{ ///@} ///@name Serialization ///@{ friend class Serializer; ///@} ///@name Private Operators ///@{
- If the class does not provide a default constructor (an empty constructor) you have to provide one in the serialization part as follows:
///@} ///@name Serialization ///@{ friend class Serializer; // A private default constructor necessary for serialization ClassName() : BaseClassName() { } ///@} ///@name Private Operators ///@{
- Adding the corresponding declarations to the the
own_application.h
:
///@} ///@name Member Variables ///@{ ... const OwnConstitutive mOwnConstitutive; ...
- Finally include the following declarations to the the
own_application.cpp
:
KratosOwnApplication::KratosOwnApplication(): ... mOwnConstitutive(); ...
- And:
void KratosOwnApplication::Register(){ ... Serializer::Register( "OwnConstitutive", mOwnConstitutive ); ...
A non-polymorphic class is a class that does not belong to any inheritance. In other words it means a class that is not derived from other classes and is not the base for other classes. Making non-polymorphic classes serializable consists in the following steps:
- The first step is adding the serialization save and load methods as follow:
///@} ///@name Serialization ///@{ friend class Serializer; // A private default constructor necessary for serialization ClassName() : BaseClassName() { } virtual void save(Serializer& rSerializer) const { } virtual void load(Serializer& rSerializer) { } ///@} ///@name Private Operators ///@{
- Now the class is ready for adding the serialization statements in order to serialize its data. There are two overloaded methods of Serializer which are in charge of saving and loading the internal data of the class:
Serializer::save(std::string rTag, TDataType const& Data) const Serializer::load(std::string rTag, TDataType& Data)
Where the Tag string is the tag given to the saved or loaded data. This tag is only for text format and debugging purpose, and actually won't be written in binary format buffers and files. Here is an example of using these methods in a class with two member variables:
///@} ///@name Member Variables ///@{ int mMyInteger; Vector mMyVector; ///@} ///@name Serialization ///@{ friend class Serializer; // A private default constructor necessary for serialization ClassName() { } virtual void save(Serializer& rSerializer) const { rSerializer.save("My Integer", mMyInteger); rSerializer.save("My Vector", mMyVector); } virtual void load(Serializer& rSerializer) { rSerializer.load("My Integer", mMyInteger); rSerializer.load("My Vector", mMyVector); } ///@} ///@name Private Operators ///@{
It is VERY IMPORTANT to have the SAME SEQUENCE of variables in the save and load method. Altering this order results in corrupted loaded object or even crash of the program!
Serializing of a polymorphic class is similar to the non-polymorphic one with the following two additional steps:
Saving the name of the class IS NOT NECESSARY anymore. Please remove it from the old codes because it will prevent them from being serialized.
The default constructor mentioned in the non-Polymorphic part has to be added in protected section to be able to be accessed from inheriting classes.
- In general it is necessary to call the base class save and load in the derived class. This can be done using the following defined macro:
KRATOS_SERIALIZE_SAVE_BASE_CLASS(Serializer, BaseType) KRATOS_SERIALIZE_LOAD_BASE_CLASS(Serializer, BaseType)
Here is an example of use for the TotalLagrangian
element derived from Element
:
virtual void save(Serializer& rSerializer) const { KRATOS_SERIALIZE_SAVE_BASE_CLASS(rSerializer, Element ); } virtual void load(Serializer& rSerializer) { KRATOS_SERIALIZE_LOAD_BASE_CLASS(rSerializer, Element ); }
- The class must be registered in serializer using the Register() method. For elements and conditions the registeration is done via KRATOS_REGISTER_ELEMENT and KRATOS_REGISTER_CONDITION with the name of the class (NOT the given name respect to its geometry). Here is an example:
KRATOS_REGISTER_ELEMENT( "TotalLagrangian", mTotalLagrangian )
This is equivalent to write:
Serializer::Register("TotalLagrangian", mTotalLagrangian);
The above form can be used to register other polymorphic classes in Kratos if necessary.
There is a trace option which helps debugging the serialization. The tracing option can be passed as an additional parameter to the constructor. Here is an example:
serializer = Serializer("filename", SERIALIZER_TRACE_ERROR)
The three options are:
- SERIALIZER_NO_TRACE disables the tracing. This is the default option and won't write any additional information to the restart file in order to minimize the size of the file.
- SERIALIZER_TRACE_ERROR enables the tracing but only reports the errors. It will write the tags given in time of saving to the restart file and then in time of loading checks if the written one coincides with expected one. In case of error it will report it as follow:
File "cantilever3dstatic.py", line 96, in serializer.Load("StructureModelPart", loaded_model_part); ValueError: in bool Kratos::Serializer::load_trace_point(const std::string&) [ /home/pooyan/kratos/kratos/includes/serializer.h , Line 561 ] with subject : In ine 386 the trace tag is not the expected one: Tag found : Variables Tag given : Variables List
- SERIALIZER_TRACE_ALL also enables the tracing and saves tags to check them in loading. The only difference with SERIALIZER_TRACE_ERROR is the additional messages which remark the tags correctly loaded. VERY VERBOSE!!
As an example we serialize the Isotropic3D class which is derived from ConstitutiveLaw:
class Isotropic3D : public ConstitutiveLaw { public: /** * Default constructor. */ Isotropic3D(); /** * Destructor. */ virtual ~Isotropic3D(); /** * Operations */ //.... //.... private: /** * Member Variables */ double mE, mNU, mDE; Vector mInSituStress; Matrix mCtangent; Vector mCurrentStress; Vector mMaterialParameters; //.... //.... }; // Class Isotropic3D
Now we add the serialization comment block and make Serializer a friend of this class:
class Isotropic3D : public ConstitutiveLaw { public: /** * Default constructor. */ Isotropic3D(); /** * Destructor. */ virtual ~Isotropic3D(); /** * Operations */ //.... //.... private: /** * Member Variables */ double mE, mNU, mDE; Vector mInSituStress; Matrix mCtangent; Vector mCurrentStress; Vector mMaterialParameters; ///@} ///@name Serialization ///@{ friend class Serializer; //.... //.... }; // Class Isotropic3D
Then add the save and load methods with serializing the base classes
class Isotropic3D : public ConstitutiveLaw { public: /** * Default constructor. */ Isotropic3D(); /** * Destructor. */ virtual ~Isotropic3D(); /** * Operations */ //.... //.... private: /** * Member Variables */ double mE, mNU, mDE; Vector mInSituStress; Matrix mCtangent; Vector mCurrentStress; Vector mMaterialParameters; ///@} ///@name Serialization ///@{ friend class Serializer; virtual void save(Serializer& rSerializer) const { KRATOS_SERIALIZE_SAVE_BASE_CLASS(rSerializer, ConstitutiveLaw); } virtual void load(Serializer& rSerializer) { KRATOS_SERIALIZE_LOAD_BASE_CLASS(rSerializer, ConstitutiveLaw); } //.... //.... }; // Class Isotropic3D
And finally we load and save all the member variables of this class as follows:
class Isotropic3D : public ConstitutiveLaw { public: /** * Default constructor. */ Isotropic3D(); /** * Destructor. */ virtual ~Isotropic3D(); /** * Operations */ //.... //.... private: /** * Member Variables */ double mE, mNU, mDE; Vector mInSituStress; Matrix mCtangent; Vector mCurrentStress; Vector mMaterialParameters; ///@} ///@name Serialization ///@{ friend class Serializer; virtual void save(Serializer& rSerializer) const { KRATOS_SERIALIZE_SAVE_BASE_CLASS(rSerializer, ConstitutiveLaw); rSerializer.save("E",mE); rSerializer.save("NU",mNU); rSerializer.save("DE",mDE); rSerializer.save("InSituStress",mInSituStress); rSerializer.save("Ctangent",mCtangent); rSerializer.save("CurrentStress",mCurrentStress); rSerializer.save("MaterialParameters",mMaterialParameters); } virtual void load(Serializer& rSerializer) { KRATOS_SERIALIZE_LOAD_BASE_CLASS(rSerializer, ConstitutiveLaw); rSerializer.load("E",mE); rSerializer.load("NU",mNU); rSerializer.load("DE",mDE); rSerializer.load("InSituStress",mInSituStress); rSerializer.load("Ctangent",mCtangent); rSerializer.load("CurrentStress",mCurrentStress); rSerializer.load("MaterialParameters",mMaterialParameters); } //.... //.... }; // Class Isotropic3D
- Getting Kratos (Last compiled Release)
- Compiling Kratos
- Running an example from GiD
- Kratos input files and I/O
- Data management
- Solving strategies
- Manipulating solution values
- Multiphysics
- Video tutorials
- Style Guide
- Authorship of Kratos files
- Configure .gitignore
- How to configure clang-format
- How to use smart pointer in Kratos
- How to define adjoint elements and response functions
- Visibility and Exposure
- Namespaces and Static Classes
Kratos structure
Conventions
Solvers
Debugging, profiling and testing
- Compiling Kratos in debug mode
- Debugging Kratos using GDB
- Cross-debugging Kratos under Windows
- Debugging Kratos C++ under Windows
- Checking memory usage with Valgind
- Profiling Kratos with MAQAO
- Creating unitary tests
- Using ThreadSanitizer to detect OMP data race bugs
- Debugging Memory with ASAN
HOW TOs
- How to create applications
- Python Tutorials
- Kratos For Dummies (I)
- List of classes and variables accessible via python
- How to use Logger
- How to Create a New Application using cmake
- How to write a JSON configuration file
- How to Access DataBase
- How to use quaternions in Kratos
- How to do Mapping between nonmatching meshes
- How to use Clang-Tidy to automatically correct code
- How to use the Constitutive Law class
- How to use Serialization
- How to use GlobalPointerCommunicator
- How to use PointerMapCommunicator
- How to use the Geometry
- How to use processes for BCs
- How to use Parallel Utilities in futureproofing the code
- Porting to Pybind11 (LEGACY CODE)
- Porting to AMatrix
- How to use Cotire
- Applications: Python-modules
- How to run multiple cases using PyCOMPSs
- How to apply a function to a list of variables
- How to use Kratos Native sparse linear algebra
Utilities
Kratos API
Kratos Structural Mechanics API