return haveCpuBondeds(fr) || haveRestraints(idef, fcd);
}
+namespace
+{
+
+/*! \brief Calculates all listed force interactions.
+ *
+ * Note that pbc_full is used only for position restraints, and is
+ * not initialized if there are none.
+ */
void calc_listed(const t_commrec* cr,
const gmx_multisim_t* ms,
struct gmx_wallcycle* wcycle,
const InteractionDefinitions& idef,
const rvec x[],
+ ArrayRef<const gmx::RVec> xWholeMolecules,
history_t* hist,
gmx::ForceOutputs* forceOutputs,
const t_forcerec* fr,
/* Do pre force calculation stuff which might require communication */
if (fcd->orires.nr > 0)
{
- /* This assertion is to ensure we have whole molecules.
- * Unfortunately we do not have an mdrun state variable that tells
- * us if molecules in x are not broken over PBC, so we have to make
- * do with checking graph!=nullptr, which should tell us if we made
- * molecules whole before calling the current function.
- */
- GMX_RELEASE_ASSERT(fr->pbcType == PbcType::No || g != nullptr,
- "With orientation restraints molecules should be whole");
+ GMX_ASSERT(!xWholeMolecules.empty(), "Need whole molecules for orienation restraints");
enerd->term[F_ORIRESDEV] =
calc_orires_dev(ms, idef.il[F_ORIRES].size(), idef.il[F_ORIRES].iatoms.data(),
- idef.iparams.data(), md, x, pbc_null, fcd, hist);
+ idef.iparams.data(), md, xWholeMolecules, x, pbc_null, fcd, hist);
}
if (fcd->disres.nres > 0)
{
}
}
+/*! \brief As calc_listed(), but only determines the potential energy
+ * for the perturbed interactions.
+ *
+ * The shift forces in fr are not affected.
+ */
void calc_listed_lambda(const InteractionDefinitions& idef,
const rvec x[],
const t_forcerec* fr,
sfree(f);
}
-void do_force_listed(struct gmx_wallcycle* wcycle,
- const matrix box,
- const t_lambda* fepvals,
- const t_commrec* cr,
- const gmx_multisim_t* ms,
- const InteractionDefinitions& idef,
- const rvec x[],
- history_t* hist,
- gmx::ForceOutputs* forceOutputs,
- const t_forcerec* fr,
- const struct t_pbc* pbc,
- const struct t_graph* graph,
- gmx_enerdata_t* enerd,
- t_nrnb* nrnb,
- const real* lambda,
- const t_mdatoms* md,
- t_fcdata* fcd,
- int* global_atom_index,
- const gmx::StepWorkload& stepWork)
+} // namespace
+
+void do_force_listed(struct gmx_wallcycle* wcycle,
+ const matrix box,
+ const t_lambda* fepvals,
+ const t_commrec* cr,
+ const gmx_multisim_t* ms,
+ const InteractionDefinitions& idef,
+ const rvec x[],
+ gmx::ArrayRef<const gmx::RVec> xWholeMolecules,
+ history_t* hist,
+ gmx::ForceOutputs* forceOutputs,
+ const t_forcerec* fr,
+ const struct t_pbc* pbc,
+ const struct t_graph* graph,
+ gmx_enerdata_t* enerd,
+ t_nrnb* nrnb,
+ const real* lambda,
+ const t_mdatoms* md,
+ t_fcdata* fcd,
+ int* global_atom_index,
+ const gmx::StepWorkload& stepWork)
{
t_pbc pbc_full; /* Full PBC is needed for position restraints */
/* Not enough flops to bother counting */
set_pbc(&pbc_full, fr->pbcType, box);
}
- calc_listed(cr, ms, wcycle, idef, x, hist, forceOutputs, fr, pbc, &pbc_full, graph, enerd, nrnb,
- lambda, md, fcd, global_atom_index, stepWork);
+ calc_listed(cr, ms, wcycle, idef, x, xWholeMolecules, hist, forceOutputs, fr, pbc, &pbc_full,
+ graph, enerd, nrnb, lambda, md, fcd, global_atom_index, stepWork);
/* Check if we have to determine energy differences
* at foreign lambda's.
//! Getter for finding a callable CPU function to compute an \c ftype interaction.
BondedFunction bondedFunction(int ftype);
-/*! \brief Calculates all listed force interactions.
- *
- * Note that pbc_full is used only for position restraints, and is
- * not initialized if there are none. */
-void calc_listed(const t_commrec* cr,
- const gmx_multisim_t* ms,
- struct gmx_wallcycle* wcycle,
- const InteractionDefinitions& idef,
- const rvec x[],
- history_t* hist,
- gmx::ForceOutputs* forceOutputs,
- const t_forcerec* fr,
- const struct t_pbc* pbc,
- const struct t_pbc* pbc_full,
- const struct t_graph* g,
- gmx_enerdata_t* enerd,
- t_nrnb* nrnb,
- const real* lambda,
- const t_mdatoms* md,
- struct t_fcdata* fcd,
- int* ddgatindex,
- const gmx::StepWorkload& stepWork);
-
-/*! \brief As calc_listed(), but only determines the potential energy
- * for the perturbed interactions.
- *
- * The shift forces in fr are not affected. */
-void calc_listed_lambda(const InteractionDefinitions& idef,
- const rvec x[],
- const t_forcerec* fr,
- const struct t_pbc* pbc,
- const struct t_graph* g,
- gmx_grppairener_t* grpp,
- real* epot,
- gmx::ArrayRef<real> dvdl,
- t_nrnb* nrnb,
- const real* lambda,
- const t_mdatoms* md,
- struct t_fcdata* fcd,
- int* global_atom_index);
-
/*! \brief Do all aspects of energy and force calculations for mdrun
- * on the set of listed interactions */
-void do_force_listed(struct gmx_wallcycle* wcycle,
- const matrix box,
- const t_lambda* fepvals,
- const t_commrec* cr,
- const gmx_multisim_t* ms,
- const InteractionDefinitions& idef,
- const rvec x[],
- history_t* hist,
- gmx::ForceOutputs* forceOutputs,
- const t_forcerec* fr,
- const struct t_pbc* pbc,
- const struct t_graph* graph,
- gmx_enerdata_t* enerd,
- t_nrnb* nrnb,
- const real* lambda,
- const t_mdatoms* md,
- struct t_fcdata* fcd,
- int* global_atom_index,
- const gmx::StepWorkload& stepWork);
+ * on the set of listed interactions
+ *
+ * xWholeMolecules only needs to contain whole molecules when orientation
+ * restraints need to be computed and can be empty otherwise.
+ */
+void do_force_listed(struct gmx_wallcycle* wcycle,
+ const matrix box,
+ const t_lambda* fepvals,
+ const t_commrec* cr,
+ const gmx_multisim_t* ms,
+ const InteractionDefinitions& idef,
+ const rvec x[],
+ gmx::ArrayRef<const gmx::RVec> xWholeMolecules,
+ history_t* hist,
+ gmx::ForceOutputs* forceOutputs,
+ const t_forcerec* fr,
+ const struct t_pbc* pbc,
+ const struct t_graph* graph,
+ gmx_enerdata_t* enerd,
+ t_nrnb* nrnb,
+ const real* lambda,
+ const t_mdatoms* md,
+ struct t_fcdata* fcd,
+ int* global_atom_index,
+ const gmx::StepWorkload& stepWork);
/*! \brief Returns true if there are position, distance or orientation restraints. */
bool haveRestraints(const InteractionDefinitions& idef, const t_fcdata& fcd);
#include "gromacs/topology/ifunc.h"
#include "gromacs/topology/mtop_util.h"
#include "gromacs/topology/topology.h"
+#include "gromacs/utility/arrayref.h"
#include "gromacs/utility/fatalerror.h"
#include "gromacs/utility/pleasecite.h"
#include "gromacs/utility/smalloc.h"
+using gmx::ArrayRef;
+using gmx::RVec;
+
// TODO This implementation of ensemble orientation restraints is nasty because
// a user can't just do multi-sim with single-sim orientation restraints.
const t_iatom forceatoms[],
const t_iparams ip[],
const t_mdatoms* md,
+ ArrayRef<const RVec> xWholeMolecules,
const rvec x[],
const t_pbc* pbc,
t_fcdata* fcd,
{
if (md->cORF[i] == 0)
{
- copy_rvec(x[i], xtmp[j]);
+ copy_rvec(xWholeMolecules[i], xtmp[j]);
mref[j] = md->massT[i];
for (int d = 0; d < DIM; d++)
{
struct t_oriresdata;
class t_state;
+namespace gmx
+{
+template<typename>
+class ArrayRef;
+} // namespace gmx
+
/*! \brief
* Decides whether orientation restraints can work, and initializes
* all the orientation restraint stuff in *od (and assumes *od is
*
* Returns the weighted RMS deviation of the orientation restraints.
*/
-real calc_orires_dev(const gmx_multisim_t* ms,
- int nfa,
- const t_iatom fa[],
- const t_iparams ip[],
- const t_mdatoms* md,
- const rvec x[],
- const t_pbc* pbc,
- t_fcdata* fcd,
- history_t* hist);
+real calc_orires_dev(const gmx_multisim_t* ms,
+ int nfa,
+ const t_iatom fa[],
+ const t_iparams ip[],
+ const t_mdatoms* md,
+ gmx::ArrayRef<const gmx::RVec> xWholeMolecules,
+ const rvec x[],
+ const t_pbc* pbc,
+ t_fcdata* fcd,
+ history_t* hist);
/*! \brief
* Diagonalizes the order tensor(s) of the orienation restraints.
#include "gromacs/math/vec.h"
#include "gromacs/mdlib/gmx_omp_nthreads.h"
-void calc_mu(int start,
- int homenr,
- gmx::ArrayRef<gmx::RVec> x,
- const real q[],
- const real qB[],
- int nChargePerturbed,
- dvec mu,
- dvec mu_B)
+void calc_mu(int start,
+ int homenr,
+ gmx::ArrayRef<const gmx::RVec> x,
+ const real q[],
+ const real qB[],
+ int nChargePerturbed,
+ dvec mu,
+ dvec mu_B)
{
int end, m;
double mu_x, mu_y, mu_z;
#include "gromacs/utility/arrayref.h"
#include "gromacs/utility/basedefinitions.h"
-void calc_mu(int start,
- int homenr,
- gmx::ArrayRef<gmx::RVec> x,
- const real q[],
- const real qB[],
- int nChargePerturbed,
- dvec mu,
- dvec mu_B);
+void calc_mu(int start,
+ int homenr,
+ gmx::ArrayRef<const gmx::RVec> x,
+ const real q[],
+ const real qB[],
+ int nChargePerturbed,
+ dvec mu,
+ dvec mu_B);
gmx_bool read_mu(FILE* fp, rvec mu, real* vol);
/* Return true on succes */
gmx_wallcycle_t wcycle,
const t_mdatoms* md,
gmx::ArrayRefWithPadding<gmx::RVec> coordinates,
+ gmx::ArrayRef<const gmx::RVec> xWholeMolecules,
history_t* hist,
gmx::ForceOutputs* forceOutputs,
gmx_enerdata_t* enerd,
set_pbc_dd(&pbc, fr->pbcType, DOMAINDECOMP(cr) ? cr->dd->numCells : nullptr, TRUE, box);
}
- do_force_listed(wcycle, box, ir->fepvals, cr, ms, idef, x, hist, forceOutputs, fr, &pbc,
- graph, enerd, nrnb, lambda, md, fcd,
+ do_force_listed(wcycle, box, ir->fepvals, cr, ms, idef, x, xWholeMolecules, hist,
+ forceOutputs, fr, &pbc, graph, enerd, nrnb, lambda, md, fcd,
DOMAINDECOMP(cr) ? cr->dd->globalAtomIndices.data() : nullptr, stepWork);
}
*/
+/* Compute listed forces, Ewald, PME corrections add when (when used).
+ *
+ * xWholeMolecules only needs to contain whole molecules when orientation
+ * restraints need to be computed and can be empty otherwise.
+ */
void do_force_lowlevel(t_forcerec* fr,
const t_inputrec* ir,
const InteractionDefinitions& idef,
gmx_wallcycle* wcycle,
const t_mdatoms* md,
gmx::ArrayRefWithPadding<gmx::RVec> coordinates,
+ gmx::ArrayRef<const gmx::RVec> xWholeMolecules,
history_t* hist,
gmx::ForceOutputs* forceOutputs,
gmx_enerdata_t* enerd,
*interaction_const = ic;
}
-bool areMoleculesDistributedOverPbc(const t_inputrec& ir, const gmx_mtop_t& mtop, const gmx::MDLogger& mdlog)
-{
- bool areMoleculesDistributedOverPbc = false;
-
- if (ir.pbcType != PbcType::No)
- {
- /* Not making molecules whole is faster in most cases,
- * but with orientation restraints or non-tinfoil boundary
- * conditions we need whole molecules.
- */
- const bool useEwaldSurfaceCorrection = (EEL_PME_EWALD(ir.coulombtype) && ir.epsilon_surface != 0);
- areMoleculesDistributedOverPbc =
- (gmx_mtop_ftype_count(mtop, F_ORIRES) == 0 && !useEwaldSurfaceCorrection);
-
- if (getenv("GMX_USE_GRAPH") != nullptr)
- {
- areMoleculesDistributedOverPbc = false;
-
- GMX_LOG(mdlog.warning)
- .asParagraph()
- .appendText(
- "GMX_USE_GRAPH is set, using the graph for bonded "
- "interactions");
-
- if (mtop.bIntermolecularInteractions)
- {
- GMX_LOG(mdlog.warning)
- .asParagraph()
- .appendText(
- "WARNING: Molecules linked by intermolecular interactions "
- "have to reside in the same periodic image, otherwise "
- "artifacts will occur!");
- }
- }
-
- GMX_RELEASE_ASSERT(areMoleculesDistributedOverPbc || !mtop.bIntermolecularInteractions,
- "We need to use PBC within molecules with inter-molecular interactions");
- }
-
- return areMoleculesDistributedOverPbc;
-}
-
void init_forcerec(FILE* fp,
const gmx::MDLogger& mdlog,
t_forcerec* fr,
{
const bool useEwaldSurfaceCorrection =
(EEL_PME_EWALD(ir->coulombtype) && ir->epsilon_surface != 0);
+ const bool haveOrientationRestraints = (gmx_mtop_ftype_count(mtop, F_ORIRES) > 0);
if (!DOMAINDECOMP(cr))
{
- fr->bMolPBC = areMoleculesDistributedOverPbc(*ir, *mtop, mdlog);
- // The assert below is equivalent to fcd->orires.nr != gmx_mtop_ftype_count(mtop, F_ORIRES)
- GMX_RELEASE_ASSERT(!fr->bMolPBC || fcd->orires.nr == 0,
- "Molecules broken over PBC exist in a simulation including "
- "orientation restraints. "
- "This likely means that the global topology and the force constant "
- "data have gotten out of sync.");
+ fr->bMolPBC = true;
+
+ if (useEwaldSurfaceCorrection || haveOrientationRestraints)
+ {
+ fr->wholeMoleculeTransform =
+ std::make_unique<gmx::WholeMoleculeTransform>(*mtop, ir->pbcType);
+ }
}
else
{
fr->bMolPBC = dd_bonded_molpbc(cr->dd, fr->pbcType);
- if (useEwaldSurfaceCorrection && !dd_moleculesAreAlwaysWhole(*cr->dd))
+ /* With Ewald surface correction it is useful to support e.g. running water
+ * in parallel with update groups.
+ * With orientation restraints there is no sensible use case supported with DD.
+ */
+ if ((useEwaldSurfaceCorrection && !dd_moleculesAreAlwaysWhole(*cr->dd)) || haveOrientationRestraints)
{
gmx_fatal(FARGS,
- "You requested dipole correction (epsilon_surface > 0), but molecules "
- "are broken "
+ "You requested Ewald surface correction or orientation restraints, "
+ "but molecules are broken "
"over periodic boundary conditions by the domain decomposition. "
"Run without domain decomposition instead.");
}
if (useEwaldSurfaceCorrection)
{
- GMX_RELEASE_ASSERT((!DOMAINDECOMP(cr) && !fr->bMolPBC)
- || (DOMAINDECOMP(cr) && dd_moleculesAreAlwaysWhole(*cr->dd)),
+ GMX_RELEASE_ASSERT(!DOMAINDECOMP(cr) || dd_moleculesAreAlwaysWhole(*cr->dd),
"Molecules can not be broken by PBC with epsilon_surface > 0");
}
}
wallcycle_stop(wcycle, ewcLAUNCH_GPU);
}
+ gmx::ArrayRef<const gmx::RVec> xWholeMolecules;
+ if (fr->wholeMoleculeTransform)
+ {
+ xWholeMolecules = fr->wholeMoleculeTransform->wholeMoleculeCoordinates(x.unpaddedArrayRef(), box);
+ }
+
DipoleData dipoleData;
if (simulationWork.computeMuTot)
/* Calculate total (local) dipole moment in a temporary common array.
* This makes it possible to sum them over nodes faster.
*/
- calc_mu(start, mdatoms->homenr, x.unpaddedArrayRef(), mdatoms->chargeA, mdatoms->chargeB,
+ gmx::ArrayRef<const gmx::RVec> xRef =
+ (xWholeMolecules.empty() ? x.unpaddedArrayRef() : xWholeMolecules);
+ calc_mu(start, mdatoms->homenr, xRef, mdatoms->chargeA, mdatoms->chargeB,
mdatoms->nChargePerturbed, dipoleData.muStaging[0], dipoleData.muStaging[1]);
reduceAndUpdateMuTot(&dipoleData, cr, (fr->efep != efepNO), lambda, muTotal, ddBalanceRegionHandler);
stateGpu->waitCoordinatesReadyOnHost(AtomLocality::NonLocal);
}
/* Compute the bonded and non-bonded energies and optionally forces */
- do_force_lowlevel(fr, inputrec, top->idef, cr, ms, nrnb, wcycle, mdatoms, x, hist, &forceOut,
- enerd, fcd, box, lambda.data(), graph, as_rvec_array(dipoleData.muStateAB),
- stepWork, ddBalanceRegionHandler);
+ do_force_lowlevel(fr, inputrec, top->idef, cr, ms, nrnb, wcycle, mdatoms, x, xWholeMolecules,
+ hist, &forceOut, enerd, fcd, box, lambda.data(), graph,
+ as_rvec_array(dipoleData.muStateAB), stepWork, ddBalanceRegionHandler);
wallcycle_stop(wcycle, ewcFORCE);
isInputCompatible
&& conditionalAssert(!doMembed,
"Membrane embedding is not supported by the modular simulator.");
- const bool useGraph = !areMoleculesDistributedOverPbc(*inputrec, globalTopology, MDLogger());
- isInputCompatible =
- isInputCompatible
- && conditionalAssert(!useGraph, "Graph is not supported by the modular simulator.");
// TODO: Change this to the boolean passed when we merge the user interface change for the GPU update.
isInputCompatible =
isInputCompatible
CommandLine mdrunCaller;
ASSERT_EQ(0, runner_.callMdrun(mdrunCaller));
EnergyTermsToCompare energyTermsToCompare{
- { { interaction_function[F_EPOT].longname, relativeToleranceAsFloatingPoint(1, 1e-4) },
- { interaction_function[F_ETOT].longname, relativeToleranceAsFloatingPoint(1, 1e-4) } }
+ { { interaction_function[F_EPOT].longname, absoluteTolerance(1e-3) },
+ { interaction_function[F_ETOT].longname, absoluteTolerance(1e-3) } }
};
TestReferenceData refData;
auto checker = refData.rootChecker().checkCompound("Simulation", simulationName);
//! Containers of systems to test.
//! \{
-// Enable when the epsilon-surface bug is fixed
-// std::vector<std::string> surfaceTerm = { "3DC", "epsilon-surface-constraint", "epsilon-surface" };
-std::vector<std::string> surfaceTerm = { "3DC", "epsilon-surface-constraint" };
+std::vector<std::string> surfaceTerm = { "3DC", "epsilon-surface-constraint", "epsilon-surface" };
//! \}
INSTANTIATE_TEST_CASE_P(EwaldSurfaceTerm, EwaldSurfaceTermTest, ::testing::ValuesIn(surfaceTerm));
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <Simulation Name="epsilon-surface">
+ <Energy Name="Total Energy">
+ <Real Name="Time 0.000000 Step 0 in frame 0">20.32147</Real>
+ <Real Name="Time 0.010000 Step 4 in frame 1">20.300804</Real>
+ <Real Name="Time 0.020000 Step 8 in frame 2">20.259245</Real>
+ <Real Name="Time 0.030000 Step 12 in frame 3">20.223288</Real>
+ <Real Name="Time 0.040000 Step 16 in frame 4">20.215561</Real>
+ <Real Name="Time 0.050000 Step 20 in frame 5">20.240704</Real>
+ </Energy>
+ <Energy Name="Potential">
+ <Real Name="Time 0.000000 Step 0 in frame 0">20.214478</Real>
+ <Real Name="Time 0.010000 Step 4 in frame 1">16.217239</Real>
+ <Real Name="Time 0.020000 Step 8 in frame 2">8.2757568</Real>
+ <Real Name="Time 0.030000 Step 12 in frame 3">1.3982239</Real>
+ <Real Name="Time 0.040000 Step 16 in frame 4">-0.07736969</Real>
+ <Real Name="Time 0.050000 Step 20 in frame 5">4.7798805</Real>
+ </Energy>
+ <Vector Name="Time 0.000000 Step 0 F[0]">
+ <Real Name="X">1.6004291</Real>
+ <Real Name="Y">522.04138</Real>
+ <Real Name="Z">370.92786</Real>
+ </Vector>
+ <Vector Name="Time 0.000000 Step 0 F[1]">
+ <Real Name="X">-1.900637</Real>
+ <Real Name="Y">-522.46527</Real>
+ <Real Name="Z">-371.22949</Real>
+ </Vector>
+ <Vector Name="Time 0.000000 Step 0 F[2]">
+ <Real Name="X">20.091843</Real>
+ <Real Name="Y">-1.0637188</Real>
+ <Real Name="Z">18.672668</Real>
+ </Vector>
+ <Vector Name="Time 0.000000 Step 0 F[3]">
+ <Real Name="X">-19.791595</Real>
+ <Real Name="Y">1.4878402</Real>
+ <Real Name="Z">-18.371048</Real>
+ </Vector>
+ <Vector Name="Time 0.010000 Step 4 F[0]">
+ <Real Name="X">1.5716085</Real>
+ <Real Name="Y">468.56262</Real>
+ <Real Name="Z">332.87283</Real>
+ </Vector>
+ <Vector Name="Time 0.010000 Step 4 F[1]">
+ <Real Name="X">-1.8655734</Real>
+ <Real Name="Y">-468.97778</Real>
+ <Real Name="Z">-333.16809</Real>
+ </Vector>
+ <Vector Name="Time 0.010000 Step 4 F[2]">
+ <Real Name="X">18.114136</Real>
+ <Real Name="Y">-1.0417742</Real>
+ <Real Name="Z">16.720505</Real>
+ </Vector>
+ <Vector Name="Time 0.010000 Step 4 F[3]">
+ <Real Name="X">-17.82019</Real>
+ <Real Name="Y">1.4571649</Real>
+ <Real Name="Z">-16.425293</Real>
+ </Vector>
+ <Vector Name="Time 0.020000 Step 8 F[0]">
+ <Real Name="X">1.5227978</Real>
+ <Real Name="Y">338.07782</Real>
+ <Real Name="Z">239.98503</Real>
+ </Vector>
+ <Vector Name="Time 0.020000 Step 8 F[1]">
+ <Real Name="X">-1.801703</Real>
+ <Real Name="Y">-338.47165</Real>
+ <Real Name="Z">-240.26477</Real>
+ </Vector>
+ <Vector Name="Time 0.020000 Step 8 F[2]">
+ <Real Name="X">13.286667</Real>
+ <Real Name="Y">-0.99115908</Real>
+ <Real Name="Z">11.956177</Real>
+ </Vector>
+ <Vector Name="Time 0.020000 Step 8 F[3]">
+ <Real Name="X">-13.007904</Real>
+ <Real Name="Y">1.3853663</Real>
+ <Real Name="Z">-11.676315</Real>
+ </Vector>
+ <Vector Name="Time 0.030000 Step 12 F[0]">
+ <Real Name="X">1.5251596</Real>
+ <Real Name="Y">152.05093</Real>
+ <Real Name="Z">107.45719</Real>
+ </Vector>
+ <Vector Name="Time 0.030000 Step 12 F[1]">
+ <Real Name="X">-1.7829351</Real>
+ <Real Name="Y">-152.41469</Real>
+ <Real Name="Z">-107.71528</Real>
+ </Vector>
+ <Vector Name="Time 0.030000 Step 12 F[2]">
+ <Real Name="X">6.4033661</Real>
+ <Real Name="Y">-0.92074591</Real>
+ <Real Name="Z">5.1584015</Real>
+ </Vector>
+ <Vector Name="Time 0.030000 Step 12 F[3]">
+ <Real Name="X">-6.1460266</Real>
+ <Real Name="Y">1.2851006</Real>
+ <Real Name="Z">-4.9001007</Real>
+ </Vector>
+ <Vector Name="Time 0.040000 Step 16 F[0]">
+ <Real Name="X">1.6834296</Real>
+ <Real Name="Y">-58.880402</Real>
+ <Real Name="Z">-43.009636</Real>
+ </Vector>
+ <Vector Name="Time 0.040000 Step 16 F[1]">
+ <Real Name="X">-1.9177186</Real>
+ <Real Name="Y">58.550491</Real>
+ <Real Name="Z">42.775757</Real>
+ </Vector>
+ <Vector Name="Time 0.040000 Step 16 F[2]">
+ <Real Name="X">-1.4052582</Real>
+ <Real Name="Y">-0.84537828</Real>
+ <Real Name="Z">-2.5614777</Real>
+ </Vector>
+ <Vector Name="Time 0.040000 Step 16 F[3]">
+ <Real Name="X">1.6388092</Real>
+ <Real Name="Y">1.1762809</Real>
+ <Real Name="Z">2.7957458</Real>
+ </Vector>
+ <Vector Name="Time 0.050000 Step 20 F[0]">
+ <Real Name="X">2.1072018</Real>
+ <Real Name="Y">-259.95499</Real>
+ <Real Name="Z">-186.73514</Real>
+ </Vector>
+ <Vector Name="Time 0.050000 Step 20 F[1]">
+ <Real Name="X">-2.3196166</Real>
+ <Real Name="Y">259.6571</Real>
+ <Real Name="Z">186.52396</Real>
+ </Vector>
+ <Vector Name="Time 0.050000 Step 20 F[2]">
+ <Real Name="X">-8.8654175</Real>
+ <Real Name="Y">-0.77974892</Real>
+ <Real Name="Z">-9.9438782</Real>
+ </Vector>
+ <Vector Name="Time 0.050000 Step 20 F[3]">
+ <Real Name="X">9.0768127</Real>
+ <Real Name="Y">1.0791473</Real>
+ <Real Name="Z">10.155777</Real>
+ </Vector>
+ </Simulation>
+</ReferenceData>