Convert gmx_molblock_t to C++
authorBerk Hess <hess@kth.se>
Wed, 14 Feb 2018 08:46:59 +0000 (09:46 +0100)
committerMark Abraham <mark.j.abraham@gmail.com>
Mon, 9 Apr 2018 09:24:38 +0000 (11:24 +0200)
Changed posres pointers in molblock to std vector.
Also moved the derived helper index data into a separate struct.
That is merged into this change to keep MPI broadcasting simple.
natoms_mol will be moved into the new struct in a child change.

Change-Id: I131fd14ab53cec98800c7e0731d3a92df3f93422

src/gromacs/domdec/domdec_topology.cpp
src/gromacs/fileio/tpxio.cpp
src/gromacs/gmxpreprocess/grompp.cpp
src/gromacs/mdlib/broadcaststructs.cpp
src/gromacs/mdlib/vsite.cpp
src/gromacs/selection/indexutil.cpp
src/gromacs/tools/convert_tpr.cpp
src/gromacs/topology/mtop_lookup.h
src/gromacs/topology/mtop_util.cpp
src/gromacs/topology/topology.cpp
src/gromacs/topology/topology.h

index ecac7caf0112dbdb74cd7dfbab4864463fbb99fd..30a7b7d5d336f67d1f39cbcf7f7e105a62abcc0b 100644 (file)
@@ -938,14 +938,14 @@ static void add_posres(int mol, int a_mol, const gmx_molblock_t *molb,
 
     /* Get the position restraint coordinates from the molblock */
     a_molb = mol*molb->natoms_mol + a_mol;
-    if (a_molb >= molb->nposres_xA)
+    if (a_molb >= static_cast<int>(molb->posres_xA.size()))
     {
         gmx_incons("Not enough position restraint coordinates");
     }
     ip->posres.pos0A[XX] = molb->posres_xA[a_molb][XX];
     ip->posres.pos0A[YY] = molb->posres_xA[a_molb][YY];
     ip->posres.pos0A[ZZ] = molb->posres_xA[a_molb][ZZ];
-    if (molb->nposres_xB > 0)
+    if (!molb->posres_xB.empty())
     {
         ip->posres.pos0B[XX] = molb->posres_xB[a_molb][XX];
         ip->posres.pos0B[YY] = molb->posres_xB[a_molb][YY];
@@ -984,7 +984,7 @@ static void add_fbposres(int mol, int a_mol, const gmx_molblock_t *molb,
 
     /* Get the position restriant coordinats from the molblock */
     a_molb = mol*molb->natoms_mol + a_mol;
-    if (a_molb >= molb->nposres_xA)
+    if (a_molb >= static_cast<int>(molb->posres_xA.size()))
     {
         gmx_incons("Not enough position restraint coordinates");
     }
index 9615c1b5dcb2c19ce8adf7a575831d09583dd648..61fc50b8f1148bb039559e8f40fd4fb8165f7071 100644 (file)
@@ -2424,23 +2424,25 @@ static void do_molblock(t_fileio *fio, gmx_molblock_t *molb, gmx_bool bRead)
     gmx_fio_do_int(fio, molb->nmol);
     gmx_fio_do_int(fio, molb->natoms_mol);
     /* Position restraint coordinates */
-    gmx_fio_do_int(fio, molb->nposres_xA);
-    if (molb->nposres_xA > 0)
+    int numPosres_xA = molb->posres_xA.size();
+    gmx_fio_do_int(fio, numPosres_xA);
+    if (numPosres_xA > 0)
     {
         if (bRead)
         {
-            snew(molb->posres_xA, molb->nposres_xA);
+            molb->posres_xA.resize(numPosres_xA);
         }
-        gmx_fio_ndo_rvec(fio, molb->posres_xA, molb->nposres_xA);
+        gmx_fio_ndo_rvec(fio, as_rvec_array(molb->posres_xA.data()), numPosres_xA);
     }
-    gmx_fio_do_int(fio, molb->nposres_xB);
-    if (molb->nposres_xB > 0)
+    int numPosres_xB = molb->posres_xB.size();
+    gmx_fio_do_int(fio, numPosres_xB);
+    if (numPosres_xB > 0)
     {
         if (bRead)
         {
-            snew(molb->posres_xB, molb->nposres_xB);
+            molb->posres_xB.resize(numPosres_xB);
         }
-        gmx_fio_ndo_rvec(fio, molb->posres_xB, molb->nposres_xB);
+        gmx_fio_ndo_rvec(fio, as_rvec_array(molb->posres_xB.data()), numPosres_xB);
     }
 
 }
index 8280fcd7a0e735deeee3237bfe4c6291d284cdfd..2cabe5da7e96e0ce1d22af06843231d9f1912016 100644 (file)
@@ -540,8 +540,6 @@ new_status(const char *topfile, const char *topppfile, const char *confin,
             sys->molblock.push_back(molb);
             gmx_molblock_t &molbs  = sys->molblock.back();
             molbs.natoms_mol       = molinfo[molbs.type].atoms.nr;
-            molbs.nposres_xA       = 0;
-            molbs.nposres_xB       = 0;
             sys->natoms           += molbs.nmol*molbs.natoms_mol;
         }
     }
@@ -828,7 +826,7 @@ static void read_posres(gmx_mtop_t *mtop, t_molinfo *molinfo, gmx_bool bTopB,
                         warninp_t wi)
 {
     gmx_bool       *hadAtom;
-    rvec           *x, *v, *xp;
+    rvec           *x, *v;
     dvec            sum;
     double          totmass;
     t_topology     *top;
@@ -916,8 +914,7 @@ static void read_posres(gmx_mtop_t *mtop, t_molinfo *molinfo, gmx_bool bTopB,
             }
             if (!bTopB)
             {
-                molb.nposres_xA = nat_molb;
-                snew(molb.posres_xA, molb.nposres_xA);
+                molb.posres_xA.resize(nat_molb);
                 for (i = 0; i < nat_molb; i++)
                 {
                     copy_rvec(x[a+i], molb.posres_xA[i]);
@@ -925,8 +922,7 @@ static void read_posres(gmx_mtop_t *mtop, t_molinfo *molinfo, gmx_bool bTopB,
             }
             else
             {
-                molb.nposres_xB = nat_molb;
-                snew(molb.posres_xB, molb.nposres_xB);
+                molb.posres_xB.resize(nat_molb);
                 for (i = 0; i < nat_molb; i++)
                 {
                     copy_rvec(x[a+i], molb.posres_xB[i]);
@@ -955,9 +951,9 @@ static void read_posres(gmx_mtop_t *mtop, t_molinfo *molinfo, gmx_bool bTopB,
         for (gmx_molblock_t &molb : mtop->molblock)
         {
             nat_molb = molb.nmol*mtop->moltype[molb.type].atoms.nr;
-            if (molb.nposres_xA > 0 || molb.nposres_xB > 0)
+            if (!molb.posres_xA.empty() || !molb.posres_xB.empty())
             {
-                xp = (!bTopB ? molb.posres_xA : molb.posres_xB);
+                std::vector<gmx::RVec> &xp = (!bTopB ? molb.posres_xA : molb.posres_xB);
                 for (i = 0; i < nat_molb; i++)
                 {
                     for (j = 0; j < npbcdim; j++)
index f6c14bbe17710359a108356518d898c4beece1c6..bba22c6e378ae1d376304696a0a84d860e9bff43 100644 (file)
@@ -749,19 +749,27 @@ static void bc_moltype(const t_commrec *cr, t_symtab *symtab,
     bc_blocka(cr, &moltype->excls);
 }
 
-static void bc_molblock(const t_commrec *cr, gmx_molblock_t *molb)
+static void bc_vector_of_rvec(const t_commrec *cr, std::vector<gmx::RVec> *vec)
 {
-    block_bc(cr, *molb);
-    if (molb->nposres_xA > 0)
+    int numElements = vec->size();
+    block_bc(cr, numElements);
+    if (!MASTER(cr))
     {
-        snew_bc(cr, molb->posres_xA, molb->nposres_xA);
-        nblock_bc(cr, molb->nposres_xA*DIM, molb->posres_xA[0]);
+        vec->resize(numElements);
     }
-    if (molb->nposres_xB > 0)
+    if (numElements > 0)
     {
-        snew_bc(cr, molb->posres_xB, molb->nposres_xB);
-        nblock_bc(cr, molb->nposres_xB*DIM, molb->posres_xB[0]);
+        nblock_bc(cr, numElements, as_rvec_array(vec->data()));
     }
+}
+
+static void bc_molblock(const t_commrec *cr, gmx_molblock_t *molb)
+{
+    block_bc(cr, molb->type);
+    block_bc(cr, molb->nmol);
+    bc_vector_of_rvec(cr, &molb->posres_xA);
+    bc_vector_of_rvec(cr, &molb->posres_xB);
+    block_bc(cr, molb->natoms_mol);
     if (debug)
     {
         fprintf(debug, "after bc_molblock\n");
@@ -830,7 +838,12 @@ void bcast_ir_mtop(const t_commrec *cr, t_inputrec *inputrec, gmx_mtop_t *mtop)
     bc_groups(cr, &mtop->symtab, mtop->natoms, &mtop->groups);
 
     GMX_RELEASE_ASSERT(!MASTER(cr) || mtop->haveMoleculeIndices, "mtop should have valid molecule indices");
-    mtop->haveMoleculeIndices = true;
+    if (!MASTER(cr))
+    {
+        mtop->haveMoleculeIndices = true;
+
+        gmx_mtop_finalize(mtop);
+    }
 }
 
 void init_parallel(t_commrec *cr, t_inputrec *inputrec,
index 706b07ed806d667c83eddedff1e7fe37bb5de3b4..3fc74f961ba854061edfbfb3d529a91ba93ab88d 100644 (file)
@@ -768,13 +768,15 @@ void constructVsitesGlobal(const gmx_mtop_t         &mtop,
                            gmx::ArrayRef<gmx::RVec>  x)
 {
     GMX_ASSERT(x.size() >= static_cast<size_t>(mtop.natoms), "x should contain the whole system");
+    GMX_ASSERT(!mtop.moleculeBlockIndices.empty(), "molblock indices are needed in constructVsitesGlobal");
 
-    for (const gmx_molblock_t &molb : mtop.molblock)
+    for (size_t mb = 0; mb < mtop.molblock.size(); mb++)
     {
-        const gmx_moltype_t  &molt = mtop.moltype[molb.type];
+        const gmx_molblock_t  &molb = mtop.molblock[mb];
+        const gmx_moltype_t   &molt = mtop.moltype[molb.type];
         if (vsiteIlistNrCount(molt.ilist) > 0)
         {
-            int atomOffset = molb.globalAtomStart;
+            int atomOffset = mtop.moleculeBlockIndices[mb].globalAtomStart;
             for (int mol = 0; mol < molb.nmol; mol++)
             {
                 construct_vsites(nullptr, as_rvec_array(x.data()) + atomOffset,
index ed0e5fe36a820799cf1c36091070d283833074ba..959a8623a4bd0d3b0e7a787659d603047b84ac62 100644 (file)
@@ -941,7 +941,7 @@ gmx_ana_index_make_block(t_blocka *t, const gmx_mtop_t *top, gmx_ana_index_t *g,
                         {
                             --first_atom;
                         }
-                        int first_mol_atom = top->molblock[molb].globalAtomStart;
+                        int first_mol_atom = top->moleculeBlockIndices[molb].globalAtomStart;
                         first_mol_atom += molnr*top->molblock[molb].natoms_mol;
                         first_atom      = first_mol_atom + first_atom + 1;
                         last_atom       = first_mol_atom + last_atom - 1;
@@ -954,13 +954,14 @@ gmx_ana_index_make_block(t_blocka *t, const gmx_mtop_t *top, gmx_ana_index_t *g,
                     case INDEX_MOL:
                     {
                         size_t molb = 0;
-                        while (molb + 1 < top->molblock.size() && id >= top->molblock[molb].moleculeIndexStart)
+                        while (molb + 1 < top->molblock.size() && id >= top->moleculeBlockIndices[molb].moleculeIndexStart)
                         {
                             ++molb;
                         }
-                        const gmx_molblock_t &molblock  = top->molblock[molb];
-                        const int             atomStart = molblock.globalAtomStart + (id - molblock.moleculeIndexStart)*molblock.natoms_mol;
-                        for (int j = 0; j < molblock.natoms_mol; ++j)
+                        const int                   numAtomsInMol = top->molblock[molb].natoms_mol;
+                        const MoleculeBlockIndices &blockIndices  = top->moleculeBlockIndices[molb];
+                        const int                   atomStart     = blockIndices.globalAtomStart + (id - blockIndices.moleculeIndexStart)*numAtomsInMol;
+                        for (int j = 0; j < numAtomsInMol; ++j)
                         {
                             t->a[t->nra++] = atomStart + j;
                         }
index 7e574d9bc8a2b44e19951e8ddce8d257467d0e09..8b5f9cbaaa880c21065a34c5459d75b731584c25 100644 (file)
@@ -303,8 +303,6 @@ static void reduce_topology_x(int gnx, int index[],
     mtop->molblock[0].type       = 0;
     mtop->molblock[0].nmol       = 1;
     mtop->molblock[0].natoms_mol = top.atoms.nr;
-    mtop->molblock[0].nposres_xA = 0;
-    mtop->molblock[0].nposres_xB = 0;
 
     mtop->natoms                 = top.atoms.nr;
 }
index fd4208c9f55d2c55602a9f56745f145392de5919..1309b265d8fbecc8983ba9dc6a020bb03386dde1 100644 (file)
@@ -75,6 +75,7 @@ mtopGetMolblockIndex(const gmx_mtop_t *mtop,
     GMX_ASSERT(globalAtomIndex >= 0 && globalAtomIndex < mtop->natoms, "The atom index to look up should be within range");
     GMX_ASSERT(moleculeBlock != nullptr, "molBlock can not be NULL");
     GMX_ASSERT(*moleculeBlock >= 0 && *moleculeBlock < static_cast<int>(mtop->molblock.size()), "The starting molecule block index for the search should be within range");
+    GMX_ASSERT(!mtop->moleculeBlockIndices.empty(), "The molecule block indices should be present when calling mtopGetMoleculeBlockIndex");
 
     /* Search the molecue block index using bisection */
     int molBlock0 = -1;
@@ -83,12 +84,12 @@ mtopGetMolblockIndex(const gmx_mtop_t *mtop,
     int globalAtomStart;
     while (TRUE)
     {
-        globalAtomStart = mtop->molblock[*moleculeBlock].globalAtomStart;
+        globalAtomStart = mtop->moleculeBlockIndices[*moleculeBlock].globalAtomStart;
         if (globalAtomIndex < globalAtomStart)
         {
             molBlock1 = *moleculeBlock;
         }
-        else if (globalAtomIndex >= mtop->molblock[*moleculeBlock].globalAtomEnd)
+        else if (globalAtomIndex >= mtop->moleculeBlockIndices[*moleculeBlock].globalAtomEnd)
         {
             molBlock0 = *moleculeBlock;
         }
@@ -130,7 +131,7 @@ mtopGetMoleculeIndex(const gmx_mtop_t *mtop,
     int localMoleculeIndex;
     mtopGetMolblockIndex(mtop, globalAtomIndex, moleculeBlock, &localMoleculeIndex, nullptr);
 
-    return mtop->molblock[*moleculeBlock].moleculeIndexStart + localMoleculeIndex;
+    return mtop->moleculeBlockIndices[*moleculeBlock].moleculeIndexStart + localMoleculeIndex;
 }
 
 /*! \brief Returns the atom data for an atom based on global atom index
@@ -212,8 +213,9 @@ mtopGetAtomAndResidueName(const gmx_mtop_t  *mtop,
     mtopGetMolblockIndex(mtop, globalAtomIndex, moleculeBlock,
                          &moleculeIndex, &atomIndexInMolecule);
 
-    const gmx_molblock_t &molb  = mtop->molblock[*moleculeBlock];
-    const t_atoms        &atoms = mtop->moltype[molb.type].atoms;
+    const gmx_molblock_t       &molb    = mtop->molblock[*moleculeBlock];
+    const t_atoms              &atoms   = mtop->moltype[molb.type].atoms;
+    const MoleculeBlockIndices &indices = mtop->moleculeBlockIndices[*moleculeBlock];
     if (atomName != nullptr)
     {
         *atomName = *(atoms.atomname[atomIndexInMolecule]);
@@ -227,7 +229,7 @@ mtopGetAtomAndResidueName(const gmx_mtop_t  *mtop,
         else
         {
             /* Single residue molecule, keep counting */
-            *residueNumber = molb.residueNumberStart + moleculeIndex*atoms.nres + atoms.atom[atomIndexInMolecule].resind;
+            *residueNumber = indices.residueNumberStart + moleculeIndex*atoms.nres + atoms.atom[atomIndexInMolecule].resind;
         }
     }
     if (residueName != nullptr)
@@ -236,7 +238,7 @@ mtopGetAtomAndResidueName(const gmx_mtop_t  *mtop,
     }
     if (globalResidueIndex != nullptr)
     {
-        *globalResidueIndex = molb.globalResidueStart + moleculeIndex*atoms.nres + atoms.atom[atomIndexInMolecule].resind;
+        *globalResidueIndex = indices.globalResidueStart + moleculeIndex*atoms.nres + atoms.atom[atomIndexInMolecule].resind;
     }
 }
 
index 4ab201b766bca7e754f1be8530ed9beed0f06656..4fb4fd0d1c09f6d257a235cd0dbd554ec3bdcc9a 100644 (file)
@@ -76,26 +76,31 @@ static int gmx_mtop_maxresnr(const gmx_mtop_t *mtop, int maxres_renum)
     return maxresnr;
 }
 
-static void finalizeMolblocks(gmx_mtop_t *mtop)
+static void buildMolblockIndices(gmx_mtop_t *mtop)
 {
+    mtop->moleculeBlockIndices.resize(mtop->molblock.size());
+
     int atomIndex          = 0;
     int residueIndex       = 0;
     int residueNumberStart = mtop->maxresnr + 1;
     int moleculeIndexStart = 0;
-    for (gmx_molblock_t &molb : mtop->molblock)
+    for (size_t mb = 0; mb < mtop->molblock.size(); mb++)
     {
-        const int numResPerMol        = mtop->moltype[molb.type].atoms.nres;
-        molb.globalAtomStart          = atomIndex;
-        molb.globalResidueStart       = residueIndex;
+        const gmx_molblock_t &molb         = mtop->molblock[mb];
+        MoleculeBlockIndices &indices      = mtop->moleculeBlockIndices[mb];
+        const int             numResPerMol = mtop->moltype[molb.type].atoms.nres;
+
+        indices.globalAtomStart       = atomIndex;
+        indices.globalResidueStart    = residueIndex;
         atomIndex                    += molb.nmol*molb.natoms_mol;
         residueIndex                 += molb.nmol*numResPerMol;
-        molb.globalAtomEnd            = atomIndex;
-        molb.residueNumberStart       = residueNumberStart;
+        indices.globalAtomEnd         = atomIndex;
+        indices.residueNumberStart    = residueNumberStart;
         if (numResPerMol <= mtop->maxres_renum)
         {
             residueNumberStart       += molb.nmol*numResPerMol;
         }
-        molb.moleculeIndexStart       = moleculeIndexStart;
+        indices.moleculeIndexStart    = moleculeIndexStart;
         moleculeIndexStart           += molb.nmol;
     }
 }
@@ -133,7 +138,7 @@ void gmx_mtop_finalize(gmx_mtop_t *mtop)
 
     mtop->maxresnr = gmx_mtop_maxresnr(mtop, mtop->maxres_renum);
 
-    finalizeMolblocks(mtop);
+    buildMolblockIndices(mtop);
 }
 
 void gmx_mtop_count_atomtypes(const gmx_mtop_t *mtop, int state, int typecount[])
@@ -771,14 +776,14 @@ static void set_posres_params(t_idef *idef, const gmx_molblock_t *molb,
         /* Copy the force constants */
         *ip    = idef->iparams[il->iatoms[i*2]];
         a_molb = il->iatoms[i*2+1] - a_offset;
-        if (molb->nposres_xA == 0)
+        if (molb->posres_xA.empty())
         {
             gmx_incons("Position restraint coordinates are missing");
         }
         ip->posres.pos0A[XX] = molb->posres_xA[a_molb][XX];
         ip->posres.pos0A[YY] = molb->posres_xA[a_molb][YY];
         ip->posres.pos0A[ZZ] = molb->posres_xA[a_molb][ZZ];
-        if (molb->nposres_xB > 0)
+        if (!molb->posres_xB.empty())
         {
             ip->posres.pos0B[XX] = molb->posres_xB[a_molb][XX];
             ip->posres.pos0B[YY] = molb->posres_xB[a_molb][YY];
@@ -812,7 +817,7 @@ static void set_fbposres_params(t_idef *idef, const gmx_molblock_t *molb,
         /* Copy the force constants */
         *ip    = idef->iparams[il->iatoms[i*2]];
         a_molb = il->iatoms[i*2+1] - a_offset;
-        if (molb->nposres_xA == 0)
+        if (molb->posres_xA.empty())
         {
             gmx_incons("Position restraint coordinates are missing");
         }
index 198e1a5af2f18d38a71c31982d57f85fc1958fdc..591ac78ba0e747032928ddf288adbfd668b22fb1 100644 (file)
@@ -48,6 +48,7 @@
 #include "gromacs/topology/ifunc.h"
 #include "gromacs/topology/symtab.h"
 #include "gromacs/utility/compare.h"
+#include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/strconvert.h"
 #include "gromacs/utility/txtdump.h"
@@ -136,37 +137,6 @@ gmx_moltype_t::~gmx_moltype_t()
     }
 }
 
-gmx_molblock_t::gmx_molblock_t()
-{
-    type       = -1;
-    nmol       = 0;
-    nposres_xA = 0;
-    posres_xA  = nullptr;
-    nposres_xB = 0;
-    posres_xB  = nullptr;
-
-    natoms_mol         = 0;
-    globalAtomStart    = -1;
-    globalAtomEnd      = -1;
-    globalResidueStart = -1;
-    residueNumberStart = -1;
-    moleculeIndexStart = -1;
-}
-
-gmx_molblock_t::~gmx_molblock_t()
-{
-    if (nposres_xA > 0)
-    {
-        nposres_xA = 0;
-        sfree(posres_xA);
-    }
-    if (nposres_xB > 0)
-    {
-        nposres_xB = 0;
-        sfree(posres_xB);
-    }
-}
-
 void done_gmx_groups_t(gmx_groups_t *g)
 {
     int i;
@@ -392,15 +362,15 @@ static void pr_molblock(FILE *fp, int indent, const char *title,
             "moltype", molb->type, *(molt[molb->type].name));
     pr_int(fp, indent, "#molecules", molb->nmol);
     pr_int(fp, indent, "#atoms_mol", molb->natoms_mol);
-    pr_int(fp, indent, "#posres_xA", molb->nposres_xA);
-    if (molb->nposres_xA > 0)
+    pr_int(fp, indent, "#posres_xA", molb->posres_xA.size());
+    if (!molb->posres_xA.empty())
     {
-        pr_rvecs(fp, indent, "posres_xA", molb->posres_xA, molb->nposres_xA);
+        pr_rvecs(fp, indent, "posres_xA", as_rvec_array(molb->posres_xA.data()), molb->posres_xA.size());
     }
-    pr_int(fp, indent, "#posres_xB", molb->nposres_xB);
-    if (molb->nposres_xB > 0)
+    pr_int(fp, indent, "#posres_xB", molb->posres_xB.size());
+    if (!molb->posres_xB.empty())
     {
-        pr_rvecs(fp, indent, "posres_xB", molb->posres_xB, molb->nposres_xB);
+        pr_rvecs(fp, indent, "posres_xB", as_rvec_array(molb->posres_xB.data()), molb->posres_xB.size());
     }
 }
 
index 04de807ffc1380da279636b19fa14486c07f0fde..7d9affdf2c4068087b40be58ccfe30c787426c0b 100644 (file)
@@ -81,30 +81,18 @@ struct gmx_moltype_t
 /*! \brief Block of molecules of the same type, used in gmx_mtop_t */
 struct gmx_molblock_t
 {
-    /*! \brief Constructor */
-    gmx_molblock_t();
-
-    /*! \brief Destructor */
-    ~gmx_molblock_t();
-
-    /*! \brief Default copy assignment operator.
-     *
-     * NOTE: Does not free the old pointers.
-     */
-    gmx_molblock_t &operator=(const gmx_molblock_t &) = default;
-
-    /*! \brief Default copy constructor */
-    gmx_molblock_t(const gmx_molblock_t &) = default;
+    int                    type = -1; /**< The molecule type index in mtop.moltype  */
+    int                    nmol = 0;  /**< The number of molecules in this block    */
+    std::vector<gmx::RVec> posres_xA; /**< Position restraint coordinates for top A */
+    std::vector<gmx::RVec> posres_xB; /**< Position restraint coordinates for top B */
 
-    int     type;               /**< The molecule type index in mtop.moltype  */
-    int     nmol;               /**< The number of molecules in this block    */
-    int     nposres_xA;         /**< The number of posres coords for top A    */
-    rvec   *posres_xA;          /**< Position restraint coordinates for top A */
-    int     nposres_xB;         /**< The number of posres coords for top B    */
-    rvec   *posres_xB;          /**< Position restraint coordinates for top B */
+    /* Convenience information, derived from other gmx_mtop_t contents */
+    int     natoms_mol = 0;           /**< The number of atoms in one molecule      */
+};
 
-    /* Convenience information, derived from other gmx_mtop_t contents     */
-    int     natoms_mol;         /**< The number of atoms in one molecule      */
+/*! \brief Indices for a gmx_molblock_t, derived from other gmx_mtop_t contents */
+struct MoleculeBlockIndices
+{
     int     globalAtomStart;    /**< Global atom index of the first atom in the block */
     int     globalAtomEnd;      /**< Global atom index + 1 of the last atom in the block */
     int     globalResidueStart; /**< Global residue index of the first residue in the block */
@@ -128,7 +116,11 @@ typedef struct gmx_groups_t
 #define ggrpnr(groups, egc, i) ((groups)->grpnr[egc] ? (groups)->grpnr[egc][i] : 0)
 
 /* The global, complete system topology struct, based on molecule types.
-   This structure should contain no data that is O(natoms) in memory. */
+ * This structure should contain no data that is O(natoms) in memory.
+ *
+ * TODO: Find a solution for ensuring that the derived data is in sync
+ *       with the primary data, possibly by converting to a class.
+ */
 struct gmx_mtop_t
 {
     /* Constructor */
@@ -150,9 +142,12 @@ struct gmx_mtop_t
     int              maxres_renum;                           /* Parameter for residue numbering      */
     int              maxresnr;                               /* The maximum residue number in moltype */
     t_atomtypes      atomtypes;                              /* Atomtype properties                  */
-    gmx_groups_t     groups;
+    gmx_groups_t     groups;                                 /* Groups of atoms for different purposes */
     t_symtab         symtab;                                 /* The symbol table                     */
     bool             haveMoleculeIndices;                    /* Tells whether we have valid molecule indices */
+
+    /* Derived data */
+    std::vector<MoleculeBlockIndices> moleculeBlockIndices;  /* Indices for each molblock entry for fast lookup of atom properties */
 };
 
 /* The mdrun node-local topology struct, completely written out */