35. Serialization

AGX Dynamics comes with a serialization system. This allows for a simulation to be stored on disk for later retrieval. Together with a callback system at restore, a stored simulation can be recreated together with custom references. This is very handy when debugging a system for example. If a problem occurs, a serialization of the simulation might be informative during debugging to locate any potential problems in the setup of the simulation. We recommend that a serialization is attached to reported tickets so that Algoryx can use that when analyzing the problem.

The serialization system will collect any references that a serialized object has. Meaning that serializing a rigid body will also store any geometries, shapes, materials that is associated to this rigid body. So it is not in general possible to do a partial store.

Serialization can be done to an ASCII (XML) file “.aagx”, or a binary file “.agx”. The ASCII format is not suitable for very large scenarios with huge height fields for example due to the size of the file. The binary file format is much faster and more compact and can in many case be written during runtime without a major effect on performance.

35.1. Universally unique identifier (UUID)

Each object derived from the base class agxStream::Serializable will inherit the property of a uuid. This is true for RigidBody, Geometry, Constraint, agxWire::Wire and many other classes.

When a simulation is stored in the serialization system, this uuid will be stored together will all the serialized objects. During restore, this uuid can be retrieved and used to identify objects. For an example, see 35.5.

35.2. Storing a simulation

To store an existing simulation there exists several options depending if you want to store it to memory or a file on disk. The simplest way is to use the writeFile function:

#include <agxIO/ReaderWriter.h>
// Create a simulation
agxSDK::SimulationRef simulation = new agxSDK::Simulation;
// Populate the simulation with bodies, geometries etc.
populateSimulation( simulation );
// Write to a file
if (!agxIO::writeFile("simulation.agx", simulation))
  error(...)

The file on disk will contain everything related to the simulation:

  • Rigid bodies

  • Geometries

  • Shapes

  • Constraints

  • Wires

  • GravityField

  • Time step

  • Current simulation time

  • Collision groups

The serialization will contain the current state of the whole simulation including velocities, tension, constraint violations etc. This means that restoring the simulation from the file will lead to an identical state as when it was stored.

Notice that restoring multiple serializations to a simulation might give you an unpredicted result. For example if one simulation disables two collision groups and another enables them, it will be the last restored simulation that dictates the result. The same goes for time step, gravity fields etc…

It is possible to filter out some of the data when performing a restore with the agxSDK::Simulation::ReadSelectionMask enum:

enum ReadSelectionMask {
  READ_NONE = 0x0,      ///<! Select to read none of the items below
  READ_TIMESTEP = 0x1,  ///<! Select to read and restore the TimeStep of the Simulation.
  READ_TIMESTAMP = 0x2, ///<! Select to read the TimeStamp (current time of the simulation)
  READ_GRAVITY = 0x4,   ///<! Select to read and restore the Gravity model of the simulation.
  READ_ALL = READ_TIMESTEP + READ_TIMESTAMP + READ_GRAVITY,
  READ_DEFAULT = READ_TIMESTEP /* + READ_TIMESTAMP */ + READ_GRAVITY
};
// Do not restore timestep, timestamp nor gravity.
agxIO::readFile("mystoredsimulation.agx", simulation, 0L, agxSDK::Simulation::READ_NONE);

Notice that the TIMESTAMP (current time) is not restored by default. So if you are restoring to an existing simulation which has been simulated for a while, the current time will not be affected.

35.3. Serialization to/from memory

To serialize a simulation to memory, first create a stream and then use the Simulation::write method:

// Create a memory stream, make sure it is in binary format to avoid NL/CR problems
std::stringstream os(std::ios_base::out | std::ios_base::binary);

// Now write the simulation to the stream. The second boolean argument determines if the
// serialization format should be binary or ASCII. Use ASCII for faster
// process and smaller memory footprint.
bool binaryFormat = true;
simulation->write(os, binaryFormat); // Serialization data is stored into the stream

To restore from memory, use an input stream and the Simulation::read method. In this case we copy data from the output stream to a new input stream, but it could just as easily been read from disk or any other location:

// Restore the simulation from memory
os.seekg(0);

// We need to get the data into a istream to be able to read from it
std::stringstream is(std::ios_base::in | std::ios_base::binary);
is.str(os.str());

// Now read from the binary stream.
simulation->read(is, binaryFormat);

35.4. Continuous serialization to disk

It is also possible to continuously serialize a simulation to disk during runtime. This might be helpful when debugging a problematic simulation. This will however have a substantial effect on performance, depending on the size of the simulation. For example, a large height field contains a lot of data per frame, hence it will severely slow down your simulation.

To enable this frame by frame simulation, you can use the API:

// Enable the serializer
simulation->getSerializer()->setEnable(true);
// Specify an interval for writing a frame
simulation->getSerializer()->setInterval(1);
simulation->getSerializer()->setFilename("frames.agx"); // 00001_frames.agx, 00002_frames.agx

Or change the Enabled value in the configuration file <agx-dir>/data/cfg/settings.cfg::

SimulationSerializer
{
  Enabled 1 // If ==1 then for each frame a file will be dumped with complete simulation content
  Mode 1 // When to write data: 0-PRE_COLLIDE, 1-PRE_STEP, 2-POST_STEP
  Interval 0.03333 // interval in seconds
  Filename "agx.agx" //.aagx for ascii, .agx for binary (faster/smaller)
}

With the settings above, a file named 00001_agx.agx, 00002_agx.agx will be written to disk with an interval of 33ms (30 Hz). These files can then be packed and set to Algoryx for further analysis regarding any issue that might have surfaced during the simulation.

35.5. Listening to restore events

It is possible to listen to a restore process and get callbacks when an object is being restored. This allows for custom connection between rigid bodies, geometries, constraints wires etc. and your own system.

In tutorial_io.cpp there is an example of how to associate rendering information for each restored geometry. Notice also that each stored object will have a uuid which is also restored. This can be used to store a reference in form of a text string (uuid, usually in the form of "8d276495-19b6-44d8-84ba-5c1830ee97a4") which later during the restore can be used to uniquely identify a restored object.

So if one has a GUI system with representations of a rigid body, the GUI system could store the uuid of the rigid body in its own file storage system. When an AGX simulation is serialized to disk, this uuid is also stored together with the rigid body.

Later at restore, the GUI representation of a rigid body can be created and the reference to the rigid body can be established based on this uuid.