How to use Serialization

From KratosWiki
Jump to: navigation, search

The serialization consist 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 restart file and retrieve it afterward on must add the necessary component used by serialization. In the following section we will specify the necessary steps for making an object serializable in Kratos.

Contents

Preparing a Class for Serialization

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 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
   private:
     ///@name Static Member Variables 
     ///@{ 
       
       
     ///@} 
     ///@name Member Variables 
     ///@{ 
       
     ///@}
     ///@name Serialization
     ///@{
 
     friend class Serializer;

     ///@} 
     ///@name Private Operators
     ///@{ 
  • If the class dos not provide a default constructor (an empty constructor) you have to provide one in the serialization part as follow:
     ///@}
     ///@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 );
     ...

Serialization of a Non-polymorphic Class

A non-polymorphic class is the one which is not belong to any inheritance. In other word it means a class which is not derived from other classes and is not the base for the other classes. Making the non-polymorphic classes consist in 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 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 save 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
     ///@{

Warn_icon.gif Warning. Please, note that:

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!

Serialization of a Polymorphic Class

Serializing of a polymorphic class is similar to the non-polymorphic one with following two additional steps:

Warn_icon.gif Warning. Please, note that:

Saving the name of the class IS NOT NECESSARY anymore. please remove it from the old codes because it will prevent them to be serialized.


Warn_icon.gif Warning. Please, note that:

The default constructor mentioned in non-Polymorphic part have to be added in protected section to be able to be accesed from heritaed 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 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 is necessary.

Debugging

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 options are:

  • SERIALIZER_NO_TRACE which disables the tracing. This is the default option and won't write any additional information to restart file to minimize the size of the file.
  • SERIALIZER_TRACE_ERROR Which 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 <module>
   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 remarks the tags correctly loaded. VERY VERBOSE!!

Examples

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 Serialzer the 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 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 follow:

  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
Personal tools
Categories