Add unit tests for selection index mapping.
authorTeemu Murtola <teemu.murtola@gmail.com>
Sun, 28 Apr 2013 10:43:28 +0000 (13:43 +0300)
committerGerrit Code Review <gerrit@gerrit.gromacs.org>
Mon, 17 Jun 2013 16:17:01 +0000 (18:17 +0200)
Add unit tests for parts of indexutil.* that are mainly used by the
selection position calculation engine.

Add required functionality to toputils.* and update typedefs.c to
support more flexible freeing of required data structures.

Part of #651, related to #1221.

Change-Id: Ibc68ad71a4834b991820014969be46152426a9f5

20 files changed:
src/gromacs/gmxlib/typedefs.c
src/gromacs/selection/indexutil.cpp
src/gromacs/selection/tests/CMakeLists.txt
src/gromacs/selection/tests/indexutil.cpp [new file with mode: 0644]
src/gromacs/selection/tests/refdata/IndexBlockTest_CreatesAtomBlock.xml [new file with mode: 0644]
src/gromacs/selection/tests/refdata/IndexBlockTest_CreatesMoleculeBlock.xml [new file with mode: 0644]
src/gromacs/selection/tests/refdata/IndexBlockTest_CreatesMoleculeBlockWithCompletion.xml [new file with mode: 0644]
src/gromacs/selection/tests/refdata/IndexBlockTest_CreatesResidueBlock.xml [new file with mode: 0644]
src/gromacs/selection/tests/refdata/IndexBlockTest_CreatesResidueBlockWithCompletion.xml [new file with mode: 0644]
src/gromacs/selection/tests/refdata/IndexBlockTest_CreatesSingleBlock.xml [new file with mode: 0644]
src/gromacs/selection/tests/refdata/IndexBlockTest_CreatesUnknownBlock.xml [new file with mode: 0644]
src/gromacs/selection/tests/refdata/IndexMapTest_HandlesMultipleRequests.xml [new file with mode: 0644]
src/gromacs/selection/tests/refdata/IndexMapTest_InitializesAtomBlock.xml [new file with mode: 0644]
src/gromacs/selection/tests/refdata/IndexMapTest_InitializesMoleculeBlock.xml [new file with mode: 0644]
src/gromacs/selection/tests/refdata/IndexMapTest_MapsResidueBlocks.xml [new file with mode: 0644]
src/gromacs/selection/tests/refdata/IndexMapTest_MapsResidueBlocksWithMask.xml [new file with mode: 0644]
src/gromacs/selection/tests/refdata/IndexMapTest_MapsSingleBlock.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 82d2b4a5fd856e88c62330a43c0e1f05567fde56..5c3a1bef1c9c7025626b57dd27de54c0d5b4be0f 100644 (file)
@@ -284,10 +284,9 @@ void done_blocka(t_blocka *block)
     block->nr    = 0;
     block->nra   = 0;
     sfree(block->index);
-    if (block->a)
-    {
-        sfree(block->a);
-    }
+    sfree(block->a);
+    block->index        = NULL;
+    block->a            = NULL;
     block->nalloc_index = 0;
     block->nalloc_a     = 0;
 }
@@ -849,27 +848,33 @@ void free_t_atoms(t_atoms *atoms, gmx_bool bFreeNames)
 {
     int i;
 
-    if (bFreeNames)
+    if (bFreeNames && atoms->atomname != NULL)
     {
         for (i = 0; i < atoms->nr; i++)
         {
-            sfree(*atoms->atomname[i]);
-            *atoms->atomname[i] = NULL;
+            if (atoms->atomname[i] != NULL)
+            {
+                sfree(*atoms->atomname[i]);
+                *atoms->atomname[i] = NULL;
+            }
         }
+    }
+    if (bFreeNames && atoms->resinfo != NULL)
+    {
         for (i = 0; i < atoms->nres; i++)
         {
-            sfree(*atoms->resinfo[i].name);
-            *atoms->resinfo[i].name = NULL;
+            if (atoms->resinfo[i].name != NULL)
+            {
+                sfree(*atoms->resinfo[i].name);
+                *atoms->resinfo[i].name = NULL;
+            }
         }
     }
     sfree(atoms->atomname);
     /* Do we need to free atomtype and atomtypeB as well ? */
     sfree(atoms->resinfo);
     sfree(atoms->atom);
-    if (atoms->pdbinfo)
-    {
-        sfree(atoms->pdbinfo);
-    }
+    sfree(atoms->pdbinfo);
     atoms->nr       = 0;
     atoms->nres     = 0;
     atoms->atomname = NULL;
index e9eda49f16944846addcccb17c3963cf342d5e04..819340f2a8f35a5259d091b32d15d3c4f3b0cd67 100644 (file)
@@ -957,6 +957,8 @@ gmx_ana_index_has_full_ablocks(gmx_ana_index_t *g, t_blocka *b)
  * \returns   true if \p g consists of one or more complete elements of type
  *   \p type, false otherwise.
  *
+ * \p g is assumed to be sorted, otherwise may return false negatives.
+ *
  * If \p type is \ref INDEX_ATOM, the return value is always true.
  * If \p type is \ref INDEX_UNKNOWN or \ref INDEX_ALL, the return value is
  * always false.
@@ -965,6 +967,7 @@ bool
 gmx_ana_index_has_complete_elems(gmx_ana_index_t *g, e_index_t type,
                                  t_topology *top)
 {
+    // TODO: Consider whether unsorted groups need to be supported better.
     switch (type)
     {
         case INDEX_UNKNOWN:
index 231924ce197b5d1576dc93eba0aee078d280acd0..fc86bdd1fe301dc279ba0596f439a17e34f3fa43 100644 (file)
@@ -33,6 +33,7 @@
 # the research papers on the package. Check out http://www.gromacs.org.
 
 gmx_add_unit_test(SelectionUnitTests selection-test
+                  indexutil.cpp
                   selectioncollection.cpp
                   selectionoption.cpp
                   toputils.cpp)
diff --git a/src/gromacs/selection/tests/indexutil.cpp b/src/gromacs/selection/tests/indexutil.cpp
new file mode 100644 (file)
index 0000000..12998ba
--- /dev/null
@@ -0,0 +1,507 @@
+/*
+ * 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 index group handling in the selection engine.
+ *
+ * \todo
+ * Tests for other functions, at least the set operations.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_selection
+ */
+#include <gtest/gtest.h>
+
+#include "gromacs/legacyheaders/typedefs.h"
+
+#include "gromacs/selection/indexutil.h"
+
+#include "testutils/refdata.h"
+
+#include "toputils.h"
+
+namespace
+{
+
+/********************************************************************
+ * IndexBlockTest
+ */
+
+class IndexBlockTest : public ::testing::Test
+{
+    public:
+        IndexBlockTest();
+        ~IndexBlockTest();
+
+        void setGroup(int count, const int atoms[]);
+        template <int count>
+        void setGroup(const int (&atoms)[count])
+        {
+            setGroup(count, atoms);
+        }
+
+        void checkBlocka();
+
+        gmx::test::TestReferenceData    data_;
+        gmx::test::TopologyManager      topManager_;
+        gmx_ana_index_t                 g_;
+        t_blocka                        blocka_;
+};
+
+IndexBlockTest::IndexBlockTest()
+{
+    blocka_.nr           = 0;
+    blocka_.index        = NULL;
+    blocka_.nalloc_index = 0;
+    blocka_.nra          = 0;
+    blocka_.a            = NULL;
+    blocka_.nalloc_a     = 0;
+    gmx_ana_index_clear(&g_);
+}
+
+IndexBlockTest::~IndexBlockTest()
+{
+    done_blocka(&blocka_);
+}
+
+void IndexBlockTest::setGroup(int count, const int atoms[])
+{
+    g_.isize = count;
+    g_.index = const_cast<int *>(atoms);
+}
+
+void IndexBlockTest::checkBlocka()
+{
+    gmx::test::TestReferenceChecker compound(
+            data_.rootChecker().checkCompound("BlockAtoms", "Block"));
+    compound.checkSequenceArray(g_.isize, g_.index, "Input");
+    compound.checkInteger(blocka_.nr, "Count");
+    for (int i = 0; i < blocka_.nr; ++i)
+    {
+        gmx::test::TestReferenceChecker blockCompound(
+                compound.checkCompound("Block", NULL));
+        blockCompound.checkSequence(&blocka_.a[blocka_.index[i]],
+                                    &blocka_.a[blocka_.index[i+1]],
+                                    "Atoms");
+    }
+}
+
+/********************************************************************
+ * gmx_ana_index_make_block() tests
+ */
+
+TEST_F(IndexBlockTest, CreatesUnknownBlock)
+{
+    gmx_ana_index_make_block(&blocka_, NULL, NULL, INDEX_UNKNOWN, false);
+    checkBlocka();
+    done_blocka(&blocka_);
+    gmx_ana_index_make_block(&blocka_, NULL, NULL, INDEX_UNKNOWN, false);
+    checkBlocka();
+}
+
+TEST_F(IndexBlockTest, CreatesAtomBlock)
+{
+    const int group[] = { 0, 1, 3, 4, 6 };
+    setGroup(group);
+    gmx_ana_index_make_block(&blocka_, NULL, &g_, INDEX_ATOM, false);
+    checkBlocka();
+    done_blocka(&blocka_);
+    gmx_ana_index_make_block(&blocka_, NULL, &g_, INDEX_ATOM, true);
+    checkBlocka();
+}
+
+TEST_F(IndexBlockTest, CreatesResidueBlock)
+{
+    const int group[] = { 0, 1, 3, 6, 7 };
+    topManager_.initAtoms(9);
+    topManager_.initUniformResidues(3);
+    setGroup(group);
+    gmx_ana_index_make_block(&blocka_, topManager_.topology(), &g_,
+                             INDEX_RES, false);
+    checkBlocka();
+}
+
+TEST_F(IndexBlockTest, CreatesMoleculeBlock)
+{
+    const int group[] = { 3, 4, 7, 8, 13 };
+    topManager_.initAtoms(18);
+    topManager_.initUniformMolecules(3);
+    setGroup(group);
+    gmx_ana_index_make_block(&blocka_, topManager_.topology(), &g_,
+                             INDEX_MOL, false);
+    checkBlocka();
+}
+
+TEST_F(IndexBlockTest, CreatesResidueBlockWithCompletion)
+{
+    const int group[] = { 3, 4, 7, 8, 13 };
+    topManager_.initAtoms(18);
+    topManager_.initUniformResidues(3);
+    setGroup(group);
+    gmx_ana_index_make_block(&blocka_, topManager_.topology(), &g_,
+                             INDEX_RES, true);
+    checkBlocka();
+}
+
+TEST_F(IndexBlockTest, CreatesMoleculeBlockWithCompletion)
+{
+    const int group[] = { 3, 4, 7, 8, 13 };
+    topManager_.initAtoms(18);
+    topManager_.initUniformMolecules(3);
+    setGroup(group);
+    gmx_ana_index_make_block(&blocka_, topManager_.topology(), &g_,
+                             INDEX_MOL, true);
+    checkBlocka();
+}
+
+TEST_F(IndexBlockTest, CreatesSingleBlock)
+{
+    const int group[] = { 0, 1, 3, 4, 6 };
+    setGroup(group);
+    gmx_ana_index_make_block(&blocka_, NULL, &g_, INDEX_ALL, false);
+    checkBlocka();
+    done_blocka(&blocka_);
+    gmx_ana_index_make_block(&blocka_, NULL, &g_, INDEX_ALL, true);
+    checkBlocka();
+}
+
+/********************************************************************
+ * gmx_ana_index_has_full_ablocks() tests
+ */
+
+TEST_F(IndexBlockTest, ChecksGroupForFullBlocksPositive)
+{
+    const int maxGroup[] = {
+        0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17
+    };
+    const int testGroup[] = { 3, 4, 5, 6, 7, 8, 12, 13, 14 };
+    topManager_.initAtoms(18);
+    topManager_.initUniformResidues(3);
+    setGroup(maxGroup);
+    gmx_ana_index_make_block(&blocka_, topManager_.topology(), &g_,
+                             INDEX_RES, false);
+    setGroup(testGroup);
+    EXPECT_TRUE(gmx_ana_index_has_full_ablocks(&g_, &blocka_));
+}
+
+TEST_F(IndexBlockTest, ChecksOutOfOrderGroupForFullBlocksPositive)
+{
+    const int maxGroup[] = {
+        15, 16, 17, 2, 1, 0, 12, 13, 14, 5, 4, 3, 9, 10, 11, 8, 7, 6
+    };
+    const int testGroup[] = { 2, 1, 0, 5, 4, 3, 8, 7, 6, };
+    topManager_.initAtoms(18);
+    topManager_.initUniformResidues(3);
+    setGroup(maxGroup);
+    gmx_ana_index_make_block(&blocka_, topManager_.topology(), &g_,
+                             INDEX_RES, false);
+    setGroup(testGroup);
+    EXPECT_TRUE(gmx_ana_index_has_full_ablocks(&g_, &blocka_));
+}
+
+TEST_F(IndexBlockTest, ChecksGroupForFullBlocksNegative)
+{
+    const int maxGroup[] = {
+        0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17
+    };
+    const int testGroup1[] = { 3, 4, 5, 6, 7, 8, 12, 13 };
+    const int testGroup2[] = { 3, 4, 5, 6, 7, 12, 13, 14 };
+    const int testGroup3[] = { 4, 5, 6, 7, 8, 12, 13, 14 };
+
+    topManager_.initAtoms(18);
+    topManager_.initUniformResidues(3);
+    setGroup(maxGroup);
+    gmx_ana_index_make_block(&blocka_, topManager_.topology(), &g_,
+                             INDEX_RES, false);
+
+    setGroup(testGroup1);
+    EXPECT_FALSE(gmx_ana_index_has_full_ablocks(&g_, &blocka_));
+
+    setGroup(testGroup2);
+    EXPECT_FALSE(gmx_ana_index_has_full_ablocks(&g_, &blocka_));
+
+    setGroup(testGroup3);
+    EXPECT_FALSE(gmx_ana_index_has_full_ablocks(&g_, &blocka_));
+}
+
+/********************************************************************
+ * gmx_ana_index_has_complete_elems() tests
+ */
+
+TEST_F(IndexBlockTest, ChecksGroupForCompleteElementsTrivial)
+{
+    const int group[] = { 0, 1, 2 };
+    setGroup(group);
+    EXPECT_TRUE(gmx_ana_index_has_complete_elems(&g_, INDEX_ATOM, NULL));
+    EXPECT_FALSE(gmx_ana_index_has_complete_elems(&g_, INDEX_ALL, NULL));
+    EXPECT_FALSE(gmx_ana_index_has_complete_elems(&g_, INDEX_UNKNOWN, NULL));
+}
+
+TEST_F(IndexBlockTest, ChecksGroupForCompleteResiduesPositive)
+{
+    const int group1[] = { 0, 1, 2, 6, 7, 8, 12, 13, 14 };
+    const int group2[] = { 3, 4, 5, 6, 7, 8 };
+
+    topManager_.initAtoms(15);
+    topManager_.initUniformResidues(3);
+    t_topology *top = topManager_.topology();
+
+    setGroup(group1);
+    EXPECT_TRUE(gmx_ana_index_has_complete_elems(&g_, INDEX_RES, top));
+
+    setGroup(group2);
+    EXPECT_TRUE(gmx_ana_index_has_complete_elems(&g_, INDEX_RES, top));
+}
+
+TEST_F(IndexBlockTest, ChecksGroupForCompleteResiduesNegative)
+{
+    const int group1[] = { 3, 4, 5, 6, 7, 8, 12, 13 };
+    const int group2[] = { 3, 4, 5, 6, 7, 12, 13, 14 };
+    const int group3[] = { 4, 5, 6, 7, 8, 12, 13, 14 };
+
+    topManager_.initAtoms(18);
+    topManager_.initUniformResidues(3);
+    t_topology *top = topManager_.topology();
+
+    setGroup(group1);
+    EXPECT_FALSE(gmx_ana_index_has_complete_elems(&g_, INDEX_RES, top));
+
+    setGroup(group2);
+    EXPECT_FALSE(gmx_ana_index_has_complete_elems(&g_, INDEX_RES, top));
+
+    setGroup(group3);
+    EXPECT_FALSE(gmx_ana_index_has_complete_elems(&g_, INDEX_RES, top));
+}
+
+TEST_F(IndexBlockTest, ChecksGroupForCompleteMoleculesPositive)
+{
+    const int group[] = { 0, 1, 2, 6, 7, 8, 12, 13, 14 };
+
+    topManager_.initAtoms(15);
+    topManager_.initUniformMolecules(3);
+    t_topology *top = topManager_.topology();
+
+    setGroup(group);
+    EXPECT_TRUE(gmx_ana_index_has_complete_elems(&g_, INDEX_MOL, top));
+}
+
+TEST_F(IndexBlockTest, ChecksGroupForCompleteMoleculesNegative)
+{
+    const int group1[] = { 3, 4, 5, 6, 7, 8, 12, 13 };
+    const int group2[] = { 3, 4, 5, 6, 7, 12, 13, 14 };
+    const int group3[] = { 4, 5, 6, 7, 8, 12, 13, 14 };
+
+    topManager_.initAtoms(18);
+    topManager_.initUniformMolecules(3);
+    t_topology *top = topManager_.topology();
+
+    setGroup(group1);
+    EXPECT_FALSE(gmx_ana_index_has_complete_elems(&g_, INDEX_MOL, top));
+
+    setGroup(group2);
+    EXPECT_FALSE(gmx_ana_index_has_complete_elems(&g_, INDEX_MOL, top));
+
+    setGroup(group3);
+    EXPECT_FALSE(gmx_ana_index_has_complete_elems(&g_, INDEX_MOL, top));
+}
+
+/********************************************************************
+ * IndexMapTest
+ */
+
+class IndexMapTest : public ::testing::Test
+{
+    public:
+        IndexMapTest();
+        ~IndexMapTest();
+
+        void testInit(int atomCount, const int atoms[], e_index_t type);
+        void testUpdate(int atomCount, const int atoms[], bool bMaskOnly,
+                        const char *name);
+        template <int count>
+        void testInit(const int (&atoms)[count], e_index_t type)
+        {
+            testInit(count, atoms, type);
+        }
+        template <int count>
+        void testUpdate(const int (&atoms)[count], bool bMaskOnly,
+                        const char *name)
+        {
+            testUpdate(count, atoms, bMaskOnly, name);
+        }
+
+        void checkMapping(int atomCount, const int atoms[], const char *name);
+
+        gmx::test::TestReferenceData    data_;
+        gmx::test::TestReferenceChecker checker_;
+        gmx::test::TopologyManager      topManager_;
+        gmx_ana_indexmap_t              map_;
+
+    private:
+        gmx_ana_index_t                 initGroup_;
+};
+
+IndexMapTest::IndexMapTest()
+    : checker_(data_.rootChecker())
+{
+    gmx_ana_indexmap_clear(&map_);
+    gmx_ana_index_clear(&initGroup_);
+}
+
+IndexMapTest::~IndexMapTest()
+{
+    gmx_ana_indexmap_deinit(&map_);
+}
+
+void IndexMapTest::testInit(int atomCount, const int atoms[], e_index_t type)
+{
+    initGroup_.isize = atomCount;
+    initGroup_.index = const_cast<int *>(atoms);
+    gmx_ana_indexmap_init(&map_, &initGroup_, topManager_.topology(), type);
+    EXPECT_EQ(type, map_.type);
+    checkMapping(atomCount, atoms, "Initialized");
+}
+
+void IndexMapTest::testUpdate(int atomCount, const int atoms[], bool bMaskOnly,
+                              const char *name)
+{
+    gmx_ana_index_t g;
+    g.isize = atomCount;
+    g.index = const_cast<int *>(atoms);
+    gmx_ana_indexmap_update(&map_, &g, bMaskOnly);
+    if (name == NULL)
+    {
+        name = "Updated";
+    }
+    if (bMaskOnly)
+    {
+        checkMapping(initGroup_.isize, initGroup_.index, name);
+    }
+    else
+    {
+        checkMapping(atomCount, atoms, name);
+    }
+}
+
+void IndexMapTest::checkMapping(int atomCount, const int atoms[],
+                                const char *name)
+{
+    ASSERT_EQ(map_.nr, map_.mapb.nr);
+    gmx::test::TestReferenceChecker compound(
+            checker_.checkCompound("IndexMapping", name));
+    compound.checkSequenceArray(atomCount, atoms, "Input");
+    compound.checkInteger(map_.nr, "Count");
+    for (int i = 0; i < map_.nr; ++i)
+    {
+        gmx::test::TestReferenceChecker blockCompound(
+                compound.checkCompound("Block", NULL));
+        blockCompound.checkSequence(&atoms[map_.mapb.index[i]],
+                                    &atoms[map_.mapb.index[i+1]],
+                                    "Atoms");
+        blockCompound.checkInteger(map_.refid[i], "RefId");
+        blockCompound.checkInteger(map_.mapid[i], "MapId");
+        int originalIdIndex = (map_.refid[i] != -1 ? map_.refid[i] : i);
+        EXPECT_EQ(map_.orgid[originalIdIndex], map_.mapid[i]);
+    }
+}
+
+/********************************************************************
+ * gmx_ana_indexmap_t tests
+ */
+
+TEST_F(IndexMapTest, InitializesAtomBlock)
+{
+    const int maxGroup[] = { 1, 2, 4, 5 };
+    testInit(maxGroup, INDEX_ATOM);
+}
+
+TEST_F(IndexMapTest, InitializesMoleculeBlock)
+{
+    const int maxGroup[] = { 3, 4, 7, 8, 13 };
+    topManager_.initAtoms(18);
+    topManager_.initUniformMolecules(3);
+    testInit(maxGroup, INDEX_MOL);
+}
+
+TEST_F(IndexMapTest, MapsSingleBlock)
+{
+    const int maxGroup[]  = { 0, 1, 2, 3 };
+    const int evalGroup[] = { 0, 2 };
+    testInit(maxGroup, INDEX_ALL);
+    testUpdate(evalGroup, false, NULL);
+}
+
+TEST_F(IndexMapTest, MapsResidueBlocks)
+{
+    const int maxGroup[] = {
+        0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17
+    };
+    const int evalGroup[] = { 3, 4, 7, 8, 13 };
+    topManager_.initAtoms(18);
+    topManager_.initUniformResidues(3);
+    testInit(maxGroup, INDEX_RES);
+    testUpdate(evalGroup, false, NULL);
+}
+
+TEST_F(IndexMapTest, MapsResidueBlocksWithMask)
+{
+    const int maxGroup[] = {
+        0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17
+    };
+    const int evalGroup[] = { 3, 4, 7, 8, 13 };
+    topManager_.initAtoms(18);
+    topManager_.initUniformResidues(3);
+    testInit(maxGroup, INDEX_RES);
+    testUpdate(evalGroup, true, NULL);
+}
+
+TEST_F(IndexMapTest, HandlesMultipleRequests)
+{
+    const int maxGroup[] = {
+        0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17
+    };
+    const int evalGroup[] = { 3, 4, 7, 8, 13 };
+    topManager_.initAtoms(18);
+    topManager_.initUniformResidues(3);
+    testInit(maxGroup, INDEX_RES);
+    testUpdate(evalGroup, false, "EvaluatedNoMask");
+    testUpdate(evalGroup, true, "EvaluatedMask");
+    testUpdate(maxGroup, true, "Initialized");
+    testUpdate(evalGroup, true, "EvaluatedMask");
+    testUpdate(evalGroup, false, "EvaluatedNoMask");
+    testUpdate(maxGroup, false, "Initialized");
+}
+
+} // namespace
diff --git a/src/gromacs/selection/tests/refdata/IndexBlockTest_CreatesAtomBlock.xml b/src/gromacs/selection/tests/refdata/IndexBlockTest_CreatesAtomBlock.xml
new file mode 100644 (file)
index 0000000..562cf7b
--- /dev/null
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <BlockAtoms Name="Block">
+    <Sequence Name="Input">
+      <Int Name="Length">5</Int>
+      <Int>0</Int>
+      <Int>1</Int>
+      <Int>3</Int>
+      <Int>4</Int>
+      <Int>6</Int>
+    </Sequence>
+    <Int Name="Count">5</Int>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">1</Int>
+        <Int>0</Int>
+      </Sequence>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">1</Int>
+        <Int>1</Int>
+      </Sequence>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">1</Int>
+        <Int>3</Int>
+      </Sequence>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">1</Int>
+        <Int>4</Int>
+      </Sequence>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">1</Int>
+        <Int>6</Int>
+      </Sequence>
+    </Block>
+  </BlockAtoms>
+</ReferenceData>
diff --git a/src/gromacs/selection/tests/refdata/IndexBlockTest_CreatesMoleculeBlock.xml b/src/gromacs/selection/tests/refdata/IndexBlockTest_CreatesMoleculeBlock.xml
new file mode 100644 (file)
index 0000000..6f710f9
--- /dev/null
@@ -0,0 +1,35 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <BlockAtoms Name="Block">
+    <Sequence Name="Input">
+      <Int Name="Length">5</Int>
+      <Int>3</Int>
+      <Int>4</Int>
+      <Int>7</Int>
+      <Int>8</Int>
+      <Int>13</Int>
+    </Sequence>
+    <Int Name="Count">3</Int>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+      </Sequence>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">2</Int>
+        <Int>7</Int>
+        <Int>8</Int>
+      </Sequence>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">1</Int>
+        <Int>13</Int>
+      </Sequence>
+    </Block>
+  </BlockAtoms>
+</ReferenceData>
diff --git a/src/gromacs/selection/tests/refdata/IndexBlockTest_CreatesMoleculeBlockWithCompletion.xml b/src/gromacs/selection/tests/refdata/IndexBlockTest_CreatesMoleculeBlockWithCompletion.xml
new file mode 100644 (file)
index 0000000..bd81848
--- /dev/null
@@ -0,0 +1,39 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <BlockAtoms Name="Block">
+    <Sequence Name="Input">
+      <Int Name="Length">5</Int>
+      <Int>3</Int>
+      <Int>4</Int>
+      <Int>7</Int>
+      <Int>8</Int>
+      <Int>13</Int>
+    </Sequence>
+    <Int Name="Count">3</Int>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+      </Sequence>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>6</Int>
+        <Int>7</Int>
+        <Int>8</Int>
+      </Sequence>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>12</Int>
+        <Int>13</Int>
+        <Int>14</Int>
+      </Sequence>
+    </Block>
+  </BlockAtoms>
+</ReferenceData>
diff --git a/src/gromacs/selection/tests/refdata/IndexBlockTest_CreatesResidueBlock.xml b/src/gromacs/selection/tests/refdata/IndexBlockTest_CreatesResidueBlock.xml
new file mode 100644 (file)
index 0000000..4c1593c
--- /dev/null
@@ -0,0 +1,35 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <BlockAtoms Name="Block">
+    <Sequence Name="Input">
+      <Int Name="Length">5</Int>
+      <Int>0</Int>
+      <Int>1</Int>
+      <Int>3</Int>
+      <Int>6</Int>
+      <Int>7</Int>
+    </Sequence>
+    <Int Name="Count">3</Int>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">2</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+      </Sequence>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">1</Int>
+        <Int>3</Int>
+      </Sequence>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">2</Int>
+        <Int>6</Int>
+        <Int>7</Int>
+      </Sequence>
+    </Block>
+  </BlockAtoms>
+</ReferenceData>
diff --git a/src/gromacs/selection/tests/refdata/IndexBlockTest_CreatesResidueBlockWithCompletion.xml b/src/gromacs/selection/tests/refdata/IndexBlockTest_CreatesResidueBlockWithCompletion.xml
new file mode 100644 (file)
index 0000000..bd81848
--- /dev/null
@@ -0,0 +1,39 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <BlockAtoms Name="Block">
+    <Sequence Name="Input">
+      <Int Name="Length">5</Int>
+      <Int>3</Int>
+      <Int>4</Int>
+      <Int>7</Int>
+      <Int>8</Int>
+      <Int>13</Int>
+    </Sequence>
+    <Int Name="Count">3</Int>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+      </Sequence>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>6</Int>
+        <Int>7</Int>
+        <Int>8</Int>
+      </Sequence>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>12</Int>
+        <Int>13</Int>
+        <Int>14</Int>
+      </Sequence>
+    </Block>
+  </BlockAtoms>
+</ReferenceData>
diff --git a/src/gromacs/selection/tests/refdata/IndexBlockTest_CreatesSingleBlock.xml b/src/gromacs/selection/tests/refdata/IndexBlockTest_CreatesSingleBlock.xml
new file mode 100644 (file)
index 0000000..427e75d
--- /dev/null
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <BlockAtoms Name="Block">
+    <Sequence Name="Input">
+      <Int Name="Length">5</Int>
+      <Int>0</Int>
+      <Int>1</Int>
+      <Int>3</Int>
+      <Int>4</Int>
+      <Int>6</Int>
+    </Sequence>
+    <Int Name="Count">1</Int>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">5</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>6</Int>
+      </Sequence>
+    </Block>
+  </BlockAtoms>
+</ReferenceData>
diff --git a/src/gromacs/selection/tests/refdata/IndexBlockTest_CreatesUnknownBlock.xml b/src/gromacs/selection/tests/refdata/IndexBlockTest_CreatesUnknownBlock.xml
new file mode 100644 (file)
index 0000000..37adfcb
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <BlockAtoms Name="Block">
+    <Sequence Name="Input">
+      <Int Name="Length">0</Int>
+    </Sequence>
+    <Int Name="Count">1</Int>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">0</Int>
+      </Sequence>
+    </Block>
+  </BlockAtoms>
+</ReferenceData>
diff --git a/src/gromacs/selection/tests/refdata/IndexMapTest_HandlesMultipleRequests.xml b/src/gromacs/selection/tests/refdata/IndexMapTest_HandlesMultipleRequests.xml
new file mode 100644 (file)
index 0000000..7d243e0
--- /dev/null
@@ -0,0 +1,209 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <IndexMapping Name="Initialized">
+    <Sequence Name="Input">
+      <Int Name="Length">18</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>
+      <Int>9</Int>
+      <Int>10</Int>
+      <Int>11</Int>
+      <Int>12</Int>
+      <Int>13</Int>
+      <Int>14</Int>
+      <Int>15</Int>
+      <Int>16</Int>
+      <Int>17</Int>
+    </Sequence>
+    <Int Name="Count">6</Int>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+      </Sequence>
+      <Int Name="RefId">0</Int>
+      <Int Name="MapId">0</Int>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+      </Sequence>
+      <Int Name="RefId">1</Int>
+      <Int Name="MapId">1</Int>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>6</Int>
+        <Int>7</Int>
+        <Int>8</Int>
+      </Sequence>
+      <Int Name="RefId">2</Int>
+      <Int Name="MapId">2</Int>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>9</Int>
+        <Int>10</Int>
+        <Int>11</Int>
+      </Sequence>
+      <Int Name="RefId">3</Int>
+      <Int Name="MapId">3</Int>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>12</Int>
+        <Int>13</Int>
+        <Int>14</Int>
+      </Sequence>
+      <Int Name="RefId">4</Int>
+      <Int Name="MapId">4</Int>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>15</Int>
+        <Int>16</Int>
+        <Int>17</Int>
+      </Sequence>
+      <Int Name="RefId">5</Int>
+      <Int Name="MapId">5</Int>
+    </Block>
+  </IndexMapping>
+  <IndexMapping Name="EvaluatedNoMask">
+    <Sequence Name="Input">
+      <Int Name="Length">5</Int>
+      <Int>3</Int>
+      <Int>4</Int>
+      <Int>7</Int>
+      <Int>8</Int>
+      <Int>13</Int>
+    </Sequence>
+    <Int Name="Count">3</Int>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+      </Sequence>
+      <Int Name="RefId">1</Int>
+      <Int Name="MapId">1</Int>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">2</Int>
+        <Int>7</Int>
+        <Int>8</Int>
+      </Sequence>
+      <Int Name="RefId">2</Int>
+      <Int Name="MapId">2</Int>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">1</Int>
+        <Int>13</Int>
+      </Sequence>
+      <Int Name="RefId">4</Int>
+      <Int Name="MapId">4</Int>
+    </Block>
+  </IndexMapping>
+  <IndexMapping Name="EvaluatedMask">
+    <Sequence Name="Input">
+      <Int Name="Length">18</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>
+      <Int>9</Int>
+      <Int>10</Int>
+      <Int>11</Int>
+      <Int>12</Int>
+      <Int>13</Int>
+      <Int>14</Int>
+      <Int>15</Int>
+      <Int>16</Int>
+      <Int>17</Int>
+    </Sequence>
+    <Int Name="Count">6</Int>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+      </Sequence>
+      <Int Name="RefId">-1</Int>
+      <Int Name="MapId">0</Int>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+      </Sequence>
+      <Int Name="RefId">1</Int>
+      <Int Name="MapId">1</Int>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>6</Int>
+        <Int>7</Int>
+        <Int>8</Int>
+      </Sequence>
+      <Int Name="RefId">2</Int>
+      <Int Name="MapId">2</Int>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>9</Int>
+        <Int>10</Int>
+        <Int>11</Int>
+      </Sequence>
+      <Int Name="RefId">-1</Int>
+      <Int Name="MapId">3</Int>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>12</Int>
+        <Int>13</Int>
+        <Int>14</Int>
+      </Sequence>
+      <Int Name="RefId">4</Int>
+      <Int Name="MapId">4</Int>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>15</Int>
+        <Int>16</Int>
+        <Int>17</Int>
+      </Sequence>
+      <Int Name="RefId">-1</Int>
+      <Int Name="MapId">5</Int>
+    </Block>
+  </IndexMapping>
+</ReferenceData>
diff --git a/src/gromacs/selection/tests/refdata/IndexMapTest_InitializesAtomBlock.xml b/src/gromacs/selection/tests/refdata/IndexMapTest_InitializesAtomBlock.xml
new file mode 100644 (file)
index 0000000..8fcd170
--- /dev/null
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <IndexMapping Name="Initialized">
+    <Sequence Name="Input">
+      <Int Name="Length">4</Int>
+      <Int>1</Int>
+      <Int>2</Int>
+      <Int>4</Int>
+      <Int>5</Int>
+    </Sequence>
+    <Int Name="Count">4</Int>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">1</Int>
+        <Int>1</Int>
+      </Sequence>
+      <Int Name="RefId">0</Int>
+      <Int Name="MapId">1</Int>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">1</Int>
+        <Int>2</Int>
+      </Sequence>
+      <Int Name="RefId">1</Int>
+      <Int Name="MapId">2</Int>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">1</Int>
+        <Int>4</Int>
+      </Sequence>
+      <Int Name="RefId">2</Int>
+      <Int Name="MapId">4</Int>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">1</Int>
+        <Int>5</Int>
+      </Sequence>
+      <Int Name="RefId">3</Int>
+      <Int Name="MapId">5</Int>
+    </Block>
+  </IndexMapping>
+</ReferenceData>
diff --git a/src/gromacs/selection/tests/refdata/IndexMapTest_InitializesMoleculeBlock.xml b/src/gromacs/selection/tests/refdata/IndexMapTest_InitializesMoleculeBlock.xml
new file mode 100644 (file)
index 0000000..a848311
--- /dev/null
@@ -0,0 +1,41 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <IndexMapping Name="Initialized">
+    <Sequence Name="Input">
+      <Int Name="Length">5</Int>
+      <Int>3</Int>
+      <Int>4</Int>
+      <Int>7</Int>
+      <Int>8</Int>
+      <Int>13</Int>
+    </Sequence>
+    <Int Name="Count">3</Int>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+      </Sequence>
+      <Int Name="RefId">0</Int>
+      <Int Name="MapId">1</Int>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">2</Int>
+        <Int>7</Int>
+        <Int>8</Int>
+      </Sequence>
+      <Int Name="RefId">1</Int>
+      <Int Name="MapId">2</Int>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">1</Int>
+        <Int>13</Int>
+      </Sequence>
+      <Int Name="RefId">2</Int>
+      <Int Name="MapId">4</Int>
+    </Block>
+  </IndexMapping>
+</ReferenceData>
diff --git a/src/gromacs/selection/tests/refdata/IndexMapTest_MapsResidueBlocks.xml b/src/gromacs/selection/tests/refdata/IndexMapTest_MapsResidueBlocks.xml
new file mode 100644 (file)
index 0000000..0e97e74
--- /dev/null
@@ -0,0 +1,125 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <IndexMapping Name="Initialized">
+    <Sequence Name="Input">
+      <Int Name="Length">18</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>
+      <Int>9</Int>
+      <Int>10</Int>
+      <Int>11</Int>
+      <Int>12</Int>
+      <Int>13</Int>
+      <Int>14</Int>
+      <Int>15</Int>
+      <Int>16</Int>
+      <Int>17</Int>
+    </Sequence>
+    <Int Name="Count">6</Int>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+      </Sequence>
+      <Int Name="RefId">0</Int>
+      <Int Name="MapId">0</Int>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+      </Sequence>
+      <Int Name="RefId">1</Int>
+      <Int Name="MapId">1</Int>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>6</Int>
+        <Int>7</Int>
+        <Int>8</Int>
+      </Sequence>
+      <Int Name="RefId">2</Int>
+      <Int Name="MapId">2</Int>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>9</Int>
+        <Int>10</Int>
+        <Int>11</Int>
+      </Sequence>
+      <Int Name="RefId">3</Int>
+      <Int Name="MapId">3</Int>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>12</Int>
+        <Int>13</Int>
+        <Int>14</Int>
+      </Sequence>
+      <Int Name="RefId">4</Int>
+      <Int Name="MapId">4</Int>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>15</Int>
+        <Int>16</Int>
+        <Int>17</Int>
+      </Sequence>
+      <Int Name="RefId">5</Int>
+      <Int Name="MapId">5</Int>
+    </Block>
+  </IndexMapping>
+  <IndexMapping Name="Updated">
+    <Sequence Name="Input">
+      <Int Name="Length">5</Int>
+      <Int>3</Int>
+      <Int>4</Int>
+      <Int>7</Int>
+      <Int>8</Int>
+      <Int>13</Int>
+    </Sequence>
+    <Int Name="Count">3</Int>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+      </Sequence>
+      <Int Name="RefId">1</Int>
+      <Int Name="MapId">1</Int>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">2</Int>
+        <Int>7</Int>
+        <Int>8</Int>
+      </Sequence>
+      <Int Name="RefId">2</Int>
+      <Int Name="MapId">2</Int>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">1</Int>
+        <Int>13</Int>
+      </Sequence>
+      <Int Name="RefId">4</Int>
+      <Int Name="MapId">4</Int>
+    </Block>
+  </IndexMapping>
+</ReferenceData>
diff --git a/src/gromacs/selection/tests/refdata/IndexMapTest_MapsResidueBlocksWithMask.xml b/src/gromacs/selection/tests/refdata/IndexMapTest_MapsResidueBlocksWithMask.xml
new file mode 100644 (file)
index 0000000..4b2c274
--- /dev/null
@@ -0,0 +1,172 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <IndexMapping Name="Initialized">
+    <Sequence Name="Input">
+      <Int Name="Length">18</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>
+      <Int>9</Int>
+      <Int>10</Int>
+      <Int>11</Int>
+      <Int>12</Int>
+      <Int>13</Int>
+      <Int>14</Int>
+      <Int>15</Int>
+      <Int>16</Int>
+      <Int>17</Int>
+    </Sequence>
+    <Int Name="Count">6</Int>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+      </Sequence>
+      <Int Name="RefId">0</Int>
+      <Int Name="MapId">0</Int>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+      </Sequence>
+      <Int Name="RefId">1</Int>
+      <Int Name="MapId">1</Int>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>6</Int>
+        <Int>7</Int>
+        <Int>8</Int>
+      </Sequence>
+      <Int Name="RefId">2</Int>
+      <Int Name="MapId">2</Int>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>9</Int>
+        <Int>10</Int>
+        <Int>11</Int>
+      </Sequence>
+      <Int Name="RefId">3</Int>
+      <Int Name="MapId">3</Int>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>12</Int>
+        <Int>13</Int>
+        <Int>14</Int>
+      </Sequence>
+      <Int Name="RefId">4</Int>
+      <Int Name="MapId">4</Int>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>15</Int>
+        <Int>16</Int>
+        <Int>17</Int>
+      </Sequence>
+      <Int Name="RefId">5</Int>
+      <Int Name="MapId">5</Int>
+    </Block>
+  </IndexMapping>
+  <IndexMapping Name="Updated">
+    <Sequence Name="Input">
+      <Int Name="Length">18</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>
+      <Int>9</Int>
+      <Int>10</Int>
+      <Int>11</Int>
+      <Int>12</Int>
+      <Int>13</Int>
+      <Int>14</Int>
+      <Int>15</Int>
+      <Int>16</Int>
+      <Int>17</Int>
+    </Sequence>
+    <Int Name="Count">6</Int>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+      </Sequence>
+      <Int Name="RefId">-1</Int>
+      <Int Name="MapId">0</Int>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+      </Sequence>
+      <Int Name="RefId">1</Int>
+      <Int Name="MapId">1</Int>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>6</Int>
+        <Int>7</Int>
+        <Int>8</Int>
+      </Sequence>
+      <Int Name="RefId">2</Int>
+      <Int Name="MapId">2</Int>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>9</Int>
+        <Int>10</Int>
+        <Int>11</Int>
+      </Sequence>
+      <Int Name="RefId">-1</Int>
+      <Int Name="MapId">3</Int>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>12</Int>
+        <Int>13</Int>
+        <Int>14</Int>
+      </Sequence>
+      <Int Name="RefId">4</Int>
+      <Int Name="MapId">4</Int>
+    </Block>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>15</Int>
+        <Int>16</Int>
+        <Int>17</Int>
+      </Sequence>
+      <Int Name="RefId">-1</Int>
+      <Int Name="MapId">5</Int>
+    </Block>
+  </IndexMapping>
+</ReferenceData>
diff --git a/src/gromacs/selection/tests/refdata/IndexMapTest_MapsSingleBlock.xml b/src/gromacs/selection/tests/refdata/IndexMapTest_MapsSingleBlock.xml
new file mode 100644 (file)
index 0000000..54df5ef
--- /dev/null
@@ -0,0 +1,42 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <IndexMapping Name="Initialized">
+    <Sequence Name="Input">
+      <Int Name="Length">4</Int>
+      <Int>0</Int>
+      <Int>1</Int>
+      <Int>2</Int>
+      <Int>3</Int>
+    </Sequence>
+    <Int Name="Count">1</Int>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">4</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+      </Sequence>
+      <Int Name="RefId">0</Int>
+      <Int Name="MapId">0</Int>
+    </Block>
+  </IndexMapping>
+  <IndexMapping Name="Updated">
+    <Sequence Name="Input">
+      <Int Name="Length">2</Int>
+      <Int>0</Int>
+      <Int>2</Int>
+    </Sequence>
+    <Int Name="Count">1</Int>
+    <Block>
+      <Sequence Name="Atoms">
+        <Int Name="Length">2</Int>
+        <Int>0</Int>
+        <Int>2</Int>
+      </Sequence>
+      <Int Name="RefId">0</Int>
+      <Int Name="MapId">0</Int>
+    </Block>
+  </IndexMapping>
+</ReferenceData>
index a624262800b294ad4c2f28986ebe8d99c336e664..b254384bdf7c6db811940ffb0e564f6617328ab5 100644 (file)
@@ -5,6 +5,69 @@
 
 <xsl:import href="common-referencedata.xsl"/>
 
+<!-- Index handling reference data -->
+
+<xsl:template match="BlockAtoms">
+    <xsl:if test="Sequence[@Name='Input']">
+        <h2>Input Atoms</h2>
+        <xsl:call-template name="SequenceAsHorizontalTable">
+            <xsl:with-param name="root" select="Sequence[@Name='Input']"/>
+        </xsl:call-template>
+    </xsl:if>
+    <h2>Blocks</h2>
+    <table border="1">
+        <tr>
+            <th>Atom count</th>
+            <th>Atoms</th>
+        </tr>
+        <xsl:for-each select="Block">
+            <tr>
+                <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>
+            </tr>
+        </xsl:for-each>
+    </table>
+</xsl:template>
+
+<xsl:template match="IndexMapping">
+    <h2><xsl:value-of select="@Name"/></h2>
+    <h3>Input Atoms</h3>
+    <xsl:call-template name="SequenceAsHorizontalTable">
+        <xsl:with-param name="root" select="Sequence[@Name='Input']"/>
+    </xsl:call-template>
+    <h3>Mapping</h3>
+    <table border="1">
+        <tr>
+            <th>RefId</th>
+            <xsl:if test="Block/Int[@Name='MapId']">
+                <th>MapId</th>
+            </xsl:if>
+            <th>Atom count</th>
+            <th>Atoms</th>
+        </tr>
+        <xsl:for-each select="Block">
+            <tr>
+                <td><xsl:value-of select="Int[@Name='RefId']"/></td>
+                <xsl:if test="Int[@Name='MapId']">
+                    <td><xsl:value-of select="Int[@Name='MapId']"/></td>
+                </xsl:if>
+                <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>
+            </tr>
+        </xsl:for-each>
+    </table>
+</xsl:template>
+
+<!-- Selection reference data -->
+
 <xsl:key name="SelectionName" match="ParsedSelections/ParsedSelection" use="@Name"/>
 
 <xsl:template match="ParsedSelections">
index 0d5f28556fae3aadd2e150343b46fb63238c3fe8..5f9e4ee66487cb125a4627208aeee55f6e2b752d 100644 (file)
@@ -46,6 +46,7 @@
 #include "gromacs/legacyheaders/smalloc.h"
 #include "gromacs/legacyheaders/statutil.h"
 #include "gromacs/legacyheaders/tpxio.h"
+#include "gromacs/legacyheaders/typedefs.h"
 #include "gromacs/legacyheaders/vec.h"
 
 #include "gromacs/utility/gmxassert.h"
@@ -115,5 +116,53 @@ void TopologyManager::loadTopology(const char *filename)
     sfree(xtop);
 }
 
+void TopologyManager::initAtoms(int count)
+{
+    GMX_RELEASE_ASSERT(top_ == NULL, "Topology initialized more than once");
+    snew(top_, 1);
+    init_t_atoms(&top_->atoms, count, FALSE);
+    for (int i = 0; i < count; ++i)
+    {
+        top_->atoms.atom[i].m = (i % 3 == 0 ? 2.0 : 1.0);
+    }
+    if (frame_ != NULL)
+    {
+        frame_->flags  = TRX_NEED_X;
+        frame_->natoms = count;
+        frame_->bX     = TRUE;
+        snew(frame_->x, count);
+    }
+}
+
+void TopologyManager::initUniformResidues(int residueSize)
+{
+    GMX_RELEASE_ASSERT(top_ != NULL, "Topology not initialized");
+    int residueIndex = -1;
+    for (int i = 0; i < top_->atoms.nr; ++i)
+    {
+        if (i % residueSize == 0)
+        {
+            ++residueIndex;
+        }
+        top_->atoms.atom[i].resind = residueIndex;
+    }
+}
+
+void TopologyManager::initUniformMolecules(int moleculeSize)
+{
+    GMX_RELEASE_ASSERT(top_ != NULL, "Topology not initialized");
+    int index = 0;
+    top_->mols.nalloc_index = (top_->atoms.nr + moleculeSize - 1) / moleculeSize + 1;
+    snew(top_->mols.index, top_->mols.nalloc_index);
+    top_->mols.nr = 0;
+    while (index < top_->atoms.nr)
+    {
+        top_->mols.index[top_->mols.nr] = index;
+        ++top_->mols.nr;
+        index += moleculeSize;
+    }
+    top_->mols.index[top_->mols.nr] = top_->atoms.nr;
+}
+
 } // namespace test
 } // namespace gmx
index 8c746302d7b5a249967b08358d14bdfbf45bb1ae..7024f86b42345b6bc5efa6fc01d87f264e5905c6 100644 (file)
@@ -58,6 +58,9 @@ class TopologyManager
         void requestFrame();
 
         void loadTopology(const char *filename);
+        void initAtoms(int count);
+        void initUniformResidues(int residueSize);
+        void initUniformMolecules(int moleculeSize);
 
         t_topology *topology() { return top_; }
         t_trxframe *frame() { return frame_; }