Add unit tests for selection position calculation.
authorTeemu Murtola <teemu.murtola@gmail.com>
Mon, 29 Apr 2013 03:35:41 +0000 (06:35 +0300)
committerGerrit Code Review <gerrit@gerrit.gromacs.org>
Thu, 25 Jul 2013 06:26:13 +0000 (08:26 +0200)
Add unit tests for most functionality of poscalc.*.  These tests also
cover centerofmass.*.

Fixed two issues:
- POS_MASKONLY calculations had an inconsistent group set in the output
  positions (which was visible in the selection interface, returning
  incorrect set of atoms for the selection).
- Force calculation was incorrect.
These do not affect g_select, so only fixed for 5.0.

Part of #651, related to #1221.

Change-Id: I4dc6475f53fb3b1559bae9296f8c9f3e6dd14bf7

18 files changed:
src/gromacs/selection/centerofmass.cpp
src/gromacs/selection/centerofmass.h
src/gromacs/selection/poscalc.cpp
src/gromacs/selection/tests/CMakeLists.txt
src/gromacs/selection/tests/poscalc.cpp [new file with mode: 0644]
src/gromacs/selection/tests/refdata/PositionCalculationTest_ComputesAtomPositions.xml [new file with mode: 0644]
src/gromacs/selection/tests/refdata/PositionCalculationTest_ComputesGroupCOGPositions.xml [new file with mode: 0644]
src/gromacs/selection/tests/refdata/PositionCalculationTest_ComputesGroupCOMPositions.xml [new file with mode: 0644]
src/gromacs/selection/tests/refdata/PositionCalculationTest_ComputesPositionMask.xml [new file with mode: 0644]
src/gromacs/selection/tests/refdata/PositionCalculationTest_ComputesPositionsWithCompleteMax.xml [new file with mode: 0644]
src/gromacs/selection/tests/refdata/PositionCalculationTest_ComputesPositionsWithCompleteWhole.xml [new file with mode: 0644]
src/gromacs/selection/tests/refdata/PositionCalculationTest_ComputesResidueCOGPositions.xml [new file with mode: 0644]
src/gromacs/selection/tests/refdata/PositionCalculationTest_ComputesResidueCOMPositions.xml [new file with mode: 0644]
src/gromacs/selection/tests/refdata/PositionCalculationTest_HandlesIdenticalStaticCalculations.xml [new file with mode: 0644]
src/gromacs/selection/tests/refdata/PositionCalculationTest_HandlesOverlappingStaticCalculations.xml [new file with mode: 0644]
src/gromacs/selection/tests/refdata/referencedata.xsl
src/gromacs/selection/tests/toputils.cpp
src/gromacs/selection/tests/toputils.h

index 4aeeca79425c51d78ee3e1d5bfb8dfe892be13df..0a5c8c5e3cff1c2248c92a84d36c190207654af4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2009,2010,2011,2012, by the GROMACS development team, led by
+ * Copyright (c) 2009,2010,2011,2012,2013, by the GROMACS development team, led by
  * David van der Spoel, Berk Hess, Erik Lindahl, and including many
  * others, as listed in the AUTHORS file in the top-level source
  * directory and at http://www.gromacs.org.
  * \author Teemu Murtola <teemu.murtola@gmail.com>
  * \ingroup module_selection
  */
+#include "gromacs/selection/centerofmass.h"
+
 #include "gromacs/legacyheaders/typedefs.h"
 #include "gromacs/legacyheaders/pbc.h"
 #include "gromacs/legacyheaders/vec.h"
 
-#include "gromacs/selection/centerofmass.h"
-
 /*!
  * \param[in]  top    Topology structure (unused, can be NULL).
  * \param[in]  x      Position vectors of all atoms.
@@ -113,9 +113,6 @@ gmx_calc_com(t_topology *top, rvec x[], int nrefat, atom_id index[], rvec xout)
  * \param[in]  index  Indices of atoms.
  * \param[out] fout   Force on the COG position for the indexed atoms.
  * \returns    0 on success, EINVAL if \p top is NULL.
- *
- * No special function is provided for calculating the force on the center of
- * mass, because this can be achieved with gmx_calc_cog().
  */
 int
 gmx_calc_cog_f(t_topology *top, rvec f[], int nrefat, atom_id index[], rvec fout)
@@ -140,7 +137,27 @@ gmx_calc_cog_f(t_topology *top, rvec f[], int nrefat, atom_id index[], rvec fout
         }
         mtot += mass;
     }
-    svmul(mtot, fout, fout);
+    svmul(mtot / nrefat, fout, fout);
+    return 0;
+}
+
+/*!
+ * \param[in]  top    Topology structure (unused, can be NULL).
+ * \param[in]  f      Forces on all atoms.
+ * \param[in]  nrefat Number of atoms in the index.
+ * \param[in]  index  Indices of atoms.
+ * \param[out] fout   Force on the COM position for the indexed atoms.
+ * \returns    0 on success.
+ */
+int
+gmx_calc_com_f(t_topology *top, rvec f[], int nrefat, atom_id index[], rvec fout)
+{
+    clear_rvec(fout);
+    for (int m = 0; m < nrefat; ++m)
+    {
+        const int ai = index[m];
+        rvec_inc(fout, f[ai]);
+    }
     return 0;
 }
 
@@ -182,7 +199,7 @@ gmx_calc_comg(t_topology *top, rvec x[], int nrefat, atom_id index[],
  * \param[out] fout  Force on the COM/COG position for the indexed atoms.
  * \returns    0 on success, EINVAL if \p top is NULL and \p bMass is false.
  *
- * Calls either gmx_calc_cog() or gmx_calc_cog_f() depending on the value of
+ * Calls either gmx_calc_cog_f() or gmx_calc_com_f() depending on the value of
  * \p bMass.
  * Other parameters are passed unmodified to these functions.
  */
@@ -192,7 +209,7 @@ gmx_calc_comg_f(t_topology *top, rvec f[], int nrefat, atom_id index[],
 {
     if (bMass)
     {
-        return gmx_calc_cog(top, f, nrefat, index, fout);
+        return gmx_calc_com_f(top, f, nrefat, index, fout);
     }
     else
     {
@@ -465,7 +482,33 @@ gmx_calc_cog_f_block(t_topology *top, rvec f[], t_block *block, atom_id index[],
             }
             mtot += mass;
         }
-        svmul(mtot, fb, fout[b]);
+        svmul(mtot / (block->index[b+1] - block->index[b]), fb, fout[b]);
+    }
+    return 0;
+}
+
+/*!
+ * \param[in]  top   Topology structure (unused, can be NULL).
+ * \param[in]  f     Forces on all atoms.
+ * \param[in]  block t_block structure that divides \p index into blocks.
+ * \param[in]  index Indices of atoms.
+ * \param[out] fout  \p block->nr Forces on COM positions.
+ * \returns    0 on success.
+ */
+int
+gmx_calc_com_f_block(t_topology *top, rvec f[], t_block *block, atom_id index[],
+                     rvec fout[])
+{
+    for (int b = 0; b < block->nr; ++b)
+    {
+        rvec fb;
+        clear_rvec(fb);
+        for (int i = block->index[b]; i < block->index[b+1]; ++i)
+        {
+            const int ai = index[i];
+            rvec_inc(fb, f[ai]);
+        }
+        copy_rvec(fb, fout[b]);
     }
     return 0;
 }
@@ -508,8 +551,8 @@ gmx_calc_comg_block(t_topology *top, rvec x[], t_block *block, atom_id index[],
  * \param[out] fout  \p block->nr forces on the COM/COG positions.
  * \returns    0 on success, EINVAL if \p top is NULL and \p bMass is true.
  *
- * Calls either gmx_calc_com_block() or gmx_calc_cog_block() depending on the
- * value of \p bMass.
+ * Calls either gmx_calc_com_f_block() or gmx_calc_cog_f_block() depending on
+ * the value of \p bMass.
  * Other parameters are passed unmodified to these functions.
  */
 int
@@ -518,7 +561,7 @@ gmx_calc_comg_f_block(t_topology *top, rvec f[], t_block *block, atom_id index[]
 {
     if (bMass)
     {
-        return gmx_calc_cog_block(top, f, block, index, fout);
+        return gmx_calc_com_f_block(top, f, block, index, fout);
     }
     else
     {
index 00cd568ac1270a436d0ba71e7f2207e22d0446f9..1f8c3e8eab1f6a6d0d60df7fd517a77a2977d870 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2009,2010,2011, by the GROMACS development team, led by
+ * Copyright (c) 2009,2010,2011,2013, by the GROMACS development team, led by
  * David van der Spoel, Berk Hess, Erik Lindahl, and including many
  * others, as listed in the AUTHORS file in the top-level source
  * directory and at http://www.gromacs.org.
@@ -85,6 +85,9 @@ gmx_calc_com(t_topology *top, rvec x[], int nrefat, atom_id index[], rvec xout);
 /** Calculate force on a single center of geometry. */
 int
 gmx_calc_cog_f(t_topology *top, rvec f[], int nrefat, atom_id index[], rvec fout);
+/** Calculate force on a single center of mass. */
+int
+gmx_calc_com_f(t_topology *top, rvec f[], int nrefat, atom_id index[], rvec fout);
 /** Calculate a single center of mass/geometry. */
 int
 gmx_calc_comg(t_topology *top, rvec x[], int nrefat, atom_id index[],
@@ -119,6 +122,10 @@ gmx_calc_com_block(t_topology *top, rvec x[], t_block *block,
 int
 gmx_calc_cog_f_block(t_topology *top, rvec f[], t_block *block,
                      atom_id index[], rvec fout[]);
+/** Calculate forces on centers of mass for a blocked index. */
+int
+gmx_calc_com_f_block(t_topology *top, rvec f[], t_block *block,
+                     atom_id index[], rvec fout[]);
 /** Calculate centers of mass/geometry for a blocked index. */
 int
 gmx_calc_comg_block(t_topology *top, rvec x[], t_block *block,
index 402af13c2f6ba33a9f605a5382ce5f1469ffaf94..d07eb7ce2ae86587903b65539f73a62b92202a22 100644 (file)
@@ -1108,7 +1108,8 @@ gmx_ana_poscalc_free(gmx_ana_poscalc_t *pc)
 bool
 gmx_ana_poscalc_requires_top(gmx_ana_poscalc_t *pc)
 {
-    if ((pc->flags & POS_MASS) || pc->type == POS_RES || pc->type == POS_MOL)
+    if ((pc->flags & POS_MASS) || pc->type == POS_RES || pc->type == POS_MOL
+        || ((pc->flags & POS_FORCES) && pc->type != POS_ATOM))
     {
         return true;
     }
@@ -1148,11 +1149,11 @@ gmx_ana_poscalc_update(gmx_ana_poscalc_t *pc, gmx_ana_pos_t *p,
     {
         g = &pc->gmax;
     }
-    gmx_ana_pos_set_evalgrp(p, g);
 
     /* Update the index map */
     if (pc->flags & POS_DYNAMIC)
     {
+        gmx_ana_pos_set_evalgrp(p, g);
         gmx_ana_indexmap_update(&p->m, g, false);
         p->nr = p->m.nr;
     }
@@ -1302,7 +1303,7 @@ gmx_ana_poscalc_update(gmx_ana_poscalc_t *pc, gmx_ana_pos_t *p,
                 }
                 if (p->f && fr->bF)
                 {
-                    gmx_calc_comg_blocka(top, fr->f, &pc->b, bMass, p->f);
+                    gmx_calc_comg_f_blocka(top, fr->f, &pc->b, bMass, p->f);
                 }
                 break;
         }
index 2948e7c03e5abc58296eaff15a0b8c1b075e5aaf..78dbbd05bef665989252e3d354d6a26940180a1f 100644 (file)
@@ -35,6 +35,7 @@
 gmx_add_unit_test(SelectionUnitTests selection-test
                   indexutil.cpp
                   nbsearch.cpp
+                  poscalc.cpp
                   selectioncollection.cpp
                   selectionoption.cpp
                   toputils.cpp)
diff --git a/src/gromacs/selection/tests/poscalc.cpp b/src/gromacs/selection/tests/poscalc.cpp
new file mode 100644 (file)
index 0000000..50f3325
--- /dev/null
@@ -0,0 +1,496 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2013, by the GROMACS development team, led by
+ * David van der Spoel, Berk Hess, Erik Lindahl, and including many
+ * others, as listed in the AUTHORS file in the top-level source
+ * directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \internal \file
+ * \brief
+ * Tests the position mapping engine.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_selection
+ */
+#include <gtest/gtest.h>
+
+#include <vector>
+
+#include "gromacs/legacyheaders/smalloc.h"
+#include "gromacs/legacyheaders/typedefs.h"
+#include "gromacs/legacyheaders/vec.h"
+
+#include "gromacs/selection/indexutil.h"
+#include "gromacs/selection/poscalc.h"
+#include "gromacs/selection/position.h"
+
+#include "testutils/refdata.h"
+
+#include "toputils.h"
+
+namespace
+{
+
+/********************************************************************
+ * PositionCalculationTest
+ */
+
+class PositionCalculationTest : public ::testing::Test
+{
+    public:
+        PositionCalculationTest();
+        ~PositionCalculationTest();
+
+        void generateCoordinates();
+
+        gmx_ana_poscalc_t *createCalculation(e_poscalc_t type, int flags);
+        void setMaximumGroup(gmx_ana_poscalc_t *pc,
+                             int count, const int atoms[]);
+        gmx_ana_pos_t *initPositions(gmx_ana_poscalc_t *pc, const char *name);
+
+        void checkInitialized();
+        void updateAndCheck(gmx_ana_poscalc_t *pc, gmx_ana_pos_t *p,
+                            int count, const int atoms[],
+                            gmx::test::TestReferenceChecker *checker,
+                            const char *name);
+
+        void testSingleStatic(e_poscalc_t type, int flags, bool bExpectTop,
+                              int atomCount, const int atoms[]);
+        void testSingleDynamic(e_poscalc_t type, int flags, bool bExpectTop,
+                               int initCount, const int initAtoms[],
+                               int evalCount, const int evalAtoms[]);
+
+        template <int count>
+        void setMaximumGroup(gmx_ana_poscalc_t *pc, const int (&atoms)[count])
+        {
+            setMaximumGroup(pc, count, atoms);
+        }
+        template <int count>
+        void updateAndCheck(gmx_ana_poscalc_t *pc, gmx_ana_pos_t *p,
+                            const int (&atoms)[count],
+                            gmx::test::TestReferenceChecker *checker,
+                            const char *name)
+        {
+            updateAndCheck(pc, p, count, atoms, checker, name);
+        }
+        template <int atomCount>
+        void testSingleStatic(e_poscalc_t type, int flags, bool bExpectTop,
+                              const int (&atoms)[atomCount])
+        {
+            testSingleStatic(type, flags, bExpectTop, atomCount, atoms);
+        }
+        template <int initCount, int evalCount>
+        void testSingleDynamic(e_poscalc_t type, int flags, bool bExpectTop,
+                               const int (&initAtoms)[initCount],
+                               const int (&evalAtoms)[evalCount])
+        {
+            testSingleDynamic(type, flags, bExpectTop,
+                              initCount, initAtoms, evalCount, evalAtoms);
+        }
+
+        gmx::test::TestReferenceData        data_;
+        gmx::test::TestReferenceChecker     checker_;
+        gmx::test::TopologyManager          topManager_;
+        gmx::PositionCalculationCollection  pcc_;
+
+    private:
+        struct PositionTest
+        {
+            PositionTest() : pos(NULL), pc(NULL), name(NULL) {}
+            PositionTest(gmx_ana_pos_t *pos, gmx_ana_poscalc_t *pc,
+                         const char *name)
+                : pos(pos), pc(pc), name(name)
+            {
+            }
+
+            gmx_ana_pos_t                  *pos;
+            gmx_ana_poscalc_t              *pc;
+            const char                     *name;
+        };
+
+        typedef std::vector<PositionTest> PositionTestList;
+
+        void setTopologyIfRequired();
+        void checkPositions(gmx::test::TestReferenceChecker *checker,
+                            const char *name, gmx_ana_pos_t *p,
+                            bool bCoordinates);
+
+        std::vector<gmx_ana_poscalc_t *>    pcList_;
+        PositionTestList                    posList_;
+        bool                                bTopSet_;
+};
+
+PositionCalculationTest::PositionCalculationTest()
+    : checker_(data_.rootChecker()), bTopSet_(false)
+{
+    topManager_.requestFrame();
+}
+
+PositionCalculationTest::~PositionCalculationTest()
+{
+    std::vector<gmx_ana_poscalc_t *>::reverse_iterator pci;
+    for (pci = pcList_.rbegin(); pci != pcList_.rend(); ++pci)
+    {
+        gmx_ana_poscalc_free(*pci);
+    }
+
+    PositionTestList::iterator pi;
+    for (pi = posList_.begin(); pi != posList_.end(); ++pi)
+    {
+        gmx_ana_pos_free(pi->pos);
+    }
+}
+
+void PositionCalculationTest::generateCoordinates()
+{
+    t_topology *top   = topManager_.topology();
+    t_trxframe *frame = topManager_.frame();
+    for (int i = 0; i < top->atoms.nr; ++i)
+    {
+        frame->x[i][XX] = i;
+        frame->x[i][YY] = top->atoms.atom[i].resind;
+        frame->x[i][ZZ] = 0.0;
+        if (frame->bV)
+        {
+            copy_rvec(frame->x[i], frame->v[i]);
+            frame->v[i][ZZ] = 1.0;
+        }
+        if (frame->bF)
+        {
+            copy_rvec(frame->x[i], frame->f[i]);
+            frame->f[i][ZZ] = -1.0;
+        }
+    }
+}
+
+gmx_ana_poscalc_t *
+PositionCalculationTest::createCalculation(e_poscalc_t type, int flags)
+{
+    pcList_.reserve(pcList_.size() + 1);
+    pcList_.push_back(pcc_.createCalculation(type, flags));
+    return pcList_.back();
+}
+
+void PositionCalculationTest::setMaximumGroup(gmx_ana_poscalc_t *pc,
+                                              int count, const int atoms[])
+{
+    setTopologyIfRequired();
+    gmx_ana_index_t g;
+    g.isize = count;
+    g.index = const_cast<int *>(atoms);
+    gmx_ana_poscalc_set_maxindex(pc, &g);
+}
+
+gmx_ana_pos_t *
+PositionCalculationTest::initPositions(gmx_ana_poscalc_t *pc, const char *name)
+{
+    posList_.reserve(posList_.size() + 1);
+    gmx_ana_pos_t *p;
+    snew(p, 1);
+    posList_.push_back(PositionTest(p, pc, name));
+    gmx_ana_poscalc_init_pos(pc, p);
+    return p;
+}
+
+void PositionCalculationTest::checkInitialized()
+{
+    gmx::test::TestReferenceChecker  compound(
+            checker_.checkCompound("InitializedPositions", NULL));
+    PositionTestList::const_iterator pi;
+    for (pi = posList_.begin(); pi != posList_.end(); ++pi)
+    {
+        checkPositions(&compound, pi->name, pi->pos, false);
+    }
+}
+
+void PositionCalculationTest::updateAndCheck(
+        gmx_ana_poscalc_t *pc, gmx_ana_pos_t *p, int count, const int atoms[],
+        gmx::test::TestReferenceChecker *checker, const char *name)
+{
+    // TODO: The group reference may get stored in p and stays there after this
+    // function returns.
+    gmx_ana_index_t g;
+    g.isize = count;
+    g.index = const_cast<int *>(atoms);
+    gmx_ana_poscalc_update(pc, p, &g, topManager_.frame(), NULL);
+    checkPositions(checker, name, p, true);
+}
+
+void PositionCalculationTest::testSingleStatic(
+        e_poscalc_t type, int flags, bool bExpectTop,
+        int atomCount, const int atoms[])
+{
+    t_trxframe *frame = topManager_.frame();
+    if (frame->bV)
+    {
+        flags |= POS_VELOCITIES;
+    }
+    if (frame->bF)
+    {
+        flags |= POS_FORCES;
+    }
+    gmx_ana_poscalc_t *pc = createCalculation(type, flags);
+    EXPECT_EQ(bExpectTop, gmx_ana_poscalc_requires_top(pc));
+    setMaximumGroup(pc, atomCount, atoms);
+    gmx_ana_pos_t *p = initPositions(pc, NULL);
+    checkInitialized();
+    {
+        pcc_.initEvaluation();
+        pcc_.initFrame();
+        generateCoordinates();
+        gmx::test::TestReferenceChecker frameCompound(
+                checker_.checkCompound("EvaluatedPositions", "Frame0"));
+        updateAndCheck(pc, p, atomCount, atoms, &frameCompound, NULL);
+    }
+}
+
+void PositionCalculationTest::testSingleDynamic(
+        e_poscalc_t type, int flags, bool bExpectTop,
+        int initCount, const int initAtoms[],
+        int evalCount, const int evalAtoms[])
+{
+    gmx_ana_poscalc_t *pc = createCalculation(type, flags | POS_DYNAMIC);
+    EXPECT_EQ(bExpectTop, gmx_ana_poscalc_requires_top(pc));
+    setMaximumGroup(pc, initCount, initAtoms);
+    gmx_ana_pos_t *p = initPositions(pc, NULL);
+    checkInitialized();
+    {
+        pcc_.initEvaluation();
+        pcc_.initFrame();
+        generateCoordinates();
+        gmx::test::TestReferenceChecker frameCompound(
+                checker_.checkCompound("EvaluatedPositions", "Frame0"));
+        updateAndCheck(pc, p, evalCount, evalAtoms, &frameCompound, NULL);
+    }
+}
+
+void PositionCalculationTest::setTopologyIfRequired()
+{
+    if (bTopSet_)
+    {
+        return;
+    }
+    std::vector<gmx_ana_poscalc_t *>::const_iterator pci;
+    for (pci = pcList_.begin(); pci != pcList_.end(); ++pci)
+    {
+        if (gmx_ana_poscalc_requires_top(*pci))
+        {
+            bTopSet_ = true;
+            pcc_.setTopology(topManager_.topology());
+            return;
+        }
+    }
+}
+
+void PositionCalculationTest::checkPositions(
+        gmx::test::TestReferenceChecker *checker,
+        const char *name, gmx_ana_pos_t *p, bool bCoordinates)
+{
+    EXPECT_EQ(p->nr, p->m.nr);
+    EXPECT_EQ(p->nr, p->m.mapb.nr);
+    ASSERT_TRUE(p->g != NULL);
+    gmx::test::TestReferenceChecker compound(
+            checker->checkCompound("Positions", name));
+    compound.checkInteger(p->nr, "Count");
+    const char *type = "???";
+    switch (p->m.type)
+    {
+        case INDEX_UNKNOWN: type = "unknown";   break;
+        case INDEX_ATOM:    type = "atoms";     break;
+        case INDEX_RES:     type = "residues";  break;
+        case INDEX_MOL:     type = "molecules"; break;
+        case INDEX_ALL:     type = "single";    break;
+    }
+    compound.checkString(type, "Type");
+    compound.checkSequenceArray(p->nr + 1, p->m.mapb.index, "Block");
+    for (int i = 0; i < p->nr; ++i)
+    {
+        gmx::test::TestReferenceChecker posCompound(
+                compound.checkCompound("Position", NULL));
+        // Always true; should satisfy clang.
+        if (p->g != NULL)
+        {
+            posCompound.checkSequence(&p->g->index[p->m.mapb.index[i]],
+                                      &p->g->index[p->m.mapb.index[i+1]],
+                                      "Atoms");
+        }
+        posCompound.checkInteger(p->m.refid[i], "RefId");
+        if (bCoordinates)
+        {
+            posCompound.checkVector(p->x[i], "Coordinates");
+        }
+        if (bCoordinates && p->v != NULL)
+        {
+            posCompound.checkVector(p->v[i], "Velocity");
+        }
+        if (bCoordinates && p->f != NULL)
+        {
+            posCompound.checkVector(p->f[i], "Force");
+        }
+        int originalIdIndex = (p->m.refid[i] != -1 ? p->m.refid[i] : i);
+        EXPECT_EQ(p->m.orgid[originalIdIndex], p->m.mapid[i]);
+    }
+}
+
+/********************************************************************
+ * Actual tests
+ */
+
+TEST_F(PositionCalculationTest, ComputesAtomPositions)
+{
+    const int group[] = { 0, 1, 2, 3 };
+    topManager_.requestVelocities();
+    topManager_.requestForces();
+    topManager_.initAtoms(4);
+    testSingleStatic(POS_ATOM, 0, false, group);
+}
+
+TEST_F(PositionCalculationTest, ComputesResidueCOGPositions)
+{
+    const int group[] = { 0, 1, 2, 3, 4, 8 };
+    topManager_.requestVelocities();
+    topManager_.requestForces();
+    topManager_.initAtoms(9);
+    topManager_.initUniformResidues(3);
+    testSingleStatic(POS_RES, 0, true, group);
+}
+
+TEST_F(PositionCalculationTest, ComputesResidueCOMPositions)
+{
+    const int group[] = { 0, 1, 2, 3, 4, 8 };
+    topManager_.requestVelocities();
+    topManager_.requestForces();
+    topManager_.initAtoms(9);
+    topManager_.initUniformResidues(3);
+    testSingleStatic(POS_RES, POS_MASS, true, group);
+}
+
+TEST_F(PositionCalculationTest, ComputesGroupCOGPositions)
+{
+    const int group[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
+    topManager_.requestVelocities();
+    topManager_.requestForces();
+    topManager_.initAtoms(9);
+    // Topology (masses) is requires for computing the force
+    testSingleStatic(POS_ALL, 0, true, group);
+}
+
+TEST_F(PositionCalculationTest, ComputesGroupCOMPositions)
+{
+    const int group[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
+    topManager_.requestVelocities();
+    topManager_.requestForces();
+    topManager_.initAtoms(9);
+    testSingleStatic(POS_ALL, POS_MASS, true, group);
+}
+
+TEST_F(PositionCalculationTest, ComputesPositionsWithCompleteWhole)
+{
+    const int group[] = { 0, 1, 2, 3, 4, 8 };
+    topManager_.initAtoms(9);
+    topManager_.initUniformResidues(3);
+    testSingleStatic(POS_RES, POS_COMPLWHOLE, true, group);
+}
+
+TEST_F(PositionCalculationTest, ComputesPositionsWithCompleteMax)
+{
+    const int maxGroup[]  = { 0, 1, 4, 5, 6, 8 };
+    const int evalGroup[] = { 0, 1, 5, 6 };
+    topManager_.initAtoms(9);
+    topManager_.initUniformResidues(3);
+    testSingleDynamic(POS_RES, POS_COMPLMAX, true, maxGroup, evalGroup);
+}
+
+TEST_F(PositionCalculationTest, ComputesPositionMask)
+{
+    const int maxGroup[]  = { 0, 1, 2, 3, 4, 5 };
+    const int evalGroup[] = { 1, 2, 4 };
+    topManager_.initAtoms(6);
+    testSingleDynamic(POS_ATOM, POS_MASKONLY, false, maxGroup, evalGroup);
+}
+
+// TODO: Check for POS_ALL_PBC
+
+TEST_F(PositionCalculationTest, HandlesIdenticalStaticCalculations)
+{
+    const int group[] = { 0, 1, 4, 5, 6, 7 };
+    topManager_.initAtoms(9);
+    topManager_.initUniformResidues(3);
+
+    gmx_ana_poscalc_t *pc1 = createCalculation(POS_RES, 0);
+    gmx_ana_poscalc_t *pc2 = createCalculation(POS_RES, 0);
+    gmx_ana_poscalc_t *pc3 = createCalculation(POS_RES, 0);
+    setMaximumGroup(pc1, group);
+    setMaximumGroup(pc2, group);
+    setMaximumGroup(pc3, group);
+    gmx_ana_pos_t *p1 = initPositions(pc1, "Positions");
+    gmx_ana_pos_t *p2 = initPositions(pc2, "Positions");
+    gmx_ana_pos_t *p3 = initPositions(pc3, "Positions");
+    checkInitialized();
+    {
+        pcc_.initEvaluation();
+        pcc_.initFrame();
+        generateCoordinates();
+        gmx::test::TestReferenceChecker frameCompound(
+                checker_.checkCompound("EvaluatedPositions", "Frame0"));
+        updateAndCheck(pc1, p1, group, &frameCompound, "Positions");
+        updateAndCheck(pc2, p2, group, &frameCompound, "Positions");
+        updateAndCheck(pc3, p3, group, &frameCompound, "Positions");
+    }
+}
+
+TEST_F(PositionCalculationTest, HandlesOverlappingStaticCalculations)
+{
+    const int group1[] = { 0, 1, 4, 5 };
+    const int group2[] = { 4, 5, 7, 8 };
+    topManager_.initAtoms(9);
+    topManager_.initUniformResidues(3);
+
+    gmx_ana_poscalc_t *pc1 = createCalculation(POS_RES, 0);
+    gmx_ana_poscalc_t *pc2 = createCalculation(POS_RES, 0);
+    setMaximumGroup(pc1, group1);
+    setMaximumGroup(pc2, group2);
+    gmx_ana_pos_t *p1 = initPositions(pc1, "P1");
+    gmx_ana_pos_t *p2 = initPositions(pc2, "P2");
+    checkInitialized();
+    {
+        pcc_.initEvaluation();
+        pcc_.initFrame();
+        generateCoordinates();
+        gmx::test::TestReferenceChecker frameCompound(
+                checker_.checkCompound("EvaluatedPositions", "Frame0"));
+        updateAndCheck(pc1, p1, group1, &frameCompound, "P1");
+        updateAndCheck(pc2, p2, group2, &frameCompound, "P2");
+    }
+}
+
+// TODO: Check for handling of more multiple calculation cases
+
+} // namespace
diff --git a/src/gromacs/selection/tests/refdata/PositionCalculationTest_ComputesAtomPositions.xml b/src/gromacs/selection/tests/refdata/PositionCalculationTest_ComputesAtomPositions.xml
new file mode 100644 (file)
index 0000000..ac1c908
--- /dev/null
@@ -0,0 +1,148 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <InitializedPositions>
+    <Positions>
+      <Int Name="Count">4</Int>
+      <String Name="Type">atoms</String>
+      <Sequence Name="Block">
+        <Int Name="Length">5</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+      </Sequence>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">1</Int>
+          <Int>0</Int>
+        </Sequence>
+        <Int Name="RefId">0</Int>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">1</Int>
+          <Int>1</Int>
+        </Sequence>
+        <Int Name="RefId">1</Int>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">1</Int>
+          <Int>2</Int>
+        </Sequence>
+        <Int Name="RefId">2</Int>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">1</Int>
+          <Int>3</Int>
+        </Sequence>
+        <Int Name="RefId">3</Int>
+      </Position>
+    </Positions>
+  </InitializedPositions>
+  <EvaluatedPositions Name="Frame0">
+    <Positions>
+      <Int Name="Count">4</Int>
+      <String Name="Type">atoms</String>
+      <Sequence Name="Block">
+        <Int Name="Length">5</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+      </Sequence>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">1</Int>
+          <Int>0</Int>
+        </Sequence>
+        <Int Name="RefId">0</Int>
+        <Vector Name="Coordinates">
+          <Real Name="X">0.000000</Real>
+          <Real Name="Y">0.000000</Real>
+          <Real Name="Z">0.000000</Real>
+        </Vector>
+        <Vector Name="Velocity">
+          <Real Name="X">0.000000</Real>
+          <Real Name="Y">0.000000</Real>
+          <Real Name="Z">1.000000</Real>
+        </Vector>
+        <Vector Name="Force">
+          <Real Name="X">0.000000</Real>
+          <Real Name="Y">0.000000</Real>
+          <Real Name="Z">-1.000000</Real>
+        </Vector>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">1</Int>
+          <Int>1</Int>
+        </Sequence>
+        <Int Name="RefId">1</Int>
+        <Vector Name="Coordinates">
+          <Real Name="X">1.000000</Real>
+          <Real Name="Y">0.000000</Real>
+          <Real Name="Z">0.000000</Real>
+        </Vector>
+        <Vector Name="Velocity">
+          <Real Name="X">1.000000</Real>
+          <Real Name="Y">0.000000</Real>
+          <Real Name="Z">1.000000</Real>
+        </Vector>
+        <Vector Name="Force">
+          <Real Name="X">1.000000</Real>
+          <Real Name="Y">0.000000</Real>
+          <Real Name="Z">-1.000000</Real>
+        </Vector>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">1</Int>
+          <Int>2</Int>
+        </Sequence>
+        <Int Name="RefId">2</Int>
+        <Vector Name="Coordinates">
+          <Real Name="X">2.000000</Real>
+          <Real Name="Y">0.000000</Real>
+          <Real Name="Z">0.000000</Real>
+        </Vector>
+        <Vector Name="Velocity">
+          <Real Name="X">2.000000</Real>
+          <Real Name="Y">0.000000</Real>
+          <Real Name="Z">1.000000</Real>
+        </Vector>
+        <Vector Name="Force">
+          <Real Name="X">2.000000</Real>
+          <Real Name="Y">0.000000</Real>
+          <Real Name="Z">-1.000000</Real>
+        </Vector>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">1</Int>
+          <Int>3</Int>
+        </Sequence>
+        <Int Name="RefId">3</Int>
+        <Vector Name="Coordinates">
+          <Real Name="X">3.000000</Real>
+          <Real Name="Y">0.000000</Real>
+          <Real Name="Z">0.000000</Real>
+        </Vector>
+        <Vector Name="Velocity">
+          <Real Name="X">3.000000</Real>
+          <Real Name="Y">0.000000</Real>
+          <Real Name="Z">1.000000</Real>
+        </Vector>
+        <Vector Name="Force">
+          <Real Name="X">3.000000</Real>
+          <Real Name="Y">0.000000</Real>
+          <Real Name="Z">-1.000000</Real>
+        </Vector>
+      </Position>
+    </Positions>
+  </EvaluatedPositions>
+</ReferenceData>
diff --git a/src/gromacs/selection/tests/refdata/PositionCalculationTest_ComputesGroupCOGPositions.xml b/src/gromacs/selection/tests/refdata/PositionCalculationTest_ComputesGroupCOGPositions.xml
new file mode 100644 (file)
index 0000000..99fab25
--- /dev/null
@@ -0,0 +1,71 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <InitializedPositions>
+    <Positions>
+      <Int Name="Count">1</Int>
+      <String Name="Type">single</String>
+      <Sequence Name="Block">
+        <Int Name="Length">2</Int>
+        <Int>0</Int>
+        <Int>9</Int>
+      </Sequence>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">9</Int>
+          <Int>0</Int>
+          <Int>1</Int>
+          <Int>2</Int>
+          <Int>3</Int>
+          <Int>4</Int>
+          <Int>5</Int>
+          <Int>6</Int>
+          <Int>7</Int>
+          <Int>8</Int>
+        </Sequence>
+        <Int Name="RefId">0</Int>
+      </Position>
+    </Positions>
+  </InitializedPositions>
+  <EvaluatedPositions Name="Frame0">
+    <Positions>
+      <Int Name="Count">1</Int>
+      <String Name="Type">single</String>
+      <Sequence Name="Block">
+        <Int Name="Length">2</Int>
+        <Int>0</Int>
+        <Int>9</Int>
+      </Sequence>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">9</Int>
+          <Int>0</Int>
+          <Int>1</Int>
+          <Int>2</Int>
+          <Int>3</Int>
+          <Int>4</Int>
+          <Int>5</Int>
+          <Int>6</Int>
+          <Int>7</Int>
+          <Int>8</Int>
+        </Sequence>
+        <Int Name="RefId">0</Int>
+        <Vector Name="Coordinates">
+          <Real Name="X">4.000000</Real>
+          <Real Name="Y">0.000000</Real>
+          <Real Name="Z">0.000000</Real>
+        </Vector>
+        <Vector Name="Velocity">
+          <Real Name="X">4.000000</Real>
+          <Real Name="Y">0.000000</Real>
+          <Real Name="Z">1.000000</Real>
+        </Vector>
+        <Vector Name="Force">
+          <Real Name="X">42.000000</Real>
+          <Real Name="Y">0.000000</Real>
+          <Real Name="Z">-10.000000</Real>
+        </Vector>
+      </Position>
+    </Positions>
+  </EvaluatedPositions>
+</ReferenceData>
diff --git a/src/gromacs/selection/tests/refdata/PositionCalculationTest_ComputesGroupCOMPositions.xml b/src/gromacs/selection/tests/refdata/PositionCalculationTest_ComputesGroupCOMPositions.xml
new file mode 100644 (file)
index 0000000..7186883
--- /dev/null
@@ -0,0 +1,71 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <InitializedPositions>
+    <Positions>
+      <Int Name="Count">1</Int>
+      <String Name="Type">single</String>
+      <Sequence Name="Block">
+        <Int Name="Length">2</Int>
+        <Int>0</Int>
+        <Int>9</Int>
+      </Sequence>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">9</Int>
+          <Int>0</Int>
+          <Int>1</Int>
+          <Int>2</Int>
+          <Int>3</Int>
+          <Int>4</Int>
+          <Int>5</Int>
+          <Int>6</Int>
+          <Int>7</Int>
+          <Int>8</Int>
+        </Sequence>
+        <Int Name="RefId">0</Int>
+      </Position>
+    </Positions>
+  </InitializedPositions>
+  <EvaluatedPositions Name="Frame0">
+    <Positions>
+      <Int Name="Count">1</Int>
+      <String Name="Type">single</String>
+      <Sequence Name="Block">
+        <Int Name="Length">2</Int>
+        <Int>0</Int>
+        <Int>9</Int>
+      </Sequence>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">9</Int>
+          <Int>0</Int>
+          <Int>1</Int>
+          <Int>2</Int>
+          <Int>3</Int>
+          <Int>4</Int>
+          <Int>5</Int>
+          <Int>6</Int>
+          <Int>7</Int>
+          <Int>8</Int>
+        </Sequence>
+        <Int Name="RefId">0</Int>
+        <Vector Name="Coordinates">
+          <Real Name="X">3.750000</Real>
+          <Real Name="Y">0.000000</Real>
+          <Real Name="Z">0.000000</Real>
+        </Vector>
+        <Vector Name="Velocity">
+          <Real Name="X">3.750000</Real>
+          <Real Name="Y">0.000000</Real>
+          <Real Name="Z">1.000000</Real>
+        </Vector>
+        <Vector Name="Force">
+          <Real Name="X">36.000000</Real>
+          <Real Name="Y">0.000000</Real>
+          <Real Name="Z">-9.000000</Real>
+        </Vector>
+      </Position>
+    </Positions>
+  </EvaluatedPositions>
+</ReferenceData>
diff --git a/src/gromacs/selection/tests/refdata/PositionCalculationTest_ComputesPositionMask.xml b/src/gromacs/selection/tests/refdata/PositionCalculationTest_ComputesPositionMask.xml
new file mode 100644 (file)
index 0000000..9e5845b
--- /dev/null
@@ -0,0 +1,150 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <InitializedPositions>
+    <Positions>
+      <Int Name="Count">6</Int>
+      <String Name="Type">atoms</String>
+      <Sequence Name="Block">
+        <Int Name="Length">7</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+        <Int>6</Int>
+      </Sequence>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">1</Int>
+          <Int>0</Int>
+        </Sequence>
+        <Int Name="RefId">0</Int>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">1</Int>
+          <Int>1</Int>
+        </Sequence>
+        <Int Name="RefId">1</Int>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">1</Int>
+          <Int>2</Int>
+        </Sequence>
+        <Int Name="RefId">2</Int>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">1</Int>
+          <Int>3</Int>
+        </Sequence>
+        <Int Name="RefId">3</Int>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">1</Int>
+          <Int>4</Int>
+        </Sequence>
+        <Int Name="RefId">4</Int>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">1</Int>
+          <Int>5</Int>
+        </Sequence>
+        <Int Name="RefId">5</Int>
+      </Position>
+    </Positions>
+  </InitializedPositions>
+  <EvaluatedPositions Name="Frame0">
+    <Positions>
+      <Int Name="Count">6</Int>
+      <String Name="Type">atoms</String>
+      <Sequence Name="Block">
+        <Int Name="Length">7</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+        <Int>6</Int>
+      </Sequence>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">1</Int>
+          <Int>0</Int>
+        </Sequence>
+        <Int Name="RefId">-1</Int>
+        <Vector Name="Coordinates">
+          <Real Name="X">0.000000</Real>
+          <Real Name="Y">0.000000</Real>
+          <Real Name="Z">0.000000</Real>
+        </Vector>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">1</Int>
+          <Int>1</Int>
+        </Sequence>
+        <Int Name="RefId">1</Int>
+        <Vector Name="Coordinates">
+          <Real Name="X">1.000000</Real>
+          <Real Name="Y">0.000000</Real>
+          <Real Name="Z">0.000000</Real>
+        </Vector>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">1</Int>
+          <Int>2</Int>
+        </Sequence>
+        <Int Name="RefId">2</Int>
+        <Vector Name="Coordinates">
+          <Real Name="X">2.000000</Real>
+          <Real Name="Y">0.000000</Real>
+          <Real Name="Z">0.000000</Real>
+        </Vector>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">1</Int>
+          <Int>3</Int>
+        </Sequence>
+        <Int Name="RefId">-1</Int>
+        <Vector Name="Coordinates">
+          <Real Name="X">3.000000</Real>
+          <Real Name="Y">0.000000</Real>
+          <Real Name="Z">0.000000</Real>
+        </Vector>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">1</Int>
+          <Int>4</Int>
+        </Sequence>
+        <Int Name="RefId">4</Int>
+        <Vector Name="Coordinates">
+          <Real Name="X">4.000000</Real>
+          <Real Name="Y">0.000000</Real>
+          <Real Name="Z">0.000000</Real>
+        </Vector>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">1</Int>
+          <Int>5</Int>
+        </Sequence>
+        <Int Name="RefId">-1</Int>
+        <Vector Name="Coordinates">
+          <Real Name="X">5.000000</Real>
+          <Real Name="Y">0.000000</Real>
+          <Real Name="Z">0.000000</Real>
+        </Vector>
+      </Position>
+    </Positions>
+  </EvaluatedPositions>
+</ReferenceData>
diff --git a/src/gromacs/selection/tests/refdata/PositionCalculationTest_ComputesPositionsWithCompleteMax.xml b/src/gromacs/selection/tests/refdata/PositionCalculationTest_ComputesPositionsWithCompleteMax.xml
new file mode 100644 (file)
index 0000000..ad3742b
--- /dev/null
@@ -0,0 +1,91 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <InitializedPositions>
+    <Positions>
+      <Int Name="Count">3</Int>
+      <String Name="Type">residues</String>
+      <Sequence Name="Block">
+        <Int Name="Length">4</Int>
+        <Int>0</Int>
+        <Int>2</Int>
+        <Int>4</Int>
+        <Int>6</Int>
+      </Sequence>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">2</Int>
+          <Int>0</Int>
+          <Int>1</Int>
+        </Sequence>
+        <Int Name="RefId">0</Int>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">2</Int>
+          <Int>4</Int>
+          <Int>5</Int>
+        </Sequence>
+        <Int Name="RefId">1</Int>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">2</Int>
+          <Int>6</Int>
+          <Int>8</Int>
+        </Sequence>
+        <Int Name="RefId">2</Int>
+      </Position>
+    </Positions>
+  </InitializedPositions>
+  <EvaluatedPositions Name="Frame0">
+    <Positions>
+      <Int Name="Count">3</Int>
+      <String Name="Type">residues</String>
+      <Sequence Name="Block">
+        <Int Name="Length">4</Int>
+        <Int>0</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+      </Sequence>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">2</Int>
+          <Int>0</Int>
+          <Int>1</Int>
+        </Sequence>
+        <Int Name="RefId">0</Int>
+        <Vector Name="Coordinates">
+          <Real Name="X">0.500000</Real>
+          <Real Name="Y">0.000000</Real>
+          <Real Name="Z">0.000000</Real>
+        </Vector>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">1</Int>
+          <Int>5</Int>
+        </Sequence>
+        <Int Name="RefId">1</Int>
+        <Vector Name="Coordinates">
+          <Real Name="X">4.500000</Real>
+          <Real Name="Y">1.000000</Real>
+          <Real Name="Z">0.000000</Real>
+        </Vector>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">1</Int>
+          <Int>6</Int>
+        </Sequence>
+        <Int Name="RefId">2</Int>
+        <Vector Name="Coordinates">
+          <Real Name="X">7.000000</Real>
+          <Real Name="Y">2.000000</Real>
+          <Real Name="Z">0.000000</Real>
+        </Vector>
+      </Position>
+    </Positions>
+  </EvaluatedPositions>
+</ReferenceData>
diff --git a/src/gromacs/selection/tests/refdata/PositionCalculationTest_ComputesPositionsWithCompleteWhole.xml b/src/gromacs/selection/tests/refdata/PositionCalculationTest_ComputesPositionsWithCompleteWhole.xml
new file mode 100644 (file)
index 0000000..0da96ad
--- /dev/null
@@ -0,0 +1,93 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <InitializedPositions>
+    <Positions>
+      <Int Name="Count">3</Int>
+      <String Name="Type">residues</String>
+      <Sequence Name="Block">
+        <Int Name="Length">4</Int>
+        <Int>0</Int>
+        <Int>3</Int>
+        <Int>5</Int>
+        <Int>6</Int>
+      </Sequence>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">3</Int>
+          <Int>0</Int>
+          <Int>1</Int>
+          <Int>2</Int>
+        </Sequence>
+        <Int Name="RefId">0</Int>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">2</Int>
+          <Int>3</Int>
+          <Int>4</Int>
+        </Sequence>
+        <Int Name="RefId">1</Int>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">1</Int>
+          <Int>8</Int>
+        </Sequence>
+        <Int Name="RefId">2</Int>
+      </Position>
+    </Positions>
+  </InitializedPositions>
+  <EvaluatedPositions Name="Frame0">
+    <Positions>
+      <Int Name="Count">3</Int>
+      <String Name="Type">residues</String>
+      <Sequence Name="Block">
+        <Int Name="Length">4</Int>
+        <Int>0</Int>
+        <Int>3</Int>
+        <Int>5</Int>
+        <Int>6</Int>
+      </Sequence>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">3</Int>
+          <Int>0</Int>
+          <Int>1</Int>
+          <Int>2</Int>
+        </Sequence>
+        <Int Name="RefId">0</Int>
+        <Vector Name="Coordinates">
+          <Real Name="X">1.000000</Real>
+          <Real Name="Y">0.000000</Real>
+          <Real Name="Z">0.000000</Real>
+        </Vector>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">2</Int>
+          <Int>3</Int>
+          <Int>4</Int>
+        </Sequence>
+        <Int Name="RefId">1</Int>
+        <Vector Name="Coordinates">
+          <Real Name="X">4.000000</Real>
+          <Real Name="Y">1.000000</Real>
+          <Real Name="Z">0.000000</Real>
+        </Vector>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">1</Int>
+          <Int>8</Int>
+        </Sequence>
+        <Int Name="RefId">2</Int>
+        <Vector Name="Coordinates">
+          <Real Name="X">7.000000</Real>
+          <Real Name="Y">2.000000</Real>
+          <Real Name="Z">0.000000</Real>
+        </Vector>
+      </Position>
+    </Positions>
+  </EvaluatedPositions>
+</ReferenceData>
diff --git a/src/gromacs/selection/tests/refdata/PositionCalculationTest_ComputesResidueCOGPositions.xml b/src/gromacs/selection/tests/refdata/PositionCalculationTest_ComputesResidueCOGPositions.xml
new file mode 100644 (file)
index 0000000..d0010f6
--- /dev/null
@@ -0,0 +1,123 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <InitializedPositions>
+    <Positions>
+      <Int Name="Count">3</Int>
+      <String Name="Type">residues</String>
+      <Sequence Name="Block">
+        <Int Name="Length">4</Int>
+        <Int>0</Int>
+        <Int>3</Int>
+        <Int>5</Int>
+        <Int>6</Int>
+      </Sequence>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">3</Int>
+          <Int>0</Int>
+          <Int>1</Int>
+          <Int>2</Int>
+        </Sequence>
+        <Int Name="RefId">0</Int>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">2</Int>
+          <Int>3</Int>
+          <Int>4</Int>
+        </Sequence>
+        <Int Name="RefId">1</Int>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">1</Int>
+          <Int>8</Int>
+        </Sequence>
+        <Int Name="RefId">2</Int>
+      </Position>
+    </Positions>
+  </InitializedPositions>
+  <EvaluatedPositions Name="Frame0">
+    <Positions>
+      <Int Name="Count">3</Int>
+      <String Name="Type">residues</String>
+      <Sequence Name="Block">
+        <Int Name="Length">4</Int>
+        <Int>0</Int>
+        <Int>3</Int>
+        <Int>5</Int>
+        <Int>6</Int>
+      </Sequence>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">3</Int>
+          <Int>0</Int>
+          <Int>1</Int>
+          <Int>2</Int>
+        </Sequence>
+        <Int Name="RefId">0</Int>
+        <Vector Name="Coordinates">
+          <Real Name="X">1.000000</Real>
+          <Real Name="Y">0.000000</Real>
+          <Real Name="Z">0.000000</Real>
+        </Vector>
+        <Vector Name="Velocity">
+          <Real Name="X">1.000000</Real>
+          <Real Name="Y">0.000000</Real>
+          <Real Name="Z">1.000000</Real>
+        </Vector>
+        <Vector Name="Force">
+          <Real Name="X">4.000000</Real>
+          <Real Name="Y">0.000000</Real>
+          <Real Name="Z">-3.333333</Real>
+        </Vector>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">2</Int>
+          <Int>3</Int>
+          <Int>4</Int>
+        </Sequence>
+        <Int Name="RefId">1</Int>
+        <Vector Name="Coordinates">
+          <Real Name="X">3.500000</Real>
+          <Real Name="Y">1.000000</Real>
+          <Real Name="Z">0.000000</Real>
+        </Vector>
+        <Vector Name="Velocity">
+          <Real Name="X">3.500000</Real>
+          <Real Name="Y">1.000000</Real>
+          <Real Name="Z">1.000000</Real>
+        </Vector>
+        <Vector Name="Force">
+          <Real Name="X">8.250000</Real>
+          <Real Name="Y">2.250000</Real>
+          <Real Name="Z">-2.250000</Real>
+        </Vector>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">1</Int>
+          <Int>8</Int>
+        </Sequence>
+        <Int Name="RefId">2</Int>
+        <Vector Name="Coordinates">
+          <Real Name="X">8.000000</Real>
+          <Real Name="Y">2.000000</Real>
+          <Real Name="Z">0.000000</Real>
+        </Vector>
+        <Vector Name="Velocity">
+          <Real Name="X">8.000000</Real>
+          <Real Name="Y">2.000000</Real>
+          <Real Name="Z">1.000000</Real>
+        </Vector>
+        <Vector Name="Force">
+          <Real Name="X">8.000000</Real>
+          <Real Name="Y">2.000000</Real>
+          <Real Name="Z">-1.000000</Real>
+        </Vector>
+      </Position>
+    </Positions>
+  </EvaluatedPositions>
+</ReferenceData>
diff --git a/src/gromacs/selection/tests/refdata/PositionCalculationTest_ComputesResidueCOMPositions.xml b/src/gromacs/selection/tests/refdata/PositionCalculationTest_ComputesResidueCOMPositions.xml
new file mode 100644 (file)
index 0000000..c9e54fc
--- /dev/null
@@ -0,0 +1,123 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <InitializedPositions>
+    <Positions>
+      <Int Name="Count">3</Int>
+      <String Name="Type">residues</String>
+      <Sequence Name="Block">
+        <Int Name="Length">4</Int>
+        <Int>0</Int>
+        <Int>3</Int>
+        <Int>5</Int>
+        <Int>6</Int>
+      </Sequence>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">3</Int>
+          <Int>0</Int>
+          <Int>1</Int>
+          <Int>2</Int>
+        </Sequence>
+        <Int Name="RefId">0</Int>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">2</Int>
+          <Int>3</Int>
+          <Int>4</Int>
+        </Sequence>
+        <Int Name="RefId">1</Int>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">1</Int>
+          <Int>8</Int>
+        </Sequence>
+        <Int Name="RefId">2</Int>
+      </Position>
+    </Positions>
+  </InitializedPositions>
+  <EvaluatedPositions Name="Frame0">
+    <Positions>
+      <Int Name="Count">3</Int>
+      <String Name="Type">residues</String>
+      <Sequence Name="Block">
+        <Int Name="Length">4</Int>
+        <Int>0</Int>
+        <Int>3</Int>
+        <Int>5</Int>
+        <Int>6</Int>
+      </Sequence>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">3</Int>
+          <Int>0</Int>
+          <Int>1</Int>
+          <Int>2</Int>
+        </Sequence>
+        <Int Name="RefId">0</Int>
+        <Vector Name="Coordinates">
+          <Real Name="X">0.750000</Real>
+          <Real Name="Y">0.000000</Real>
+          <Real Name="Z">0.000000</Real>
+        </Vector>
+        <Vector Name="Velocity">
+          <Real Name="X">0.750000</Real>
+          <Real Name="Y">0.000000</Real>
+          <Real Name="Z">1.000000</Real>
+        </Vector>
+        <Vector Name="Force">
+          <Real Name="X">3.000000</Real>
+          <Real Name="Y">0.000000</Real>
+          <Real Name="Z">-3.000000</Real>
+        </Vector>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">2</Int>
+          <Int>3</Int>
+          <Int>4</Int>
+        </Sequence>
+        <Int Name="RefId">1</Int>
+        <Vector Name="Coordinates">
+          <Real Name="X">3.333333</Real>
+          <Real Name="Y">1.000000</Real>
+          <Real Name="Z">0.000000</Real>
+        </Vector>
+        <Vector Name="Velocity">
+          <Real Name="X">3.333333</Real>
+          <Real Name="Y">1.000000</Real>
+          <Real Name="Z">1.000000</Real>
+        </Vector>
+        <Vector Name="Force">
+          <Real Name="X">7.000000</Real>
+          <Real Name="Y">2.000000</Real>
+          <Real Name="Z">-2.000000</Real>
+        </Vector>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">1</Int>
+          <Int>8</Int>
+        </Sequence>
+        <Int Name="RefId">2</Int>
+        <Vector Name="Coordinates">
+          <Real Name="X">8.000000</Real>
+          <Real Name="Y">2.000000</Real>
+          <Real Name="Z">0.000000</Real>
+        </Vector>
+        <Vector Name="Velocity">
+          <Real Name="X">8.000000</Real>
+          <Real Name="Y">2.000000</Real>
+          <Real Name="Z">1.000000</Real>
+        </Vector>
+        <Vector Name="Force">
+          <Real Name="X">8.000000</Real>
+          <Real Name="Y">2.000000</Real>
+          <Real Name="Z">-1.000000</Real>
+        </Vector>
+      </Position>
+    </Positions>
+  </EvaluatedPositions>
+</ReferenceData>
diff --git a/src/gromacs/selection/tests/refdata/PositionCalculationTest_HandlesIdenticalStaticCalculations.xml b/src/gromacs/selection/tests/refdata/PositionCalculationTest_HandlesIdenticalStaticCalculations.xml
new file mode 100644 (file)
index 0000000..08febd7
--- /dev/null
@@ -0,0 +1,93 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <InitializedPositions>
+    <Positions Name="Positions">
+      <Int Name="Count">3</Int>
+      <String Name="Type">residues</String>
+      <Sequence Name="Block">
+        <Int Name="Length">4</Int>
+        <Int>0</Int>
+        <Int>2</Int>
+        <Int>4</Int>
+        <Int>6</Int>
+      </Sequence>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">2</Int>
+          <Int>0</Int>
+          <Int>1</Int>
+        </Sequence>
+        <Int Name="RefId">0</Int>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">2</Int>
+          <Int>4</Int>
+          <Int>5</Int>
+        </Sequence>
+        <Int Name="RefId">1</Int>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">2</Int>
+          <Int>6</Int>
+          <Int>7</Int>
+        </Sequence>
+        <Int Name="RefId">2</Int>
+      </Position>
+    </Positions>
+  </InitializedPositions>
+  <EvaluatedPositions Name="Frame0">
+    <Positions Name="Positions">
+      <Int Name="Count">3</Int>
+      <String Name="Type">residues</String>
+      <Sequence Name="Block">
+        <Int Name="Length">4</Int>
+        <Int>0</Int>
+        <Int>2</Int>
+        <Int>4</Int>
+        <Int>6</Int>
+      </Sequence>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">2</Int>
+          <Int>0</Int>
+          <Int>1</Int>
+        </Sequence>
+        <Int Name="RefId">0</Int>
+        <Vector Name="Coordinates">
+          <Real Name="X">0.500000</Real>
+          <Real Name="Y">0.000000</Real>
+          <Real Name="Z">0.000000</Real>
+        </Vector>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">2</Int>
+          <Int>4</Int>
+          <Int>5</Int>
+        </Sequence>
+        <Int Name="RefId">1</Int>
+        <Vector Name="Coordinates">
+          <Real Name="X">4.500000</Real>
+          <Real Name="Y">1.000000</Real>
+          <Real Name="Z">0.000000</Real>
+        </Vector>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">2</Int>
+          <Int>6</Int>
+          <Int>7</Int>
+        </Sequence>
+        <Int Name="RefId">2</Int>
+        <Vector Name="Coordinates">
+          <Real Name="X">6.500000</Real>
+          <Real Name="Y">2.000000</Real>
+          <Real Name="Z">0.000000</Real>
+        </Vector>
+      </Position>
+    </Positions>
+  </EvaluatedPositions>
+</ReferenceData>
diff --git a/src/gromacs/selection/tests/refdata/PositionCalculationTest_HandlesOverlappingStaticCalculations.xml b/src/gromacs/selection/tests/refdata/PositionCalculationTest_HandlesOverlappingStaticCalculations.xml
new file mode 100644 (file)
index 0000000..35a277f
--- /dev/null
@@ -0,0 +1,132 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <InitializedPositions>
+    <Positions Name="P1">
+      <Int Name="Count">2</Int>
+      <String Name="Type">residues</String>
+      <Sequence Name="Block">
+        <Int Name="Length">3</Int>
+        <Int>0</Int>
+        <Int>2</Int>
+        <Int>4</Int>
+      </Sequence>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">2</Int>
+          <Int>0</Int>
+          <Int>1</Int>
+        </Sequence>
+        <Int Name="RefId">0</Int>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">2</Int>
+          <Int>4</Int>
+          <Int>5</Int>
+        </Sequence>
+        <Int Name="RefId">1</Int>
+      </Position>
+    </Positions>
+    <Positions Name="P2">
+      <Int Name="Count">2</Int>
+      <String Name="Type">residues</String>
+      <Sequence Name="Block">
+        <Int Name="Length">3</Int>
+        <Int>0</Int>
+        <Int>2</Int>
+        <Int>4</Int>
+      </Sequence>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">2</Int>
+          <Int>4</Int>
+          <Int>5</Int>
+        </Sequence>
+        <Int Name="RefId">0</Int>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">2</Int>
+          <Int>7</Int>
+          <Int>8</Int>
+        </Sequence>
+        <Int Name="RefId">1</Int>
+      </Position>
+    </Positions>
+  </InitializedPositions>
+  <EvaluatedPositions Name="Frame0">
+    <Positions Name="P1">
+      <Int Name="Count">2</Int>
+      <String Name="Type">residues</String>
+      <Sequence Name="Block">
+        <Int Name="Length">3</Int>
+        <Int>0</Int>
+        <Int>2</Int>
+        <Int>4</Int>
+      </Sequence>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">2</Int>
+          <Int>0</Int>
+          <Int>1</Int>
+        </Sequence>
+        <Int Name="RefId">0</Int>
+        <Vector Name="Coordinates">
+          <Real Name="X">0.500000</Real>
+          <Real Name="Y">0.000000</Real>
+          <Real Name="Z">0.000000</Real>
+        </Vector>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">2</Int>
+          <Int>4</Int>
+          <Int>5</Int>
+        </Sequence>
+        <Int Name="RefId">1</Int>
+        <Vector Name="Coordinates">
+          <Real Name="X">4.500000</Real>
+          <Real Name="Y">1.000000</Real>
+          <Real Name="Z">0.000000</Real>
+        </Vector>
+      </Position>
+    </Positions>
+    <Positions Name="P2">
+      <Int Name="Count">2</Int>
+      <String Name="Type">residues</String>
+      <Sequence Name="Block">
+        <Int Name="Length">3</Int>
+        <Int>0</Int>
+        <Int>2</Int>
+        <Int>4</Int>
+      </Sequence>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">2</Int>
+          <Int>4</Int>
+          <Int>5</Int>
+        </Sequence>
+        <Int Name="RefId">0</Int>
+        <Vector Name="Coordinates">
+          <Real Name="X">4.500000</Real>
+          <Real Name="Y">1.000000</Real>
+          <Real Name="Z">0.000000</Real>
+        </Vector>
+      </Position>
+      <Position>
+        <Sequence Name="Atoms">
+          <Int Name="Length">2</Int>
+          <Int>7</Int>
+          <Int>8</Int>
+        </Sequence>
+        <Int Name="RefId">1</Int>
+        <Vector Name="Coordinates">
+          <Real Name="X">7.500000</Real>
+          <Real Name="Y">2.000000</Real>
+          <Real Name="Z">0.000000</Real>
+        </Vector>
+      </Position>
+    </Positions>
+  </EvaluatedPositions>
+</ReferenceData>
index b254384bdf7c6db811940ffb0e564f6617328ab5..5f6cb924d267b745064a2cea77f589b965149baf 100644 (file)
     </table>
 </xsl:template>
 
+<!-- Position calculation reference data -->
+
+<xsl:template match="InitializedPositions">
+    <h2>Initialized Positions</h2>
+    <xsl:apply-templates />
+</xsl:template>
+
+<xsl:template match="EvaluatedPositions">
+    <h2>Evaluated for <xsl:value-of select="@Name"/></h2>
+    <xsl:apply-templates />
+</xsl:template>
+
+<xsl:template match="Positions">
+    <xsl:if test="@Name">
+        <h3><xsl:value-of select="@Name"/></h3>
+    </xsl:if>
+    <table>
+        <tr>
+            <td>Count:</td>
+            <td>
+                <xsl:value-of select="Int[@Name='Count']"/>
+                (type: <xsl:value-of select="String[@Name='Type']"/>)
+            </td>
+        </tr>
+        <tr>
+            <td>Blocks:</td>
+            <td>
+                <xsl:call-template name="SequenceAsCSV">
+                    <xsl:with-param name="root" select="Sequence[@Name='Block']"/>
+                </xsl:call-template>
+            </td>
+        </tr>
+    </table>
+    <table border="1">
+        <tr>
+            <th>RefId</th>
+            <th>Atom count</th>
+            <th>Atoms</th>
+            <xsl:if test="Position/Vector[@Name='Coordinates']">
+                <th>Coordinates</th>
+            </xsl:if>
+            <xsl:if test="Position/Vector[@Name='Velocity']">
+                <th>Velocity</th>
+            </xsl:if>
+            <xsl:if test="Position/Vector[@Name='Force']">
+                <th>Force</th>
+            </xsl:if>
+        </tr>
+        <xsl:for-each select="Position">
+            <tr>
+                <td><xsl:value-of select="Int[@Name='RefId']"/></td>
+                <td><xsl:value-of select="Sequence[@Name='Atoms']/Int[@Name='Length']"/></td>
+                <td>
+                    <xsl:call-template name="SequenceAsCSV">
+                        <xsl:with-param name="root" select="Sequence[@Name='Atoms']"/>
+                    </xsl:call-template>
+                </td>
+                <xsl:if test="Vector[@Name='Coordinates']">
+                    <td>
+                        <xsl:apply-templates select="Vector[@Name='Coordinates']"/>
+                    </td>
+                </xsl:if>
+                <xsl:if test="Vector[@Name='Velocity']">
+                    <td>
+                        <xsl:apply-templates select="Vector[@Name='Velocity']"/>
+                    </td>
+                </xsl:if>
+                <xsl:if test="Vector[@Name='Force']">
+                    <td>
+                        <xsl:apply-templates select="Vector[@Name='Force']"/>
+                    </td>
+                </xsl:if>
+            </tr>
+        </xsl:for-each>
+    </table>
+</xsl:template>
+
 <!-- Selection reference data -->
 
 <xsl:key name="SelectionName" match="ParsedSelections/ParsedSelection" use="@Name"/>
index 5f9e4ee66487cb125a4627208aeee55f6e2b752d..c75e95ef2145415c7d90c791267b5f71645f67b1 100644 (file)
@@ -75,6 +75,8 @@ TopologyManager::~TopologyManager()
     if (frame_ != NULL)
     {
         sfree(frame_->x);
+        sfree(frame_->v);
+        sfree(frame_->f);
         sfree(frame_);
     }
 }
@@ -89,6 +91,28 @@ void TopologyManager::requestFrame()
     }
 }
 
+void TopologyManager::requestVelocities()
+{
+    GMX_RELEASE_ASSERT(frame_ != NULL,
+                       "Velocities requested before requesting a frame");
+    frame_->bV = TRUE;
+    if (frame_->natoms > 0)
+    {
+        snew(frame_->v, frame_->natoms);
+    }
+}
+
+void TopologyManager::requestForces()
+{
+    GMX_RELEASE_ASSERT(frame_ != NULL,
+                       "Forces requested before requesting a frame");
+    frame_->bF = TRUE;
+    if (frame_->natoms > 0)
+    {
+        snew(frame_->f, frame_->natoms);
+    }
+}
+
 void TopologyManager::loadTopology(const char *filename)
 {
     char    title[STRLEN];
@@ -131,6 +155,14 @@ void TopologyManager::initAtoms(int count)
         frame_->natoms = count;
         frame_->bX     = TRUE;
         snew(frame_->x, count);
+        if (frame_->bV)
+        {
+            snew(frame_->v, count);
+        }
+        if (frame_->bF)
+        {
+            snew(frame_->f, count);
+        }
     }
 }
 
index 7024f86b42345b6bc5efa6fc01d87f264e5905c6..893cbc206fe6fe05505012a72c53e8b10baac256 100644 (file)
@@ -56,6 +56,8 @@ class TopologyManager
         ~TopologyManager();
 
         void requestFrame();
+        void requestVelocities();
+        void requestForces();
 
         void loadTopology(const char *filename);
         void initAtoms(int count);