Remove unused function generate_excls and make clean_excls static
[gromacs.git] / src / gromacs / topology / mtop_util.cpp
blob519b1c28b7ab95809c4b14a79ab8034efae6299a
1 /*
2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2008,2009,2010,
5 * Copyright (c) 2012,2013,2014,2015,2016,2017,2018,2019, by the GROMACS development team, led by
6 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
7 * and including many others, as listed in the AUTHORS file in the
8 * top-level source directory and at http://www.gromacs.org.
10 * GROMACS is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public License
12 * as published by the Free Software Foundation; either version 2.1
13 * of the License, or (at your option) any later version.
15 * GROMACS is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with GROMACS; if not, see
22 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
23 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 * If you want to redistribute modifications to GROMACS, please
26 * consider that scientific software is very special. Version
27 * control is crucial - bugs must be traceable. We will be happy to
28 * consider code for inclusion in the official distribution, but
29 * derived work must not be called official GROMACS. Details are found
30 * in the README & COPYING files - if they are missing, get the
31 * official version at http://www.gromacs.org.
33 * To help us fund GROMACS development, we humbly ask that you cite
34 * the research papers on the package. Check out http://www.gromacs.org.
36 #include "gmxpre.h"
38 #include "mtop_util.h"
40 #include <climits>
41 #include <cstddef>
42 #include <cstdio>
43 #include <cstdlib>
44 #include <cstring>
46 #include "gromacs/math/vectypes.h"
47 #include "gromacs/topology/atoms.h"
48 #include "gromacs/topology/block.h"
49 #include "gromacs/topology/exclusionblocks.h"
50 #include "gromacs/topology/idef.h"
51 #include "gromacs/topology/ifunc.h"
52 #include "gromacs/topology/topology.h"
53 #include "gromacs/topology/topsort.h"
54 #include "gromacs/utility/arrayref.h"
55 #include "gromacs/utility/fatalerror.h"
56 #include "gromacs/utility/real.h"
57 #include "gromacs/utility/smalloc.h"
59 static int gmx_mtop_maxresnr(const gmx_mtop_t *mtop, int maxres_renum)
61 int maxresnr = 0;
63 for (const gmx_moltype_t &moltype : mtop->moltype)
65 const t_atoms &atoms = moltype.atoms;
66 if (atoms.nres > maxres_renum)
68 for (int r = 0; r < atoms.nres; r++)
70 if (atoms.resinfo[r].nr > maxresnr)
72 maxresnr = atoms.resinfo[r].nr;
78 return maxresnr;
81 static void buildMolblockIndices(gmx_mtop_t *mtop)
83 mtop->moleculeBlockIndices.resize(mtop->molblock.size());
85 int atomIndex = 0;
86 int residueIndex = 0;
87 int residueNumberStart = mtop->maxresnr + 1;
88 int moleculeIndexStart = 0;
89 for (size_t mb = 0; mb < mtop->molblock.size(); mb++)
91 const gmx_molblock_t &molb = mtop->molblock[mb];
92 MoleculeBlockIndices &indices = mtop->moleculeBlockIndices[mb];
93 const int numResPerMol = mtop->moltype[molb.type].atoms.nres;
95 indices.numAtomsPerMolecule = mtop->moltype[molb.type].atoms.nr;
96 indices.globalAtomStart = atomIndex;
97 indices.globalResidueStart = residueIndex;
98 atomIndex += molb.nmol*indices.numAtomsPerMolecule;
99 residueIndex += molb.nmol*numResPerMol;
100 indices.globalAtomEnd = atomIndex;
101 indices.residueNumberStart = residueNumberStart;
102 if (numResPerMol <= mtop->maxres_renum)
104 residueNumberStart += molb.nmol*numResPerMol;
106 indices.moleculeIndexStart = moleculeIndexStart;
107 moleculeIndexStart += molb.nmol;
111 void gmx_mtop_finalize(gmx_mtop_t *mtop)
113 char *env;
115 if (mtop->molblock.size() == 1 && mtop->molblock[0].nmol == 1)
117 /* We have a single molecule only, no renumbering needed.
118 * This case also covers an mtop converted from pdb/gro/... input,
119 * so we retain the original residue numbering.
121 mtop->maxres_renum = 0;
123 else
125 /* We only renumber single residue molecules. Their intra-molecular
126 * residue numbering is anyhow irrelevant.
128 mtop->maxres_renum = 1;
131 env = getenv("GMX_MAXRESRENUM");
132 if (env != nullptr)
134 sscanf(env, "%d", &mtop->maxres_renum);
136 if (mtop->maxres_renum == -1)
138 /* -1 signals renumber residues in all molecules */
139 mtop->maxres_renum = INT_MAX;
142 mtop->maxresnr = gmx_mtop_maxresnr(mtop, mtop->maxres_renum);
144 buildMolblockIndices(mtop);
147 void gmx_mtop_count_atomtypes(const gmx_mtop_t *mtop, int state, int typecount[])
149 for (int i = 0; i < mtop->ffparams.atnr; ++i)
151 typecount[i] = 0;
153 for (const gmx_molblock_t &molb : mtop->molblock)
155 const t_atoms &atoms = mtop->moltype[molb.type].atoms;
156 for (int i = 0; i < atoms.nr; ++i)
158 int tpi;
159 if (state == 0)
161 tpi = atoms.atom[i].type;
163 else
165 tpi = atoms.atom[i].typeB;
167 typecount[tpi] += molb.nmol;
172 int gmx_mtop_num_molecules(const gmx_mtop_t &mtop)
174 int numMolecules = 0;
175 for (const gmx_molblock_t &molb : mtop.molblock)
177 numMolecules += molb.nmol;
179 return numMolecules;
182 int gmx_mtop_nres(const gmx_mtop_t *mtop)
184 int nres = 0;
185 for (const gmx_molblock_t &molb : mtop->molblock)
187 nres += molb.nmol*mtop->moltype[molb.type].atoms.nres;
189 return nres;
192 AtomIterator::AtomIterator(const gmx_mtop_t &mtop, int globalAtomNumber)
193 : mtop_(&mtop), mblock_(0),
194 atoms_(&mtop.moltype[mtop.molblock[0].type].atoms),
195 currentMolecule_(0), highestResidueNumber_(mtop.maxresnr),
196 localAtomNumber_(0), globalAtomNumber_(globalAtomNumber)
198 GMX_ASSERT(globalAtomNumber == 0 || globalAtomNumber == mtop.natoms,
199 "Starting at other atoms not implemented yet");
202 AtomIterator &AtomIterator::operator++()
204 localAtomNumber_++;
205 globalAtomNumber_++;
207 if (localAtomNumber_ >= atoms_->nr)
209 if (atoms_->nres <= mtop_->maxresnr)
211 /* Single residue molecule, increase the count with one */
212 highestResidueNumber_ += atoms_->nres;
214 currentMolecule_++;
215 localAtomNumber_ = 0;
216 if (currentMolecule_ >= mtop_->molblock[mblock_].nmol)
218 mblock_++;
219 if (mblock_ >= mtop_->molblock.size())
221 return *this;
223 atoms_ = &mtop_->moltype[mtop_->molblock[mblock_].type].atoms;
224 currentMolecule_ = 0;
227 return *this;
230 AtomIterator AtomIterator::operator++(int)
232 AtomIterator temp = *this;
233 ++(*this);
234 return temp;
237 bool AtomIterator::operator==(const AtomIterator &o) const
239 return mtop_ == o.mtop_ && globalAtomNumber_ == o.globalAtomNumber_;
242 bool AtomIterator::operator!=(const AtomIterator &o) const
244 return !(*this == o);
247 const t_atom &AtomProxy::atom() const
249 return it_->atoms_->atom[it_->localAtomNumber_];
252 int AtomProxy::globalAtomNumber() const
254 return it_->globalAtomNumber_;
257 const char *AtomProxy::atomName() const
259 return *(it_->atoms_->atomname[it_->localAtomNumber_]);
262 const char *AtomProxy::residueName() const
264 int residueIndexInMolecule = it_->atoms_->atom[it_->localAtomNumber_].resind;
265 return *(it_->atoms_->resinfo[residueIndexInMolecule].name);
268 int AtomProxy::residueNumber() const
270 int residueIndexInMolecule = it_->atoms_->atom[it_->localAtomNumber_].resind;
271 if (it_->atoms_->nres <= it_->mtop_->maxres_renum)
273 return it_->highestResidueNumber_ + 1 + residueIndexInMolecule;
275 else
277 return it_->atoms_->resinfo[residueIndexInMolecule].nr;
281 const gmx_moltype_t &AtomProxy::moleculeType() const
283 return it_->mtop_->moltype[it_->mtop_->molblock[it_->mblock_].type];
286 int AtomProxy::atomNumberInMol() const
288 return it_->localAtomNumber_;
291 typedef struct gmx_mtop_atomloop_block
293 const gmx_mtop_t *mtop;
294 size_t mblock;
295 const t_atoms *atoms;
296 int at_local;
297 } t_gmx_mtop_atomloop_block;
299 gmx_mtop_atomloop_block_t
300 gmx_mtop_atomloop_block_init(const gmx_mtop_t *mtop)
302 struct gmx_mtop_atomloop_block *aloop;
304 snew(aloop, 1);
306 aloop->mtop = mtop;
307 aloop->mblock = 0;
308 aloop->atoms = &mtop->moltype[mtop->molblock[aloop->mblock].type].atoms;
309 aloop->at_local = -1;
311 return aloop;
314 static void gmx_mtop_atomloop_block_destroy(gmx_mtop_atomloop_block_t aloop)
316 sfree(aloop);
319 gmx_bool gmx_mtop_atomloop_block_next(gmx_mtop_atomloop_block_t aloop,
320 const t_atom **atom, int *nmol)
322 if (aloop == nullptr)
324 gmx_incons("gmx_mtop_atomloop_all_next called without calling gmx_mtop_atomloop_all_init");
327 aloop->at_local++;
329 if (aloop->at_local >= aloop->atoms->nr)
331 aloop->mblock++;
332 if (aloop->mblock >= aloop->mtop->molblock.size())
334 gmx_mtop_atomloop_block_destroy(aloop);
335 return FALSE;
337 aloop->atoms = &aloop->mtop->moltype[aloop->mtop->molblock[aloop->mblock].type].atoms;
338 aloop->at_local = 0;
341 *atom = &aloop->atoms->atom[aloop->at_local];
342 *nmol = aloop->mtop->molblock[aloop->mblock].nmol;
344 return TRUE;
347 typedef struct gmx_mtop_ilistloop
349 const gmx_mtop_t *mtop;
350 int mblock;
351 } t_gmx_mtop_ilist;
353 gmx_mtop_ilistloop_t
354 gmx_mtop_ilistloop_init(const gmx_mtop_t *mtop)
356 struct gmx_mtop_ilistloop *iloop;
358 snew(iloop, 1);
360 iloop->mtop = mtop;
361 iloop->mblock = -1;
363 return iloop;
366 gmx_mtop_ilistloop_t
367 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)
374 sfree(iloop);
377 const InteractionLists *
378 gmx_mtop_ilistloop_next(gmx_mtop_ilistloop_t iloop,
379 int *nmol)
381 if (iloop == nullptr)
383 gmx_incons("gmx_mtop_ilistloop_next called without calling gmx_mtop_ilistloop_init");
386 iloop->mblock++;
387 if (iloop->mblock >= gmx::ssize(iloop->mtop->molblock))
389 if (iloop->mblock == gmx::ssize(iloop->mtop->molblock) &&
390 iloop->mtop->bIntermolecularInteractions)
392 *nmol = 1;
393 return iloop->mtop->intermolecular_ilist.get();
396 gmx_mtop_ilistloop_destroy(iloop);
397 return nullptr;
400 *nmol = iloop->mtop->molblock[iloop->mblock].nmol;
402 return
403 &iloop->mtop->moltype[iloop->mtop->molblock[iloop->mblock].type].ilist;
405 typedef struct gmx_mtop_ilistloop_all
407 const gmx_mtop_t *mtop;
408 size_t mblock;
409 int mol;
410 int a_offset;
411 } t_gmx_mtop_ilist_all;
413 gmx_mtop_ilistloop_all_t
414 gmx_mtop_ilistloop_all_init(const gmx_mtop_t *mtop)
416 struct gmx_mtop_ilistloop_all *iloop;
418 snew(iloop, 1);
420 iloop->mtop = mtop;
421 iloop->mblock = 0;
422 iloop->mol = -1;
423 iloop->a_offset = 0;
425 return iloop;
428 static void gmx_mtop_ilistloop_all_destroy(gmx_mtop_ilistloop_all_t iloop)
430 sfree(iloop);
433 const InteractionLists *
434 gmx_mtop_ilistloop_all_next(gmx_mtop_ilistloop_all_t iloop,
435 int *atnr_offset)
438 if (iloop == nullptr)
440 gmx_incons("gmx_mtop_ilistloop_all_next called without calling gmx_mtop_ilistloop_all_init");
443 if (iloop->mol >= 0)
445 iloop->a_offset += iloop->mtop->moleculeBlockIndices[iloop->mblock].numAtomsPerMolecule;
448 iloop->mol++;
450 /* Inter-molecular interactions, if present, are indexed with
451 * iloop->mblock == iloop->mtop->nmolblock, thus we should separately
452 * check for this value in this conditional.
454 if (iloop->mblock == iloop->mtop->molblock.size() ||
455 iloop->mol >= iloop->mtop->molblock[iloop->mblock].nmol)
457 iloop->mblock++;
458 iloop->mol = 0;
459 if (iloop->mblock >= iloop->mtop->molblock.size())
461 if (iloop->mblock == iloop->mtop->molblock.size() &&
462 iloop->mtop->bIntermolecularInteractions)
464 *atnr_offset = 0;
465 return iloop->mtop->intermolecular_ilist.get();
468 gmx_mtop_ilistloop_all_destroy(iloop);
469 return nullptr;
473 *atnr_offset = iloop->a_offset;
475 return
476 &iloop->mtop->moltype[iloop->mtop->molblock[iloop->mblock].type].ilist;
479 int gmx_mtop_ftype_count(const gmx_mtop_t *mtop, int ftype)
481 gmx_mtop_ilistloop_t iloop;
482 int n, nmol;
484 n = 0;
486 iloop = gmx_mtop_ilistloop_init(mtop);
487 while (const InteractionLists *il = gmx_mtop_ilistloop_next(iloop, &nmol))
489 n += nmol*(*il)[ftype].size()/(1+NRAL(ftype));
492 if (mtop->bIntermolecularInteractions)
494 n += (*mtop->intermolecular_ilist)[ftype].size()/(1+NRAL(ftype));
497 return n;
500 int gmx_mtop_ftype_count(const gmx_mtop_t &mtop, int ftype)
502 return gmx_mtop_ftype_count(&mtop, ftype);
505 static void atomcat(t_atoms *dest, const t_atoms *src, int copies,
506 int maxres_renum, int *maxresnr)
508 int i, j, l, size;
509 int srcnr = src->nr;
510 int destnr = dest->nr;
512 if (dest->nr == 0)
514 dest->haveMass = src->haveMass;
515 dest->haveType = src->haveType;
516 dest->haveCharge = src->haveCharge;
517 dest->haveBState = src->haveBState;
518 dest->havePdbInfo = src->havePdbInfo;
520 else
522 dest->haveMass = dest->haveMass && src->haveMass;
523 dest->haveType = dest->haveType && src->haveType;
524 dest->haveCharge = dest->haveCharge && src->haveCharge;
525 dest->haveBState = dest->haveBState && src->haveBState;
526 dest->havePdbInfo = dest->havePdbInfo && src->havePdbInfo;
529 if (srcnr)
531 size = destnr+copies*srcnr;
532 srenew(dest->atom, size);
533 srenew(dest->atomname, size);
534 if (dest->haveType)
536 srenew(dest->atomtype, size);
537 if (dest->haveBState)
539 srenew(dest->atomtypeB, size);
542 if (dest->havePdbInfo)
544 srenew(dest->pdbinfo, size);
547 if (src->nres)
549 size = dest->nres+copies*src->nres;
550 srenew(dest->resinfo, size);
553 /* residue information */
554 for (l = dest->nres, j = 0; (j < copies); j++, l += src->nres)
556 memcpy(reinterpret_cast<char *>(&(dest->resinfo[l])), reinterpret_cast<char *>(&(src->resinfo[0])),
557 static_cast<size_t>(src->nres*sizeof(src->resinfo[0])));
560 for (l = destnr, j = 0; (j < copies); j++, l += srcnr)
562 memcpy(reinterpret_cast<char *>(&(dest->atom[l])), reinterpret_cast<char *>(&(src->atom[0])),
563 static_cast<size_t>(srcnr*sizeof(src->atom[0])));
564 memcpy(reinterpret_cast<char *>(&(dest->atomname[l])), reinterpret_cast<char *>(&(src->atomname[0])),
565 static_cast<size_t>(srcnr*sizeof(src->atomname[0])));
566 if (dest->haveType)
568 memcpy(reinterpret_cast<char *>(&(dest->atomtype[l])), reinterpret_cast<char *>(&(src->atomtype[0])),
569 static_cast<size_t>(srcnr*sizeof(src->atomtype[0])));
570 if (dest->haveBState)
572 memcpy(reinterpret_cast<char *>(&(dest->atomtypeB[l])), reinterpret_cast<char *>(&(src->atomtypeB[0])),
573 static_cast<size_t>(srcnr*sizeof(src->atomtypeB[0])));
576 if (dest->havePdbInfo)
578 memcpy(reinterpret_cast<char *>(&(dest->pdbinfo[l])), reinterpret_cast<char *>(&(src->pdbinfo[0])),
579 static_cast<size_t>(srcnr*sizeof(src->pdbinfo[0])));
583 /* Increment residue indices */
584 for (l = destnr, j = 0; (j < copies); j++)
586 for (i = 0; (i < srcnr); i++, l++)
588 dest->atom[l].resind = dest->nres+j*src->nres+src->atom[i].resind;
592 if (src->nres <= maxres_renum)
594 /* Single residue molecule, continue counting residues */
595 for (j = 0; (j < copies); j++)
597 for (l = 0; l < src->nres; l++)
599 (*maxresnr)++;
600 dest->resinfo[dest->nres+j*src->nres+l].nr = *maxresnr;
605 dest->nres += copies*src->nres;
606 dest->nr += copies*src->nr;
609 t_atoms gmx_mtop_global_atoms(const gmx_mtop_t *mtop)
611 t_atoms atoms;
613 init_t_atoms(&atoms, 0, FALSE);
615 int maxresnr = mtop->maxresnr;
616 for (const gmx_molblock_t &molb : mtop->molblock)
618 atomcat(&atoms, &mtop->moltype[molb.type].atoms, molb.nmol,
619 mtop->maxres_renum, &maxresnr);
622 return atoms;
626 * The cat routines below are old code from src/kernel/topcat.c
629 static void blockacat(t_blocka *dest, const t_blocka *src, int copies,
630 int dnum, int snum)
632 int i, j, l, size;
633 int destnr = dest->nr;
634 int destnra = dest->nra;
636 if (src->nr)
638 size = (dest->nr+copies*src->nr+1);
639 srenew(dest->index, size);
641 if (src->nra)
643 size = (dest->nra+copies*src->nra);
644 srenew(dest->a, size);
647 for (l = destnr, j = 0; (j < copies); j++)
649 for (i = 0; (i < src->nr); i++)
651 dest->index[l++] = dest->nra+src->index[i];
653 dest->nra += src->nra;
655 for (l = destnra, j = 0; (j < copies); j++)
657 for (i = 0; (i < src->nra); i++)
659 dest->a[l++] = dnum+src->a[i];
661 dnum += snum;
662 dest->nr += src->nr;
664 dest->index[dest->nr] = dest->nra;
665 dest->nalloc_index = dest->nr;
666 dest->nalloc_a = dest->nra;
669 static void ilistcat(int ftype,
670 t_ilist *dest,
671 const InteractionList &src,
672 int copies,
673 int dnum,
674 int snum)
676 int nral, c, i, a;
678 nral = NRAL(ftype);
680 dest->nalloc = dest->nr + copies*src.size();
681 srenew(dest->iatoms, dest->nalloc);
683 for (c = 0; c < copies; c++)
685 for (i = 0; i < src.size(); )
687 dest->iatoms[dest->nr++] = src.iatoms[i++];
688 for (a = 0; a < nral; a++)
690 dest->iatoms[dest->nr++] = dnum + src.iatoms[i++];
693 dnum += snum;
697 static void set_posres_params(t_idef *idef, const gmx_molblock_t *molb,
698 int i0, int a_offset)
700 t_ilist *il;
701 int i1, i, a_molb;
702 t_iparams *ip;
704 il = &idef->il[F_POSRES];
705 i1 = il->nr/2;
706 idef->iparams_posres_nalloc = i1;
707 srenew(idef->iparams_posres, idef->iparams_posres_nalloc);
708 for (i = i0; i < i1; i++)
710 ip = &idef->iparams_posres[i];
711 /* Copy the force constants */
712 *ip = idef->iparams[il->iatoms[i*2]];
713 a_molb = il->iatoms[i*2+1] - a_offset;
714 if (molb->posres_xA.empty())
716 gmx_incons("Position restraint coordinates are missing");
718 ip->posres.pos0A[XX] = molb->posres_xA[a_molb][XX];
719 ip->posres.pos0A[YY] = molb->posres_xA[a_molb][YY];
720 ip->posres.pos0A[ZZ] = molb->posres_xA[a_molb][ZZ];
721 if (!molb->posres_xB.empty())
723 ip->posres.pos0B[XX] = molb->posres_xB[a_molb][XX];
724 ip->posres.pos0B[YY] = molb->posres_xB[a_molb][YY];
725 ip->posres.pos0B[ZZ] = molb->posres_xB[a_molb][ZZ];
727 else
729 ip->posres.pos0B[XX] = ip->posres.pos0A[XX];
730 ip->posres.pos0B[YY] = ip->posres.pos0A[YY];
731 ip->posres.pos0B[ZZ] = ip->posres.pos0A[ZZ];
733 /* Set the parameter index for idef->iparams_posre */
734 il->iatoms[i*2] = i;
738 static void set_fbposres_params(t_idef *idef, const gmx_molblock_t *molb,
739 int i0, int a_offset)
741 t_ilist *il;
742 int i1, i, a_molb;
743 t_iparams *ip;
745 il = &idef->il[F_FBPOSRES];
746 i1 = il->nr/2;
747 idef->iparams_fbposres_nalloc = i1;
748 srenew(idef->iparams_fbposres, idef->iparams_fbposres_nalloc);
749 for (i = i0; i < i1; i++)
751 ip = &idef->iparams_fbposres[i];
752 /* Copy the force constants */
753 *ip = idef->iparams[il->iatoms[i*2]];
754 a_molb = il->iatoms[i*2+1] - a_offset;
755 if (molb->posres_xA.empty())
757 gmx_incons("Position restraint coordinates are missing");
759 /* Take flat-bottom posres reference from normal position restraints */
760 ip->fbposres.pos0[XX] = molb->posres_xA[a_molb][XX];
761 ip->fbposres.pos0[YY] = molb->posres_xA[a_molb][YY];
762 ip->fbposres.pos0[ZZ] = molb->posres_xA[a_molb][ZZ];
763 /* Note: no B-type for flat-bottom posres */
765 /* Set the parameter index for idef->iparams_posre */
766 il->iatoms[i*2] = i;
770 /*! \brief Copy idef structure from mtop.
772 * Makes a deep copy of an idef data structure from a gmx_mtop_t.
773 * Used to initialize legacy topology types.
775 * \param[in] mtop Reference to input mtop.
776 * \param[in] idef Pointer to idef to populate.
777 * \param[in] mergeConstr Decide if constraints will be merged.
778 * \param[in] freeEnergyInteractionsAtEnd Decide if free energy stuff should
779 * be added at the end.
781 static void copyIdefFromMtop(const gmx_mtop_t &mtop,
782 t_idef *idef,
783 bool freeEnergyInteractionsAtEnd,
784 bool mergeConstr)
786 const gmx_ffparams_t *ffp = &mtop.ffparams;
788 idef->ntypes = ffp->numTypes();
789 idef->atnr = ffp->atnr;
790 /* we can no longer copy the pointers to the mtop members,
791 * because they will become invalid as soon as mtop gets free'd.
792 * We also need to make sure to only operate on valid data!
795 if (!ffp->functype.empty())
797 snew(idef->functype, ffp->functype.size());
798 std::copy(ffp->functype.data(), ffp->functype.data() + ffp->functype.size(), idef->functype);
800 else
802 idef->functype = nullptr;
804 if (!ffp->iparams.empty())
806 snew(idef->iparams, ffp->iparams.size());
807 std::copy(ffp->iparams.data(), ffp->iparams.data() + ffp->iparams.size(), idef->iparams);
809 else
811 idef->iparams = nullptr;
813 idef->iparams_posres = nullptr;
814 idef->iparams_posres_nalloc = 0;
815 idef->iparams_fbposres = nullptr;
816 idef->iparams_fbposres_nalloc = 0;
817 idef->fudgeQQ = ffp->fudgeQQ;
818 idef->cmap_grid = new gmx_cmap_t;
819 *idef->cmap_grid = ffp->cmap_grid;
820 idef->ilsort = ilsortUNKNOWN;
822 for (int ftype = 0; ftype < F_NRE; ftype++)
824 idef->il[ftype].nr = 0;
825 idef->il[ftype].nalloc = 0;
826 idef->il[ftype].iatoms = nullptr;
829 int natoms = 0;
830 for (const gmx_molblock_t &molb : mtop.molblock)
832 const gmx_moltype_t &molt = mtop.moltype[molb.type];
834 int srcnr = molt.atoms.nr;
835 int destnr = natoms;
837 int nposre_old = idef->il[F_POSRES].nr;
838 int nfbposre_old = idef->il[F_FBPOSRES].nr;
839 for (int ftype = 0; ftype < F_NRE; ftype++)
841 if (mergeConstr &&
842 ftype == F_CONSTR && molt.ilist[F_CONSTRNC].size() > 0)
844 /* Merge all constrains into one ilist.
845 * This simplifies the constraint code.
847 for (int mol = 0; mol < molb.nmol; mol++)
849 ilistcat(ftype, &idef->il[F_CONSTR], molt.ilist[F_CONSTR],
850 1, destnr + mol*srcnr, srcnr);
851 ilistcat(ftype, &idef->il[F_CONSTR], molt.ilist[F_CONSTRNC],
852 1, destnr + mol*srcnr, srcnr);
855 else if (!(mergeConstr && ftype == F_CONSTRNC))
857 ilistcat(ftype, &idef->il[ftype], molt.ilist[ftype],
858 molb.nmol, destnr, srcnr);
861 if (idef->il[F_POSRES].nr > nposre_old)
863 /* Executing this line line stops gmxdump -sys working
864 * correctly. I'm not aware there's an elegant fix. */
865 set_posres_params(idef, &molb, nposre_old/2, natoms);
867 if (idef->il[F_FBPOSRES].nr > nfbposre_old)
869 set_fbposres_params(idef, &molb, nfbposre_old/2, natoms);
872 natoms += molb.nmol*srcnr;
875 if (mtop.bIntermolecularInteractions)
877 for (int ftype = 0; ftype < F_NRE; ftype++)
879 ilistcat(ftype, &idef->il[ftype], (*mtop.intermolecular_ilist)[ftype],
880 1, 0, mtop.natoms);
884 if (freeEnergyInteractionsAtEnd && gmx_mtop_bondeds_free_energy(&mtop))
886 std::vector<real> qA(mtop.natoms);
887 std::vector<real> qB(mtop.natoms);
888 for (const AtomProxy atomP : AtomRange(mtop))
890 const t_atom &local = atomP.atom();
891 int index = atomP.globalAtomNumber();
892 qA[index] = local.q;
893 qB[index] = local.qB;
895 gmx_sort_ilist_fe(idef, qA.data(), qB.data());
897 else
899 idef->ilsort = ilsortNO_FE;
903 /*! \brief Copy atomtypes from mtop
905 * Makes a deep copy of t_atomtypes from gmx_mtop_t.
906 * Used to initialize legacy topology types.
908 * \param[in] mtop Reference to input mtop.
909 * \param[in] atomtypes Pointer to atomtypes to populate.
911 static void copyAtomtypesFromMtop(const gmx_mtop_t &mtop,
912 t_atomtypes *atomtypes)
914 atomtypes->nr = mtop.atomtypes.nr;
915 if (mtop.atomtypes.atomnumber)
917 snew(atomtypes->atomnumber, mtop.atomtypes.nr);
918 std::copy(mtop.atomtypes.atomnumber, mtop.atomtypes.atomnumber + mtop.atomtypes.nr, atomtypes->atomnumber);
920 else
922 atomtypes->atomnumber = nullptr;
926 /*! \brief Copy excls from mtop.
928 * Makes a deep copy of excls(t_blocka) from gmx_mtop_t.
929 * Used to initialize legacy topology types.
931 * \param[in] mtop Reference to input mtop.
932 * \param[in] excls Pointer to final excls data structure.
934 static void copyExclsFromMtop(const gmx_mtop_t &mtop,
935 t_blocka *excls)
937 init_blocka(excls);
938 int natoms = 0;
939 for (const gmx_molblock_t &molb : mtop.molblock)
941 const gmx_moltype_t &molt = mtop.moltype[molb.type];
943 int srcnr = molt.atoms.nr;
944 int destnr = natoms;
946 blockacat(excls, &molt.excls, molb.nmol, destnr, srcnr);
948 natoms += molb.nmol*srcnr;
952 /*! \brief Updates inter-molecular exclusion lists
954 * This function updates inter-molecular exclusions to exclude all
955 * non-bonded interactions between a given list of atoms
957 * \param[inout] excls existing exclusions in local topology
958 * \param[in] ids list of global IDs of atoms
960 static void addMimicExclusions(t_blocka *excls,
961 const gmx::ArrayRef<const int> ids)
963 t_blocka inter_excl {};
964 init_blocka(&inter_excl);
965 size_t n_q = ids.size();
967 inter_excl.nr = excls->nr;
968 inter_excl.nra = n_q * n_q;
970 size_t total_nra = n_q * n_q;
972 snew(inter_excl.index, excls->nr + 1);
973 snew(inter_excl.a, total_nra);
975 for (int i = 0; i < excls->nr; ++i)
977 inter_excl.index[i] = 0;
980 /* Here we loop over the list of QM atom ids
981 * and create exclusions between all of them resulting in
982 * n_q * n_q sized exclusion list
984 int prev_index = 0;
985 for (int k = 0; k < inter_excl.nr; ++k)
987 inter_excl.index[k] = prev_index;
988 for (long i = 0; i < ids.ssize(); i++)
990 if (k != ids[i])
992 continue;
994 size_t index = n_q * i;
995 inter_excl.index[ids[i]] = index;
996 prev_index = index + n_q;
997 for (size_t j = 0; j < n_q; ++j)
999 inter_excl.a[n_q * i + j] = ids[j];
1003 inter_excl.index[ids[n_q - 1] + 1] = n_q * n_q;
1005 inter_excl.index[inter_excl.nr] = n_q * n_q;
1007 std::vector<gmx::ExclusionBlock> qmexcl2(excls->nr);
1008 gmx::blockaToExclusionBlocks(&inter_excl, qmexcl2);
1010 // Merge the created exclusion list with the existing one
1011 gmx::mergeExclusions(excls, qmexcl2);
1014 static void gen_local_top(const gmx_mtop_t &mtop,
1015 bool freeEnergyInteractionsAtEnd,
1016 bool bMergeConstr,
1017 gmx_localtop_t *top)
1019 copyAtomtypesFromMtop(mtop, &top->atomtypes);
1020 copyIdefFromMtop(mtop, &top->idef, freeEnergyInteractionsAtEnd, bMergeConstr);
1021 copyExclsFromMtop(mtop, &top->excls);
1022 if (!mtop.intermolecularExclusionGroup.empty())
1024 addMimicExclusions(&top->excls,
1025 mtop.intermolecularExclusionGroup);
1029 void
1030 gmx_mtop_generate_local_top(const gmx_mtop_t &mtop,
1031 gmx_localtop_t *top,
1032 bool freeEnergyInteractionsAtEnd)
1034 gen_local_top(mtop, freeEnergyInteractionsAtEnd, true, top);
1037 /*! \brief Fills an array with molecule begin/end atom indices
1039 * \param[in] mtop The global topology
1040 * \param[out] index Array of size nr. of molecules + 1 to be filled with molecule begin/end indices
1042 static void fillMoleculeIndices(const gmx_mtop_t &mtop,
1043 gmx::ArrayRef<int> index)
1045 int globalAtomIndex = 0;
1046 int globalMolIndex = 0;
1047 index[globalMolIndex] = globalAtomIndex;
1048 for (const gmx_molblock_t &molb : mtop.molblock)
1050 int numAtomsPerMolecule = mtop.moltype[molb.type].atoms.nr;
1051 for (int mol = 0; mol < molb.nmol; mol++)
1053 globalAtomIndex += numAtomsPerMolecule;
1054 globalMolIndex += 1;
1055 index[globalMolIndex] = globalAtomIndex;
1060 gmx::RangePartitioning gmx_mtop_molecules(const gmx_mtop_t &mtop)
1062 gmx::RangePartitioning mols;
1064 for (const gmx_molblock_t &molb : mtop.molblock)
1066 int numAtomsPerMolecule = mtop.moltype[molb.type].atoms.nr;
1067 for (int mol = 0; mol < molb.nmol; mol++)
1069 mols.appendBlock(numAtomsPerMolecule);
1073 return mols;
1076 /*! \brief Creates and returns a deprecated t_block struct with molecule indices
1078 * \param[in] mtop The global topology
1080 static t_block gmx_mtop_molecules_t_block(const gmx_mtop_t &mtop)
1082 t_block mols;
1084 mols.nr = gmx_mtop_num_molecules(mtop);
1085 mols.nalloc_index = mols.nr + 1;
1086 snew(mols.index, mols.nalloc_index);
1088 fillMoleculeIndices(mtop, gmx::arrayRefFromArray(mols.index, mols.nr + 1));
1090 return mols;
1093 static void gen_t_topology(const gmx_mtop_t &mtop,
1094 bool freeEnergyInteractionsAtEnd,
1095 bool bMergeConstr,
1096 t_topology *top)
1098 copyAtomtypesFromMtop(mtop, &top->atomtypes);
1099 copyIdefFromMtop(mtop, &top->idef, freeEnergyInteractionsAtEnd, bMergeConstr);
1100 copyExclsFromMtop(mtop, &top->excls);
1102 top->name = mtop.name;
1103 top->atoms = gmx_mtop_global_atoms(&mtop);
1104 top->mols = gmx_mtop_molecules_t_block(mtop);
1105 top->bIntermolecularInteractions = mtop.bIntermolecularInteractions;
1106 top->symtab = mtop.symtab;
1109 t_topology gmx_mtop_t_to_t_topology(gmx_mtop_t *mtop, bool freeMTop)
1111 t_topology top;
1113 gen_t_topology(*mtop, false, false, &top);
1115 if (freeMTop)
1117 // Clear pointers and counts, such that the pointers copied to top
1118 // keep pointing to valid data after destroying mtop.
1119 mtop->symtab.symbuf = nullptr;
1120 mtop->symtab.nr = 0;
1122 return top;
1125 std::vector<int> get_atom_index(const gmx_mtop_t *mtop)
1128 std::vector<int> atom_index;
1129 for (const AtomProxy atomP : AtomRange(*mtop))
1131 const t_atom &local = atomP.atom();
1132 int index = atomP.globalAtomNumber();
1133 if (local.ptype == eptAtom)
1135 atom_index.push_back(index);
1138 return atom_index;
1141 void convertAtomsToMtop(t_symtab *symtab,
1142 char **name,
1143 t_atoms *atoms,
1144 gmx_mtop_t *mtop)
1146 mtop->symtab = *symtab;
1148 mtop->name = name;
1150 mtop->moltype.clear();
1151 mtop->moltype.resize(1);
1152 mtop->moltype.back().atoms = *atoms;
1154 mtop->molblock.resize(1);
1155 mtop->molblock[0].type = 0;
1156 mtop->molblock[0].nmol = 1;
1158 mtop->bIntermolecularInteractions = FALSE;
1160 mtop->natoms = atoms->nr;
1162 mtop->haveMoleculeIndices = false;
1164 gmx_mtop_finalize(mtop);