HOWTO save and restore
This article is known to contain outdated information. If you know of correct information, please edit this article! Thank you. Copy-dumped from old wiki
The following is a (hopefully) current list of considerations and possible pitfalls when attempting to save and restore a simulation so that it arrives at the exact same results.
When restoring the simulation state, the following should be done:
- Reset each body's position - dBody[Get,Set]Position()
- Reset each body's quaternion - dBody[Get,Set]Quaternion() ODE stores rotation in quaternions, so don't save/restore in euler angles because it will have to convert to/from quaternions and you won't get a perfect restoration.
- Reset each body's linear velocity - dBody[Get,Set]LinearVel()
- Reset each body's angular velocity - dBody[Get,Set]AngularVel()
- In the quickstep solver, "warm starting" is enabled by default. This involves storing 6 dReal lambda values with each joint so that the previous solution can be applied towards achieving the next. These values must be stored and reset or warm starting disabled. There is no current method to retrieve or set these values, so one must be added manually. They are found at the bottom of the dxJoint struct in joint.h in the source. To disable warm starting, comment out the "#define WARM_STARTING" line in quickstep.cpp.
- Reset "desired velocity" and "FMax" parameters for motorized joints
- Reset the "enable" state of every body - If bodies are set to auto-disable, you may need to reset their associated variables (adis_timeleft,adis_stepsleft,etc) - there is no current api method for that.
- Remove contact joints created during the previous step
- You might want to assert that the force and torque accumulators are zero
- Make sure the rest of your controller/simulation is also reset
Notes:
- If completely remaking the sim, create all bodies and geoms in the same order as before and set them to their starting positions (not their stored target positions). Then add in joints. This way, joints will be attached to their corresponding bodies in the same way they were originally. After adding joints, reset bodies to their target state.
- The random seed affects the random number generator used by the stepfast and quickstep solvers and should always be reset via dRandSetSeed() before simulating. This can be set to some constant value at simulation time 0 and saved and restored between runs or re-seeded at each potential save/restore point with some function of the simulation time.
- When setting a body's quaternion value with dBodySetQuaternion(), the provided quaternion is normalized. Thus when re-plugging values obtained from the simulation, the stored values may vary by a bit or two due to floating point inaccuracies, thus slightly throwing off the simulation as compared to the original. To work around this, either re-plug all obtained values into the simulation at every possible save point (thus getting the same slightly modified values on every run including the original) or remove the dNormalize4() line in dBodySetQuaternion().
- In their present state, simple or hash spaces need slight modification to work consistently between runs. Currently, when a dxGeom is added to one of these spaces, it is placed on a list in the space. This list is sorted such that "dirty" geoms (ones needing bounding box updates or whatnot) are first in the list. Thus when a geom is dirtied, it is re-added to the list at the beginning. Thus if a simulation is run from frame 0 up to frame x, at frame x the geoms are all shuffled around from being dirtied many times up to that point, but if the simulation is recreated at frame x, the geoms appear on the list in the order they were just added. This means the order they are returned in for collision callbacks and other such things will be totally different and in the end the simulation can arrive at different results. A workaround is as follows: Remove the reordering code in dxSpace::dirty() in collision_space.cpp (the geom->spaceRemove() and geom->spaceAdd() lines). Next, modify dxSimpleSpace::cleanGeoms() and dxHashSpace::cleanGeoms() to scan through all geoms looking for dirty ones instead of stopping once it finds a non-dirty one (since dirty ones are no longer grouped at the beginning of the list).
- Currently, retrieving aMotor angles only returns correct values after a simulation step has been run. This can throw off simulations that set joint parameters based on these angles, since they will get different values after being restored to a given state than they would after originally arriving at that state through simulation. To return correct values, the angle computing code from amotorGetInfo1() in joint.cpp can be inserted into dJointGetAMotorAngle() to update the value every time.
- If you're saving values to a text file, you will probably need to write the floating-point values with additional digits to get sufficient precision (DBL_DIG + 2 has been reported to work)
- If you get really desperate, try compiling with -ffloat-store (gcc) or "Improve Floating Point Consistency" (MSVC). That's usually not it though.
- On the x86 architecture, if the default floating point unit is used (i.e. -mfpmath=387 for GCC) the resulting floating point operations get rounded unpredictably, effectively . The only reliable workaround is to use the SSE unit for floating point operations (i.e. -mfpmath=sse for GCC), meaning the binary will require at least a Pentium III to run. On the x86-64 architecture SSE is used by default by all compilers. A lengthy discussion on this hardware design problem can be seen on bug 323 from the GCC bug tracker.
- There's also an issue about Direct X autonomously changing the internal FPU accuracy, leading to inconsistent calculations. Direct3D by default changes the FPU to single precision mode at program startup and does not change it back to improve speed (This means that your double variables will behave like float). To disable this behaviour, pass the D3DCREATE_FPU_PRESERVE flag to the CreateDevice call. This might adversely affect D3D performance (not much though). Search the mailing list for details. More info here and here.