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.
38 #include "mtop_util.h"
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
)
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
;
81 static void buildMolblockIndices(gmx_mtop_t
*mtop
)
83 mtop
->moleculeBlockIndices
.resize(mtop
->molblock
.size());
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
)
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;
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");
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
)
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
)
161 tpi
= atoms
.atom
[i
].type
;
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
;
182 int gmx_mtop_nres(const gmx_mtop_t
*mtop
)
185 for (const gmx_molblock_t
&molb
: mtop
->molblock
)
187 nres
+= molb
.nmol
*mtop
->moltype
[molb
.type
].atoms
.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++()
207 if (localAtomNumber_
>= atoms_
->nr
)
209 if (atoms_
->nres
<= mtop_
->maxresnr
)
211 /* Single residue molecule, increase the count with one */
212 highestResidueNumber_
+= atoms_
->nres
;
215 localAtomNumber_
= 0;
216 if (currentMolecule_
>= mtop_
->molblock
[mblock_
].nmol
)
219 if (mblock_
>= mtop_
->molblock
.size())
223 atoms_
= &mtop_
->moltype
[mtop_
->molblock
[mblock_
].type
].atoms
;
224 currentMolecule_
= 0;
230 AtomIterator
AtomIterator::operator++(int)
232 AtomIterator temp
= *this;
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
;
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
;
295 const t_atoms
*atoms
;
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
;
308 aloop
->atoms
= &mtop
->moltype
[mtop
->molblock
[aloop
->mblock
].type
].atoms
;
309 aloop
->at_local
= -1;
314 static void gmx_mtop_atomloop_block_destroy(gmx_mtop_atomloop_block_t 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");
329 if (aloop
->at_local
>= aloop
->atoms
->nr
)
332 if (aloop
->mblock
>= aloop
->mtop
->molblock
.size())
334 gmx_mtop_atomloop_block_destroy(aloop
);
337 aloop
->atoms
= &aloop
->mtop
->moltype
[aloop
->mtop
->molblock
[aloop
->mblock
].type
].atoms
;
341 *atom
= &aloop
->atoms
->atom
[aloop
->at_local
];
342 *nmol
= aloop
->mtop
->molblock
[aloop
->mblock
].nmol
;
347 typedef struct gmx_mtop_ilistloop
349 const gmx_mtop_t
*mtop
;
354 gmx_mtop_ilistloop_init(const gmx_mtop_t
*mtop
)
356 struct gmx_mtop_ilistloop
*iloop
;
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
)
377 const InteractionLists
*
378 gmx_mtop_ilistloop_next(gmx_mtop_ilistloop_t iloop
,
381 if (iloop
== nullptr)
383 gmx_incons("gmx_mtop_ilistloop_next called without calling gmx_mtop_ilistloop_init");
387 if (iloop
->mblock
>= gmx::ssize(iloop
->mtop
->molblock
))
389 if (iloop
->mblock
== gmx::ssize(iloop
->mtop
->molblock
) &&
390 iloop
->mtop
->bIntermolecularInteractions
)
393 return iloop
->mtop
->intermolecular_ilist
.get();
396 gmx_mtop_ilistloop_destroy(iloop
);
400 *nmol
= iloop
->mtop
->molblock
[iloop
->mblock
].nmol
;
403 &iloop
->mtop
->moltype
[iloop
->mtop
->molblock
[iloop
->mblock
].type
].ilist
;
405 typedef struct gmx_mtop_ilistloop_all
407 const gmx_mtop_t
*mtop
;
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
;
428 static void gmx_mtop_ilistloop_all_destroy(gmx_mtop_ilistloop_all_t iloop
)
433 const InteractionLists
*
434 gmx_mtop_ilistloop_all_next(gmx_mtop_ilistloop_all_t iloop
,
438 if (iloop
== nullptr)
440 gmx_incons("gmx_mtop_ilistloop_all_next called without calling gmx_mtop_ilistloop_all_init");
445 iloop
->a_offset
+= iloop
->mtop
->moleculeBlockIndices
[iloop
->mblock
].numAtomsPerMolecule
;
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
)
459 if (iloop
->mblock
>= iloop
->mtop
->molblock
.size())
461 if (iloop
->mblock
== iloop
->mtop
->molblock
.size() &&
462 iloop
->mtop
->bIntermolecularInteractions
)
465 return iloop
->mtop
->intermolecular_ilist
.get();
468 gmx_mtop_ilistloop_all_destroy(iloop
);
473 *atnr_offset
= iloop
->a_offset
;
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
;
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
));
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
)
510 int destnr
= dest
->nr
;
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
;
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
;
531 size
= destnr
+copies
*srcnr
;
532 srenew(dest
->atom
, size
);
533 srenew(dest
->atomname
, size
);
536 srenew(dest
->atomtype
, size
);
537 if (dest
->haveBState
)
539 srenew(dest
->atomtypeB
, size
);
542 if (dest
->havePdbInfo
)
544 srenew(dest
->pdbinfo
, size
);
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])));
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
++)
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
)
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
);
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
,
633 int destnr
= dest
->nr
;
634 int destnra
= dest
->nra
;
638 size
= (dest
->nr
+copies
*src
->nr
+1);
639 srenew(dest
->index
, size
);
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
];
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
,
671 const InteractionList
&src
,
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
++];
697 static void set_posres_params(t_idef
*idef
, const gmx_molblock_t
*molb
,
698 int i0
, int a_offset
)
704 il
= &idef
->il
[F_POSRES
];
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
];
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 */
738 static void set_fbposres_params(t_idef
*idef
, const gmx_molblock_t
*molb
,
739 int i0
, int a_offset
)
745 il
= &idef
->il
[F_FBPOSRES
];
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 */
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
,
783 bool freeEnergyInteractionsAtEnd
,
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
);
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
);
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;
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
;
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
++)
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
],
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();
893 qB
[index
] = local
.qB
;
895 gmx_sort_ilist_fe(idef
, qA
.data(), qB
.data());
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
);
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
,
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
;
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
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
++)
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
,
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
);
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
);
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
)
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));
1093 static void gen_t_topology(const gmx_mtop_t
&mtop
,
1094 bool freeEnergyInteractionsAtEnd
,
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
)
1113 gen_t_topology(*mtop
, false, false, &top
);
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;
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
);
1141 void convertAtomsToMtop(t_symtab
*symtab
,
1146 mtop
->symtab
= *symtab
;
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
);