2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2008,2009,2010, The GROMACS development team.
5 * Copyright (c) 2012,2013,2014,2015,2016 The GROMACS development team.
6 * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
7 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8 * and including many others, as listed in the AUTHORS file in the
9 * top-level source directory and at http://www.gromacs.org.
11 * GROMACS is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public License
13 * as published by the Free Software Foundation; either version 2.1
14 * of the License, or (at your option) any later version.
16 * GROMACS is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with GROMACS; if not, see
23 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 * If you want to redistribute modifications to GROMACS, please
27 * consider that scientific software is very special. Version
28 * control is crucial - bugs must be traceable. We will be happy to
29 * consider code for inclusion in the official distribution, but
30 * derived work must not be called official GROMACS. Details are found
31 * in the README & COPYING files - if they are missing, get the
32 * official version at http://www.gromacs.org.
34 * To help us fund GROMACS development, we humbly ask that you cite
35 * the research papers on the package. Check out http://www.gromacs.org.
39 #include "mtop_util.h"
47 #include "gromacs/math/vectypes.h"
48 #include "gromacs/topology/atoms.h"
49 #include "gromacs/topology/block.h"
50 #include "gromacs/topology/exclusionblocks.h"
51 #include "gromacs/topology/idef.h"
52 #include "gromacs/topology/ifunc.h"
53 #include "gromacs/topology/topology.h"
54 #include "gromacs/topology/topsort.h"
55 #include "gromacs/utility/arrayref.h"
56 #include "gromacs/utility/fatalerror.h"
57 #include "gromacs/utility/real.h"
58 #include "gromacs/utility/smalloc.h"
60 static int gmx_mtop_maxresnr(const gmx_mtop_t* mtop, int maxres_renum)
64 for (const gmx_moltype_t& moltype : mtop->moltype)
66 const t_atoms& atoms = moltype.atoms;
67 if (atoms.nres > maxres_renum)
69 for (int r = 0; r < atoms.nres; r++)
71 if (atoms.resinfo[r].nr > maxresnr)
73 maxresnr = atoms.resinfo[r].nr;
82 static void buildMolblockIndices(gmx_mtop_t* mtop)
84 mtop->moleculeBlockIndices.resize(mtop->molblock.size());
88 int residueNumberStart = mtop->maxresnr + 1;
89 int moleculeIndexStart = 0;
90 for (size_t mb = 0; mb < mtop->molblock.size(); mb++)
92 const gmx_molblock_t& molb = mtop->molblock[mb];
93 MoleculeBlockIndices& indices = mtop->moleculeBlockIndices[mb];
94 const int numResPerMol = mtop->moltype[molb.type].atoms.nres;
96 indices.numAtomsPerMolecule = mtop->moltype[molb.type].atoms.nr;
97 indices.globalAtomStart = atomIndex;
98 indices.globalResidueStart = residueIndex;
99 atomIndex += molb.nmol * indices.numAtomsPerMolecule;
100 residueIndex += molb.nmol * numResPerMol;
101 indices.globalAtomEnd = atomIndex;
102 indices.residueNumberStart = residueNumberStart;
103 if (numResPerMol <= mtop->maxres_renum)
105 residueNumberStart += molb.nmol * numResPerMol;
107 indices.moleculeIndexStart = moleculeIndexStart;
108 moleculeIndexStart += molb.nmol;
112 void gmx_mtop_finalize(gmx_mtop_t* mtop)
116 if (mtop->molblock.size() == 1 && mtop->molblock[0].nmol == 1)
118 /* We have a single molecule only, no renumbering needed.
119 * This case also covers an mtop converted from pdb/gro/... input,
120 * so we retain the original residue numbering.
122 mtop->maxres_renum = 0;
126 /* We only renumber single residue molecules. Their intra-molecular
127 * residue numbering is anyhow irrelevant.
129 mtop->maxres_renum = 1;
132 env = getenv("GMX_MAXRESRENUM");
135 sscanf(env, "%d", &mtop->maxres_renum);
137 if (mtop->maxres_renum == -1)
139 /* -1 signals renumber residues in all molecules */
140 mtop->maxres_renum = INT_MAX;
143 mtop->maxresnr = gmx_mtop_maxresnr(mtop, mtop->maxres_renum);
145 buildMolblockIndices(mtop);
148 void gmx_mtop_count_atomtypes(const gmx_mtop_t* mtop, int state, int typecount[])
150 for (int i = 0; i < mtop->ffparams.atnr; ++i)
154 for (const gmx_molblock_t& molb : mtop->molblock)
156 const t_atoms& atoms = mtop->moltype[molb.type].atoms;
157 for (int i = 0; i < atoms.nr; ++i)
162 tpi = atoms.atom[i].type;
166 tpi = atoms.atom[i].typeB;
168 typecount[tpi] += molb.nmol;
173 int gmx_mtop_num_molecules(const gmx_mtop_t& mtop)
175 int numMolecules = 0;
176 for (const gmx_molblock_t& molb : mtop.molblock)
178 numMolecules += molb.nmol;
183 int gmx_mtop_nres(const gmx_mtop_t* mtop)
186 for (const gmx_molblock_t& molb : mtop->molblock)
188 nres += molb.nmol * mtop->moltype[molb.type].atoms.nres;
193 AtomIterator::AtomIterator(const gmx_mtop_t& mtop, int globalAtomNumber) :
196 atoms_(&mtop.moltype[mtop.molblock[0].type].atoms),
198 highestResidueNumber_(mtop.maxresnr),
200 globalAtomNumber_(globalAtomNumber)
202 GMX_ASSERT(globalAtomNumber == 0 || globalAtomNumber == mtop.natoms,
203 "Starting at other atoms not implemented yet");
206 AtomIterator& AtomIterator::operator++()
211 if (localAtomNumber_ >= atoms_->nr)
213 if (atoms_->nres <= mtop_->maxresnr)
215 /* Single residue molecule, increase the count with one */
216 highestResidueNumber_ += atoms_->nres;
219 localAtomNumber_ = 0;
220 if (currentMolecule_ >= mtop_->molblock[mblock_].nmol)
223 if (mblock_ >= mtop_->molblock.size())
227 atoms_ = &mtop_->moltype[mtop_->molblock[mblock_].type].atoms;
228 currentMolecule_ = 0;
234 AtomIterator AtomIterator::operator++(int)
236 AtomIterator temp = *this;
241 bool AtomIterator::operator==(const AtomIterator& o) const
243 return mtop_ == o.mtop_ && globalAtomNumber_ == o.globalAtomNumber_;
246 bool AtomIterator::operator!=(const AtomIterator& o) const
248 return !(*this == o);
251 const t_atom& AtomProxy::atom() const
253 return it_->atoms_->atom[it_->localAtomNumber_];
256 int AtomProxy::globalAtomNumber() const
258 return it_->globalAtomNumber_;
261 const char* AtomProxy::atomName() const
263 return *(it_->atoms_->atomname[it_->localAtomNumber_]);
266 const char* AtomProxy::residueName() const
268 int residueIndexInMolecule = it_->atoms_->atom[it_->localAtomNumber_].resind;
269 return *(it_->atoms_->resinfo[residueIndexInMolecule].name);
272 int AtomProxy::residueNumber() const
274 int residueIndexInMolecule = it_->atoms_->atom[it_->localAtomNumber_].resind;
275 if (it_->atoms_->nres <= it_->mtop_->maxres_renum)
277 return it_->highestResidueNumber_ + 1 + residueIndexInMolecule;
281 return it_->atoms_->resinfo[residueIndexInMolecule].nr;
285 const gmx_moltype_t& AtomProxy::moleculeType() const
287 return it_->mtop_->moltype[it_->mtop_->molblock[it_->mblock_].type];
290 int AtomProxy::atomNumberInMol() const
292 return it_->localAtomNumber_;
295 typedef struct gmx_mtop_atomloop_block
297 const gmx_mtop_t* mtop;
299 const t_atoms* atoms;
301 } t_gmx_mtop_atomloop_block;
303 gmx_mtop_atomloop_block_t gmx_mtop_atomloop_block_init(const gmx_mtop_t* mtop)
305 struct gmx_mtop_atomloop_block* aloop;
311 aloop->atoms = &mtop->moltype[mtop->molblock[aloop->mblock].type].atoms;
312 aloop->at_local = -1;
317 static void gmx_mtop_atomloop_block_destroy(gmx_mtop_atomloop_block_t aloop)
322 gmx_bool gmx_mtop_atomloop_block_next(gmx_mtop_atomloop_block_t aloop, const t_atom** atom, int* nmol)
324 if (aloop == nullptr)
326 gmx_incons("gmx_mtop_atomloop_all_next called without calling gmx_mtop_atomloop_all_init");
331 if (aloop->at_local >= aloop->atoms->nr)
334 if (aloop->mblock >= aloop->mtop->molblock.size())
336 gmx_mtop_atomloop_block_destroy(aloop);
339 aloop->atoms = &aloop->mtop->moltype[aloop->mtop->molblock[aloop->mblock].type].atoms;
343 *atom = &aloop->atoms->atom[aloop->at_local];
344 *nmol = aloop->mtop->molblock[aloop->mblock].nmol;
349 typedef struct gmx_mtop_ilistloop
351 const gmx_mtop_t* mtop;
355 gmx_mtop_ilistloop_t gmx_mtop_ilistloop_init(const gmx_mtop_t* mtop)
357 struct gmx_mtop_ilistloop* iloop;
367 gmx_mtop_ilistloop_t gmx_mtop_ilistloop_init(const gmx_mtop_t& mtop)
369 return gmx_mtop_ilistloop_init(&mtop);
372 static void gmx_mtop_ilistloop_destroy(gmx_mtop_ilistloop_t iloop)
377 const InteractionLists* gmx_mtop_ilistloop_next(gmx_mtop_ilistloop_t iloop, int* nmol)
379 if (iloop == nullptr)
381 gmx_incons("gmx_mtop_ilistloop_next called without calling gmx_mtop_ilistloop_init");
385 if (iloop->mblock >= gmx::ssize(iloop->mtop->molblock))
387 if (iloop->mblock == gmx::ssize(iloop->mtop->molblock) && iloop->mtop->bIntermolecularInteractions)
390 return iloop->mtop->intermolecular_ilist.get();
393 gmx_mtop_ilistloop_destroy(iloop);
397 *nmol = iloop->mtop->molblock[iloop->mblock].nmol;
399 return &iloop->mtop->moltype[iloop->mtop->molblock[iloop->mblock].type].ilist;
401 typedef struct gmx_mtop_ilistloop_all
403 const gmx_mtop_t* mtop;
407 } t_gmx_mtop_ilist_all;
409 gmx_mtop_ilistloop_all_t gmx_mtop_ilistloop_all_init(const gmx_mtop_t* mtop)
411 struct gmx_mtop_ilistloop_all* iloop;
423 static void gmx_mtop_ilistloop_all_destroy(gmx_mtop_ilistloop_all_t iloop)
428 const InteractionLists* gmx_mtop_ilistloop_all_next(gmx_mtop_ilistloop_all_t iloop, int* atnr_offset)
431 if (iloop == nullptr)
434 "gmx_mtop_ilistloop_all_next called without calling gmx_mtop_ilistloop_all_init");
439 iloop->a_offset += iloop->mtop->moleculeBlockIndices[iloop->mblock].numAtomsPerMolecule;
444 /* Inter-molecular interactions, if present, are indexed with
445 * iloop->mblock == iloop->mtop->nmolblock, thus we should separately
446 * check for this value in this conditional.
448 if (iloop->mblock == iloop->mtop->molblock.size()
449 || iloop->mol >= iloop->mtop->molblock[iloop->mblock].nmol)
453 if (iloop->mblock >= iloop->mtop->molblock.size())
455 if (iloop->mblock == iloop->mtop->molblock.size() && iloop->mtop->bIntermolecularInteractions)
458 return iloop->mtop->intermolecular_ilist.get();
461 gmx_mtop_ilistloop_all_destroy(iloop);
466 *atnr_offset = iloop->a_offset;
468 return &iloop->mtop->moltype[iloop->mtop->molblock[iloop->mblock].type].ilist;
471 int gmx_mtop_ftype_count(const gmx_mtop_t* mtop, int ftype)
473 gmx_mtop_ilistloop_t iloop;
478 iloop = gmx_mtop_ilistloop_init(mtop);
479 while (const InteractionLists* il = gmx_mtop_ilistloop_next(iloop, &nmol))
481 n += nmol * (*il)[ftype].size() / (1 + NRAL(ftype));
484 if (mtop->bIntermolecularInteractions)
486 n += (*mtop->intermolecular_ilist)[ftype].size() / (1 + NRAL(ftype));
492 int gmx_mtop_ftype_count(const gmx_mtop_t& mtop, int ftype)
494 return gmx_mtop_ftype_count(&mtop, ftype);
497 int gmx_mtop_interaction_count(const gmx_mtop_t& mtop, const int unsigned if_flags)
501 gmx_mtop_ilistloop_t iloop = gmx_mtop_ilistloop_init(mtop);
503 while (const InteractionLists* il = gmx_mtop_ilistloop_next(iloop, &nmol))
505 for (int ftype = 0; ftype < F_NRE; ftype++)
507 if ((interaction_function[ftype].flags & if_flags) == if_flags)
509 n += nmol * (*il)[ftype].size() / (1 + NRAL(ftype));
514 if (mtop.bIntermolecularInteractions)
516 for (int ftype = 0; ftype < F_NRE; ftype++)
518 if ((interaction_function[ftype].flags & if_flags) == if_flags)
520 n += (*mtop.intermolecular_ilist)[ftype].size() / (1 + NRAL(ftype));
528 std::array<int, eptNR> gmx_mtop_particletype_count(const gmx_mtop_t& mtop)
530 std::array<int, eptNR> count = { { 0 } };
532 for (const auto& molblock : mtop.molblock)
534 const t_atoms& atoms = mtop.moltype[molblock.type].atoms;
535 for (int a = 0; a < atoms.nr; a++)
537 count[atoms.atom[a].ptype] += molblock.nmol;
544 static void atomcat(t_atoms* dest, const t_atoms* src, int copies, int maxres_renum, int* maxresnr)
548 int destnr = dest->nr;
552 dest->haveMass = src->haveMass;
553 dest->haveType = src->haveType;
554 dest->haveCharge = src->haveCharge;
555 dest->haveBState = src->haveBState;
556 dest->havePdbInfo = src->havePdbInfo;
560 dest->haveMass = dest->haveMass && src->haveMass;
561 dest->haveType = dest->haveType && src->haveType;
562 dest->haveCharge = dest->haveCharge && src->haveCharge;
563 dest->haveBState = dest->haveBState && src->haveBState;
564 dest->havePdbInfo = dest->havePdbInfo && src->havePdbInfo;
569 size = destnr + copies * srcnr;
570 srenew(dest->atom, size);
571 srenew(dest->atomname, size);
574 srenew(dest->atomtype, size);
575 if (dest->haveBState)
577 srenew(dest->atomtypeB, size);
580 if (dest->havePdbInfo)
582 srenew(dest->pdbinfo, size);
587 size = dest->nres + copies * src->nres;
588 srenew(dest->resinfo, size);
591 /* residue information */
592 for (l = dest->nres, j = 0; (j < copies); j++, l += src->nres)
594 memcpy(reinterpret_cast<char*>(&(dest->resinfo[l])), reinterpret_cast<char*>(&(src->resinfo[0])),
595 static_cast<size_t>(src->nres * sizeof(src->resinfo[0])));
598 for (l = destnr, j = 0; (j < copies); j++, l += srcnr)
600 memcpy(reinterpret_cast<char*>(&(dest->atom[l])), reinterpret_cast<char*>(&(src->atom[0])),
601 static_cast<size_t>(srcnr * sizeof(src->atom[0])));
602 memcpy(reinterpret_cast<char*>(&(dest->atomname[l])),
603 reinterpret_cast<char*>(&(src->atomname[0])),
604 static_cast<size_t>(srcnr * sizeof(src->atomname[0])));
607 memcpy(reinterpret_cast<char*>(&(dest->atomtype[l])),
608 reinterpret_cast<char*>(&(src->atomtype[0])),
609 static_cast<size_t>(srcnr * sizeof(src->atomtype[0])));
610 if (dest->haveBState)
612 memcpy(reinterpret_cast<char*>(&(dest->atomtypeB[l])),
613 reinterpret_cast<char*>(&(src->atomtypeB[0])),
614 static_cast<size_t>(srcnr * sizeof(src->atomtypeB[0])));
617 if (dest->havePdbInfo)
619 memcpy(reinterpret_cast<char*>(&(dest->pdbinfo[l])),
620 reinterpret_cast<char*>(&(src->pdbinfo[0])),
621 static_cast<size_t>(srcnr * sizeof(src->pdbinfo[0])));
625 /* Increment residue indices */
626 for (l = destnr, j = 0; (j < copies); j++)
628 for (i = 0; (i < srcnr); i++, l++)
630 dest->atom[l].resind = dest->nres + j * src->nres + src->atom[i].resind;
634 if (src->nres <= maxres_renum)
636 /* Single residue molecule, continue counting residues */
637 for (j = 0; (j < copies); j++)
639 for (l = 0; l < src->nres; l++)
642 dest->resinfo[dest->nres + j * src->nres + l].nr = *maxresnr;
647 dest->nres += copies * src->nres;
648 dest->nr += copies * src->nr;
651 t_atoms gmx_mtop_global_atoms(const gmx_mtop_t* mtop)
655 init_t_atoms(&atoms, 0, FALSE);
657 int maxresnr = mtop->maxresnr;
658 for (const gmx_molblock_t& molb : mtop->molblock)
660 atomcat(&atoms, &mtop->moltype[molb.type].atoms, molb.nmol, mtop->maxres_renum, &maxresnr);
667 * The cat routines below are old code from src/kernel/topcat.c
670 static void ilistcat(int ftype, InteractionList* dest, const InteractionList& src, int copies, int dnum, int snum)
676 size_t destIndex = dest->iatoms.size();
677 dest->iatoms.resize(dest->iatoms.size() + copies * src.size());
679 for (c = 0; c < copies; c++)
681 for (i = 0; i < src.size();)
683 dest->iatoms[destIndex++] = src.iatoms[i++];
684 for (a = 0; a < nral; a++)
686 dest->iatoms[destIndex++] = dnum + src.iatoms[i++];
693 static void ilistcat(int ftype, t_ilist* dest, const InteractionList& src, int copies, int dnum, int snum)
699 dest->nalloc = dest->nr + copies * src.size();
700 srenew(dest->iatoms, dest->nalloc);
702 for (c = 0; c < copies; c++)
704 for (i = 0; i < src.size();)
706 dest->iatoms[dest->nr++] = src.iatoms[i++];
707 for (a = 0; a < nral; a++)
709 dest->iatoms[dest->nr++] = dnum + src.iatoms[i++];
716 static const t_iparams& getIparams(const InteractionDefinitions& idef, const int index)
718 return idef.iparams[index];
721 static const t_iparams& getIparams(const t_idef& idef, const int index)
723 return idef.iparams[index];
726 static void resizeIParams(std::vector<t_iparams>* iparams, const int newSize)
728 iparams->resize(newSize);
731 static void resizeIParams(t_iparams** iparams, const int newSize)
733 srenew(*iparams, newSize);
736 template<typename IdefType>
737 static void set_posres_params(IdefType* idef, const gmx_molblock_t* molb, int i0, int a_offset)
742 auto* il = &idef->il[F_POSRES];
744 resizeIParams(&idef->iparams_posres, i1);
745 for (i = i0; i < i1; i++)
747 ip = &idef->iparams_posres[i];
748 /* Copy the force constants */
749 *ip = getIparams(*idef, il->iatoms[i * 2]);
750 a_molb = il->iatoms[i * 2 + 1] - a_offset;
751 if (molb->posres_xA.empty())
753 gmx_incons("Position restraint coordinates are missing");
755 ip->posres.pos0A[XX] = molb->posres_xA[a_molb][XX];
756 ip->posres.pos0A[YY] = molb->posres_xA[a_molb][YY];
757 ip->posres.pos0A[ZZ] = molb->posres_xA[a_molb][ZZ];
758 if (!molb->posres_xB.empty())
760 ip->posres.pos0B[XX] = molb->posres_xB[a_molb][XX];
761 ip->posres.pos0B[YY] = molb->posres_xB[a_molb][YY];
762 ip->posres.pos0B[ZZ] = molb->posres_xB[a_molb][ZZ];
766 ip->posres.pos0B[XX] = ip->posres.pos0A[XX];
767 ip->posres.pos0B[YY] = ip->posres.pos0A[YY];
768 ip->posres.pos0B[ZZ] = ip->posres.pos0A[ZZ];
770 /* Set the parameter index for idef->iparams_posre */
771 il->iatoms[i * 2] = i;
775 template<typename IdefType>
776 static void set_fbposres_params(IdefType* idef, const gmx_molblock_t* molb, int i0, int a_offset)
781 auto* il = &idef->il[F_FBPOSRES];
783 resizeIParams(&idef->iparams_fbposres, i1);
784 for (i = i0; i < i1; i++)
786 ip = &idef->iparams_fbposres[i];
787 /* Copy the force constants */
788 *ip = getIparams(*idef, il->iatoms[i * 2]);
789 a_molb = il->iatoms[i * 2 + 1] - a_offset;
790 if (molb->posres_xA.empty())
792 gmx_incons("Position restraint coordinates are missing");
794 /* Take flat-bottom posres reference from normal position restraints */
795 ip->fbposres.pos0[XX] = molb->posres_xA[a_molb][XX];
796 ip->fbposres.pos0[YY] = molb->posres_xA[a_molb][YY];
797 ip->fbposres.pos0[ZZ] = molb->posres_xA[a_molb][ZZ];
798 /* Note: no B-type for flat-bottom posres */
800 /* Set the parameter index for idef->iparams_posre */
801 il->iatoms[i * 2] = i;
805 /*! \brief Copy parameters to idef structure from mtop.
807 * Makes a deep copy of the force field parameters data structure from a gmx_mtop_t.
808 * Used to initialize legacy topology types.
810 * \param[in] mtop Reference to input mtop.
811 * \param[in] idef Pointer to idef to populate.
813 static void copyFFParametersFromMtop(const gmx_mtop_t& mtop, t_idef* idef)
815 const gmx_ffparams_t* ffp = &mtop.ffparams;
817 idef->ntypes = ffp->numTypes();
818 idef->atnr = ffp->atnr;
819 /* we can no longer copy the pointers to the mtop members,
820 * because they will become invalid as soon as mtop gets free'd.
821 * We also need to make sure to only operate on valid data!
824 if (!ffp->functype.empty())
826 snew(idef->functype, ffp->functype.size());
827 std::copy(ffp->functype.data(), ffp->functype.data() + ffp->functype.size(), idef->functype);
831 idef->functype = nullptr;
833 if (!ffp->iparams.empty())
835 snew(idef->iparams, ffp->iparams.size());
836 std::copy(ffp->iparams.data(), ffp->iparams.data() + ffp->iparams.size(), idef->iparams);
840 idef->iparams = nullptr;
842 idef->iparams_posres = nullptr;
843 idef->iparams_fbposres = nullptr;
844 idef->fudgeQQ = ffp->fudgeQQ;
845 idef->ilsort = ilsortUNKNOWN;
848 /*! \brief Copy idef structure from mtop.
850 * Makes a deep copy of an idef data structure from a gmx_mtop_t.
851 * Used to initialize legacy topology types.
853 * \param[in] mtop Reference to input mtop.
854 * \param[in] idef Pointer to idef to populate.
855 * \param[in] mergeConstr Decide if constraints will be merged.
857 template<typename IdefType>
858 static void copyIListsFromMtop(const gmx_mtop_t& mtop, IdefType* idef, bool mergeConstr)
861 for (const gmx_molblock_t& molb : mtop.molblock)
863 const gmx_moltype_t& molt = mtop.moltype[molb.type];
865 int srcnr = molt.atoms.nr;
868 int nposre_old = idef->il[F_POSRES].size();
869 int nfbposre_old = idef->il[F_FBPOSRES].size();
870 for (int ftype = 0; ftype < F_NRE; ftype++)
872 if (mergeConstr && ftype == F_CONSTR && !molt.ilist[F_CONSTRNC].empty())
874 /* Merge all constrains into one ilist.
875 * This simplifies the constraint code.
877 for (int mol = 0; mol < molb.nmol; mol++)
879 ilistcat(ftype, &idef->il[F_CONSTR], molt.ilist[F_CONSTR], 1,
880 destnr + mol * srcnr, srcnr);
881 ilistcat(ftype, &idef->il[F_CONSTR], molt.ilist[F_CONSTRNC], 1,
882 destnr + mol * srcnr, srcnr);
885 else if (!(mergeConstr && ftype == F_CONSTRNC))
887 ilistcat(ftype, &idef->il[ftype], molt.ilist[ftype], molb.nmol, destnr, srcnr);
890 if (idef->il[F_POSRES].size() > nposre_old)
892 /* Executing this line line stops gmxdump -sys working
893 * correctly. I'm not aware there's an elegant fix. */
894 set_posres_params(idef, &molb, nposre_old / 2, natoms);
896 if (idef->il[F_FBPOSRES].size() > nfbposre_old)
898 set_fbposres_params(idef, &molb, nfbposre_old / 2, natoms);
901 natoms += molb.nmol * srcnr;
904 if (mtop.bIntermolecularInteractions)
906 for (int ftype = 0; ftype < F_NRE; ftype++)
908 ilistcat(ftype, &idef->il[ftype], (*mtop.intermolecular_ilist)[ftype], 1, 0, mtop.natoms);
912 // We have not (yet) sorted free-energy interactions to the end of the ilists
913 idef->ilsort = ilsortNO_FE;
916 /*! \brief Copy atomtypes from mtop
918 * Makes a deep copy of t_atomtypes from gmx_mtop_t.
919 * Used to initialize legacy topology types.
921 * \param[in] mtop Reference to input mtop.
922 * \param[in] atomtypes Pointer to atomtypes to populate.
924 static void copyAtomtypesFromMtop(const gmx_mtop_t& mtop, t_atomtypes* atomtypes)
926 atomtypes->nr = mtop.atomtypes.nr;
927 if (mtop.atomtypes.atomnumber)
929 snew(atomtypes->atomnumber, mtop.atomtypes.nr);
930 std::copy(mtop.atomtypes.atomnumber, mtop.atomtypes.atomnumber + mtop.atomtypes.nr,
931 atomtypes->atomnumber);
935 atomtypes->atomnumber = nullptr;
939 /*! \brief Generate a single list of lists of exclusions for the whole system
941 * \param[in] mtop Reference to input mtop.
943 static gmx::ListOfLists<int> globalExclusionLists(const gmx_mtop_t& mtop)
945 gmx::ListOfLists<int> excls;
948 for (const gmx_molblock_t& molb : mtop.molblock)
950 const gmx_moltype_t& molt = mtop.moltype[molb.type];
952 for (int mol = 0; mol < molb.nmol; mol++)
954 excls.appendListOfLists(molt.excls, atomIndex);
956 atomIndex += molt.atoms.nr;
963 /*! \brief Updates inter-molecular exclusion lists
965 * This function updates inter-molecular exclusions to exclude all
966 * non-bonded interactions between a given list of atoms
968 * \param[inout] excls existing exclusions in local topology
969 * \param[in] ids list of global IDs of atoms
971 static void addMimicExclusions(gmx::ListOfLists<int>* excls, const gmx::ArrayRef<const int> ids)
973 t_blocka inter_excl{};
974 init_blocka(&inter_excl);
975 size_t n_q = ids.size();
977 inter_excl.nr = excls->ssize();
978 inter_excl.nra = n_q * n_q;
980 size_t total_nra = n_q * n_q;
982 snew(inter_excl.index, excls->ssize() + 1);
983 snew(inter_excl.a, total_nra);
985 for (int i = 0; i < inter_excl.nr; ++i)
987 inter_excl.index[i] = 0;
990 /* Here we loop over the list of QM atom ids
991 * and create exclusions between all of them resulting in
992 * n_q * n_q sized exclusion list
995 for (int k = 0; k < inter_excl.nr; ++k)
997 inter_excl.index[k] = prev_index;
998 for (long i = 0; i < ids.ssize(); i++)
1004 size_t index = n_q * i;
1005 inter_excl.index[ids[i]] = index;
1006 prev_index = index + n_q;
1007 for (size_t j = 0; j < n_q; ++j)
1009 inter_excl.a[n_q * i + j] = ids[j];
1013 inter_excl.index[ids[n_q - 1] + 1] = n_q * n_q;
1015 inter_excl.index[inter_excl.nr] = n_q * n_q;
1017 std::vector<gmx::ExclusionBlock> qmexcl2(excls->size());
1018 gmx::blockaToExclusionBlocks(&inter_excl, qmexcl2);
1020 // Merge the created exclusion list with the existing one
1021 gmx::mergeExclusions(excls, qmexcl2);
1024 static void sortFreeEnergyInteractionsAtEnd(const gmx_mtop_t& mtop, InteractionDefinitions* idef)
1026 std::vector<real> qA(mtop.natoms);
1027 std::vector<real> qB(mtop.natoms);
1028 for (const AtomProxy atomP : AtomRange(mtop))
1030 const t_atom& local = atomP.atom();
1031 int index = atomP.globalAtomNumber();
1032 qA[index] = local.q;
1033 qB[index] = local.qB;
1035 gmx_sort_ilist_fe(idef, qA.data(), qB.data());
1038 static void gen_local_top(const gmx_mtop_t& mtop,
1039 bool freeEnergyInteractionsAtEnd,
1041 gmx_localtop_t* top)
1043 copyIListsFromMtop(mtop, &top->idef, bMergeConstr);
1044 if (freeEnergyInteractionsAtEnd)
1046 sortFreeEnergyInteractionsAtEnd(mtop, &top->idef);
1048 top->excls = globalExclusionLists(mtop);
1049 if (!mtop.intermolecularExclusionGroup.empty())
1051 addMimicExclusions(&top->excls, mtop.intermolecularExclusionGroup);
1055 void gmx_mtop_generate_local_top(const gmx_mtop_t& mtop, gmx_localtop_t* top, bool freeEnergyInteractionsAtEnd)
1057 gen_local_top(mtop, freeEnergyInteractionsAtEnd, true, top);
1060 /*! \brief Fills an array with molecule begin/end atom indices
1062 * \param[in] mtop The global topology
1063 * \param[out] index Array of size nr. of molecules + 1 to be filled with molecule begin/end indices
1065 static void fillMoleculeIndices(const gmx_mtop_t& mtop, gmx::ArrayRef<int> index)
1067 int globalAtomIndex = 0;
1068 int globalMolIndex = 0;
1069 index[globalMolIndex] = globalAtomIndex;
1070 for (const gmx_molblock_t& molb : mtop.molblock)
1072 int numAtomsPerMolecule = mtop.moltype[molb.type].atoms.nr;
1073 for (int mol = 0; mol < molb.nmol; mol++)
1075 globalAtomIndex += numAtomsPerMolecule;
1076 globalMolIndex += 1;
1077 index[globalMolIndex] = globalAtomIndex;
1082 gmx::RangePartitioning gmx_mtop_molecules(const gmx_mtop_t& mtop)
1084 gmx::RangePartitioning mols;
1086 for (const gmx_molblock_t& molb : mtop.molblock)
1088 int numAtomsPerMolecule = mtop.moltype[molb.type].atoms.nr;
1089 for (int mol = 0; mol < molb.nmol; mol++)
1091 mols.appendBlock(numAtomsPerMolecule);
1098 /*! \brief Creates and returns a deprecated t_block struct with molecule indices
1100 * \param[in] mtop The global topology
1102 static t_block gmx_mtop_molecules_t_block(const gmx_mtop_t& mtop)
1106 mols.nr = gmx_mtop_num_molecules(mtop);
1107 mols.nalloc_index = mols.nr + 1;
1108 snew(mols.index, mols.nalloc_index);
1110 fillMoleculeIndices(mtop, gmx::arrayRefFromArray(mols.index, mols.nr + 1));
1115 static void gen_t_topology(const gmx_mtop_t& mtop, bool bMergeConstr, t_topology* top)
1117 copyAtomtypesFromMtop(mtop, &top->atomtypes);
1118 for (int ftype = 0; ftype < F_NRE; ftype++)
1120 top->idef.il[ftype].nr = 0;
1121 top->idef.il[ftype].nalloc = 0;
1122 top->idef.il[ftype].iatoms = nullptr;
1124 copyFFParametersFromMtop(mtop, &top->idef);
1125 copyIListsFromMtop(mtop, &top->idef, bMergeConstr);
1127 top->name = mtop.name;
1128 top->atoms = gmx_mtop_global_atoms(&mtop);
1129 top->mols = gmx_mtop_molecules_t_block(mtop);
1130 top->bIntermolecularInteractions = mtop.bIntermolecularInteractions;
1131 top->symtab = mtop.symtab;
1134 t_topology gmx_mtop_t_to_t_topology(gmx_mtop_t* mtop, bool freeMTop)
1138 gen_t_topology(*mtop, false, &top);
1142 // Clear pointers and counts, such that the pointers copied to top
1143 // keep pointing to valid data after destroying mtop.
1144 mtop->symtab.symbuf = nullptr;
1145 mtop->symtab.nr = 0;
1150 std::vector<int> get_atom_index(const gmx_mtop_t* mtop)
1153 std::vector<int> atom_index;
1154 for (const AtomProxy atomP : AtomRange(*mtop))
1156 const t_atom& local = atomP.atom();
1157 int index = atomP.globalAtomNumber();
1158 if (local.ptype == eptAtom)
1160 atom_index.push_back(index);
1166 void convertAtomsToMtop(t_symtab* symtab, char** name, t_atoms* atoms, gmx_mtop_t* mtop)
1168 mtop->symtab = *symtab;
1172 mtop->moltype.clear();
1173 mtop->moltype.resize(1);
1174 mtop->moltype.back().atoms = *atoms;
1176 mtop->molblock.resize(1);
1177 mtop->molblock[0].type = 0;
1178 mtop->molblock[0].nmol = 1;
1180 mtop->bIntermolecularInteractions = FALSE;
1182 mtop->natoms = atoms->nr;
1184 mtop->haveMoleculeIndices = false;
1186 gmx_mtop_finalize(mtop);
1189 bool haveFepPerturbedNBInteractions(const gmx_mtop_t* mtop)
1191 for (size_t mb = 0; mb < mtop->molblock.size(); mb++)
1193 const gmx_molblock_t& molb = mtop->molblock[mb];
1194 const gmx_moltype_t& molt = mtop->moltype[molb.type];
1195 for (int m = 0; m < molb.nmol; m++)
1197 for (int a = 0; a < molt.atoms.nr; a++)
1199 const t_atom& atom = molt.atoms.atom[a];
1200 if (PERTURBED(atom))