Add coolquotes
[gromacs.git] / src / gromacs / topology / mtop_util.cpp
blobcea904562fa86ea70bd26cb129d07e43ef1030a5
1 /*
2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2008,2009,2010,2012,2013,2014,2015,2016,2017,2018, by the GROMACS development team, led by
5 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6 * and including many others, as listed in the AUTHORS file in the
7 * top-level source directory and at http://www.gromacs.org.
9 * GROMACS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1
12 * of the License, or (at your option) any later version.
14 * GROMACS is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with GROMACS; if not, see
21 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * If you want to redistribute modifications to GROMACS, please
25 * consider that scientific software is very special. Version
26 * control is crucial - bugs must be traceable. We will be happy to
27 * consider code for inclusion in the official distribution, but
28 * derived work must not be called official GROMACS. Details are found
29 * in the README & COPYING files - if they are missing, get the
30 * official version at http://www.gromacs.org.
32 * To help us fund GROMACS development, we humbly ask that you cite
33 * the research papers on the package. Check out http://www.gromacs.org.
35 #include "gmxpre.h"
37 #include "mtop_util.h"
39 #include <climits>
40 #include <cstddef>
41 #include <cstdio>
42 #include <cstdlib>
43 #include <cstring>
45 #include "gromacs/math/vectypes.h"
46 #include "gromacs/topology/atoms.h"
47 #include "gromacs/topology/block.h"
48 #include "gromacs/topology/exclusionblocks.h"
49 #include "gromacs/topology/idef.h"
50 #include "gromacs/topology/ifunc.h"
51 #include "gromacs/topology/topology.h"
52 #include "gromacs/topology/topsort.h"
53 #include "gromacs/utility/arrayref.h"
54 #include "gromacs/utility/fatalerror.h"
55 #include "gromacs/utility/real.h"
56 #include "gromacs/utility/smalloc.h"
58 static int gmx_mtop_maxresnr(const gmx_mtop_t *mtop, int maxres_renum)
60 int maxresnr = 0;
62 for (const gmx_moltype_t &moltype : mtop->moltype)
64 const t_atoms &atoms = moltype.atoms;
65 if (atoms.nres > maxres_renum)
67 for (int r = 0; r < atoms.nres; r++)
69 if (atoms.resinfo[r].nr > maxresnr)
71 maxresnr = atoms.resinfo[r].nr;
77 return maxresnr;
80 static void buildMolblockIndices(gmx_mtop_t *mtop)
82 mtop->moleculeBlockIndices.resize(mtop->molblock.size());
84 int atomIndex = 0;
85 int residueIndex = 0;
86 int residueNumberStart = mtop->maxresnr + 1;
87 int moleculeIndexStart = 0;
88 for (size_t mb = 0; mb < mtop->molblock.size(); mb++)
90 const gmx_molblock_t &molb = mtop->molblock[mb];
91 MoleculeBlockIndices &indices = mtop->moleculeBlockIndices[mb];
92 const int numResPerMol = mtop->moltype[molb.type].atoms.nres;
94 indices.numAtomsPerMolecule = mtop->moltype[molb.type].atoms.nr;
95 indices.globalAtomStart = atomIndex;
96 indices.globalResidueStart = residueIndex;
97 atomIndex += molb.nmol*indices.numAtomsPerMolecule;
98 residueIndex += molb.nmol*numResPerMol;
99 indices.globalAtomEnd = atomIndex;
100 indices.residueNumberStart = residueNumberStart;
101 if (numResPerMol <= mtop->maxres_renum)
103 residueNumberStart += molb.nmol*numResPerMol;
105 indices.moleculeIndexStart = moleculeIndexStart;
106 moleculeIndexStart += molb.nmol;
110 void gmx_mtop_finalize(gmx_mtop_t *mtop)
112 char *env;
114 if (mtop->molblock.size() == 1 && mtop->molblock[0].nmol == 1)
116 /* We have a single molecule only, no renumbering needed.
117 * This case also covers an mtop converted from pdb/gro/... input,
118 * so we retain the original residue numbering.
120 mtop->maxres_renum = 0;
122 else
124 /* We only renumber single residue molecules. Their intra-molecular
125 * residue numbering is anyhow irrelevant.
127 mtop->maxres_renum = 1;
130 env = getenv("GMX_MAXRESRENUM");
131 if (env != nullptr)
133 sscanf(env, "%d", &mtop->maxres_renum);
135 if (mtop->maxres_renum == -1)
137 /* -1 signals renumber residues in all molecules */
138 mtop->maxres_renum = INT_MAX;
141 mtop->maxresnr = gmx_mtop_maxresnr(mtop, mtop->maxres_renum);
143 buildMolblockIndices(mtop);
146 void gmx_mtop_count_atomtypes(const gmx_mtop_t *mtop, int state, int typecount[])
148 for (int i = 0; i < mtop->ffparams.atnr; ++i)
150 typecount[i] = 0;
152 for (const gmx_molblock_t &molb : mtop->molblock)
154 const t_atoms &atoms = mtop->moltype[molb.type].atoms;
155 for (int i = 0; i < atoms.nr; ++i)
157 int tpi;
158 if (state == 0)
160 tpi = atoms.atom[i].type;
162 else
164 tpi = atoms.atom[i].typeB;
166 typecount[tpi] += molb.nmol;
171 int ncg_mtop(const gmx_mtop_t *mtop)
173 int ncg = 0;
174 for (const gmx_molblock_t &molb : mtop->molblock)
176 ncg += molb.nmol*mtop->moltype[molb.type].cgs.nr;
179 return ncg;
182 int gmx_mtop_num_molecules(const gmx_mtop_t &mtop)
184 int numMolecules = 0;
185 for (const gmx_molblock_t &molb : mtop.molblock)
187 numMolecules += molb.nmol;
189 return numMolecules;
192 int gmx_mtop_nres(const gmx_mtop_t *mtop)
194 int nres = 0;
195 for (const gmx_molblock_t &molb : mtop->molblock)
197 nres += molb.nmol*mtop->moltype[molb.type].atoms.nres;
199 return nres;
202 void gmx_mtop_remove_chargegroups(gmx_mtop_t *mtop)
204 for (gmx_moltype_t &molt : mtop->moltype)
206 t_block &cgs = molt.cgs;
207 if (cgs.nr < molt.atoms.nr)
209 cgs.nr = molt.atoms.nr;
210 srenew(cgs.index, cgs.nr + 1);
211 for (int i = 0; i < cgs.nr + 1; i++)
213 cgs.index[i] = i;
219 typedef struct gmx_mtop_atomloop_all
221 const gmx_mtop_t *mtop;
222 size_t mblock;
223 const t_atoms *atoms;
224 int mol;
225 int maxresnr;
226 int at_local;
227 int at_global;
228 } t_gmx_mtop_atomloop_all;
230 gmx_mtop_atomloop_all_t
231 gmx_mtop_atomloop_all_init(const gmx_mtop_t *mtop)
233 struct gmx_mtop_atomloop_all *aloop;
235 snew(aloop, 1);
237 aloop->mtop = mtop;
238 aloop->mblock = 0;
239 aloop->atoms =
240 &mtop->moltype[mtop->molblock[aloop->mblock].type].atoms;
241 aloop->mol = 0;
242 aloop->maxresnr = mtop->maxresnr;
243 aloop->at_local = -1;
244 aloop->at_global = -1;
246 return aloop;
249 static void gmx_mtop_atomloop_all_destroy(gmx_mtop_atomloop_all_t aloop)
251 sfree(aloop);
254 gmx_bool gmx_mtop_atomloop_all_next(gmx_mtop_atomloop_all_t aloop,
255 int *at_global, const t_atom **atom)
257 if (aloop == nullptr)
259 gmx_incons("gmx_mtop_atomloop_all_next called without calling gmx_mtop_atomloop_all_init");
262 aloop->at_local++;
263 aloop->at_global++;
265 if (aloop->at_local >= aloop->atoms->nr)
267 if (aloop->atoms->nres <= aloop->mtop->maxres_renum)
269 /* Single residue molecule, increase the count with one */
270 aloop->maxresnr += aloop->atoms->nres;
272 aloop->mol++;
273 aloop->at_local = 0;
274 if (aloop->mol >= aloop->mtop->molblock[aloop->mblock].nmol)
276 aloop->mblock++;
277 if (aloop->mblock >= aloop->mtop->molblock.size())
279 gmx_mtop_atomloop_all_destroy(aloop);
280 return FALSE;
282 aloop->atoms = &aloop->mtop->moltype[aloop->mtop->molblock[aloop->mblock].type].atoms;
283 aloop->mol = 0;
287 *at_global = aloop->at_global;
288 *atom = &aloop->atoms->atom[aloop->at_local];
290 return TRUE;
293 void gmx_mtop_atomloop_all_names(gmx_mtop_atomloop_all_t aloop,
294 char **atomname, int *resnr, char **resname)
296 int resind_mol;
298 *atomname = *(aloop->atoms->atomname[aloop->at_local]);
299 resind_mol = aloop->atoms->atom[aloop->at_local].resind;
300 *resnr = aloop->atoms->resinfo[resind_mol].nr;
301 if (aloop->atoms->nres <= aloop->mtop->maxres_renum)
303 *resnr = aloop->maxresnr + 1 + resind_mol;
305 *resname = *(aloop->atoms->resinfo[resind_mol].name);
308 void gmx_mtop_atomloop_all_moltype(gmx_mtop_atomloop_all_t aloop,
309 const gmx_moltype_t **moltype,
310 int *at_mol)
312 *moltype = &aloop->mtop->moltype[aloop->mtop->molblock[aloop->mblock].type];
313 *at_mol = aloop->at_local;
316 typedef struct gmx_mtop_atomloop_block
318 const gmx_mtop_t *mtop;
319 size_t mblock;
320 const t_atoms *atoms;
321 int at_local;
322 } t_gmx_mtop_atomloop_block;
324 gmx_mtop_atomloop_block_t
325 gmx_mtop_atomloop_block_init(const gmx_mtop_t *mtop)
327 struct gmx_mtop_atomloop_block *aloop;
329 snew(aloop, 1);
331 aloop->mtop = mtop;
332 aloop->mblock = 0;
333 aloop->atoms = &mtop->moltype[mtop->molblock[aloop->mblock].type].atoms;
334 aloop->at_local = -1;
336 return aloop;
339 static void gmx_mtop_atomloop_block_destroy(gmx_mtop_atomloop_block_t aloop)
341 sfree(aloop);
344 gmx_bool gmx_mtop_atomloop_block_next(gmx_mtop_atomloop_block_t aloop,
345 const t_atom **atom, int *nmol)
347 if (aloop == nullptr)
349 gmx_incons("gmx_mtop_atomloop_all_next called without calling gmx_mtop_atomloop_all_init");
352 aloop->at_local++;
354 if (aloop->at_local >= aloop->atoms->nr)
356 aloop->mblock++;
357 if (aloop->mblock >= aloop->mtop->molblock.size())
359 gmx_mtop_atomloop_block_destroy(aloop);
360 return FALSE;
362 aloop->atoms = &aloop->mtop->moltype[aloop->mtop->molblock[aloop->mblock].type].atoms;
363 aloop->at_local = 0;
366 *atom = &aloop->atoms->atom[aloop->at_local];
367 *nmol = aloop->mtop->molblock[aloop->mblock].nmol;
369 return TRUE;
372 typedef struct gmx_mtop_ilistloop
374 const gmx_mtop_t *mtop;
375 int mblock;
376 } t_gmx_mtop_ilist;
378 gmx_mtop_ilistloop_t
379 gmx_mtop_ilistloop_init(const gmx_mtop_t *mtop)
381 struct gmx_mtop_ilistloop *iloop;
383 snew(iloop, 1);
385 iloop->mtop = mtop;
386 iloop->mblock = -1;
388 return iloop;
391 gmx_mtop_ilistloop_t
392 gmx_mtop_ilistloop_init(const gmx_mtop_t &mtop)
394 return gmx_mtop_ilistloop_init(&mtop);
397 static void gmx_mtop_ilistloop_destroy(gmx_mtop_ilistloop_t iloop)
399 sfree(iloop);
402 const InteractionLists *
403 gmx_mtop_ilistloop_next(gmx_mtop_ilistloop_t iloop,
404 int *nmol)
406 if (iloop == nullptr)
408 gmx_incons("gmx_mtop_ilistloop_next called without calling gmx_mtop_ilistloop_init");
411 iloop->mblock++;
412 if (iloop->mblock >= static_cast<int>(iloop->mtop->molblock.size()))
414 if (iloop->mblock == static_cast<int>(iloop->mtop->molblock.size()) &&
415 iloop->mtop->bIntermolecularInteractions)
417 *nmol = 1;
418 return iloop->mtop->intermolecular_ilist.get();
421 gmx_mtop_ilistloop_destroy(iloop);
422 return nullptr;
425 *nmol = iloop->mtop->molblock[iloop->mblock].nmol;
427 return
428 &iloop->mtop->moltype[iloop->mtop->molblock[iloop->mblock].type].ilist;
430 typedef struct gmx_mtop_ilistloop_all
432 const gmx_mtop_t *mtop;
433 size_t mblock;
434 int mol;
435 int a_offset;
436 } t_gmx_mtop_ilist_all;
438 gmx_mtop_ilistloop_all_t
439 gmx_mtop_ilistloop_all_init(const gmx_mtop_t *mtop)
441 struct gmx_mtop_ilistloop_all *iloop;
443 snew(iloop, 1);
445 iloop->mtop = mtop;
446 iloop->mblock = 0;
447 iloop->mol = -1;
448 iloop->a_offset = 0;
450 return iloop;
453 static void gmx_mtop_ilistloop_all_destroy(gmx_mtop_ilistloop_all_t iloop)
455 sfree(iloop);
458 const InteractionLists *
459 gmx_mtop_ilistloop_all_next(gmx_mtop_ilistloop_all_t iloop,
460 int *atnr_offset)
463 if (iloop == nullptr)
465 gmx_incons("gmx_mtop_ilistloop_all_next called without calling gmx_mtop_ilistloop_all_init");
468 if (iloop->mol >= 0)
470 iloop->a_offset += iloop->mtop->moleculeBlockIndices[iloop->mblock].numAtomsPerMolecule;
473 iloop->mol++;
475 /* Inter-molecular interactions, if present, are indexed with
476 * iloop->mblock == iloop->mtop->nmolblock, thus we should separately
477 * check for this value in this conditional.
479 if (iloop->mblock == iloop->mtop->molblock.size() ||
480 iloop->mol >= iloop->mtop->molblock[iloop->mblock].nmol)
482 iloop->mblock++;
483 iloop->mol = 0;
484 if (iloop->mblock >= iloop->mtop->molblock.size())
486 if (iloop->mblock == iloop->mtop->molblock.size() &&
487 iloop->mtop->bIntermolecularInteractions)
489 *atnr_offset = 0;
490 return iloop->mtop->intermolecular_ilist.get();
493 gmx_mtop_ilistloop_all_destroy(iloop);
494 return nullptr;
498 *atnr_offset = iloop->a_offset;
500 return
501 &iloop->mtop->moltype[iloop->mtop->molblock[iloop->mblock].type].ilist;
504 int gmx_mtop_ftype_count(const gmx_mtop_t *mtop, int ftype)
506 gmx_mtop_ilistloop_t iloop;
507 int n, nmol;
509 n = 0;
511 iloop = gmx_mtop_ilistloop_init(mtop);
512 while (const InteractionLists *il = gmx_mtop_ilistloop_next(iloop, &nmol))
514 n += nmol*(*il)[ftype].size()/(1+NRAL(ftype));
517 if (mtop->bIntermolecularInteractions)
519 n += (*mtop->intermolecular_ilist)[ftype].size()/(1+NRAL(ftype));
522 return n;
525 int gmx_mtop_ftype_count(const gmx_mtop_t &mtop, int ftype)
527 return gmx_mtop_ftype_count(&mtop, ftype);
530 t_block gmx_mtop_global_cgs(const gmx_mtop_t *mtop)
532 t_block cgs_gl;
533 /* In most cases this is too much, but we realloc at the end */
534 snew(cgs_gl.index, mtop->natoms+1);
536 cgs_gl.nr = 0;
537 cgs_gl.index[0] = 0;
538 for (const gmx_molblock_t &molb : mtop->molblock)
540 const t_block &cgs_mol = mtop->moltype[molb.type].cgs;
541 for (int mol = 0; mol < molb.nmol; mol++)
543 for (int cg = 0; cg < cgs_mol.nr; cg++)
545 cgs_gl.index[cgs_gl.nr + 1] =
546 cgs_gl.index[cgs_gl.nr] +
547 cgs_mol.index[cg + 1] - cgs_mol.index[cg];
548 cgs_gl.nr++;
552 cgs_gl.nalloc_index = cgs_gl.nr + 1;
553 srenew(cgs_gl.index, cgs_gl.nalloc_index);
555 return cgs_gl;
558 static void atomcat(t_atoms *dest, const t_atoms *src, int copies,
559 int maxres_renum, int *maxresnr)
561 int i, j, l, size;
562 int srcnr = src->nr;
563 int destnr = dest->nr;
565 if (dest->nr == 0)
567 dest->haveMass = src->haveMass;
568 dest->haveType = src->haveType;
569 dest->haveCharge = src->haveCharge;
570 dest->haveBState = src->haveBState;
571 dest->havePdbInfo = src->havePdbInfo;
573 else
575 dest->haveMass = dest->haveMass && src->haveMass;
576 dest->haveType = dest->haveType && src->haveType;
577 dest->haveCharge = dest->haveCharge && src->haveCharge;
578 dest->haveBState = dest->haveBState && src->haveBState;
579 dest->havePdbInfo = dest->havePdbInfo && src->havePdbInfo;
582 if (srcnr)
584 size = destnr+copies*srcnr;
585 srenew(dest->atom, size);
586 srenew(dest->atomname, size);
587 if (dest->haveType)
589 srenew(dest->atomtype, size);
590 if (dest->haveBState)
592 srenew(dest->atomtypeB, size);
595 if (dest->havePdbInfo)
597 srenew(dest->pdbinfo, size);
600 if (src->nres)
602 size = dest->nres+copies*src->nres;
603 srenew(dest->resinfo, size);
606 /* residue information */
607 for (l = dest->nres, j = 0; (j < copies); j++, l += src->nres)
609 memcpy(reinterpret_cast<char *>(&(dest->resinfo[l])), reinterpret_cast<char *>(&(src->resinfo[0])),
610 static_cast<size_t>(src->nres*sizeof(src->resinfo[0])));
613 for (l = destnr, j = 0; (j < copies); j++, l += srcnr)
615 memcpy(reinterpret_cast<char *>(&(dest->atom[l])), reinterpret_cast<char *>(&(src->atom[0])),
616 static_cast<size_t>(srcnr*sizeof(src->atom[0])));
617 memcpy(reinterpret_cast<char *>(&(dest->atomname[l])), reinterpret_cast<char *>(&(src->atomname[0])),
618 static_cast<size_t>(srcnr*sizeof(src->atomname[0])));
619 if (dest->haveType)
621 memcpy(reinterpret_cast<char *>(&(dest->atomtype[l])), reinterpret_cast<char *>(&(src->atomtype[0])),
622 static_cast<size_t>(srcnr*sizeof(src->atomtype[0])));
623 if (dest->haveBState)
625 memcpy(reinterpret_cast<char *>(&(dest->atomtypeB[l])), reinterpret_cast<char *>(&(src->atomtypeB[0])),
626 static_cast<size_t>(srcnr*sizeof(src->atomtypeB[0])));
629 if (dest->havePdbInfo)
631 memcpy(reinterpret_cast<char *>(&(dest->pdbinfo[l])), reinterpret_cast<char *>(&(src->pdbinfo[0])),
632 static_cast<size_t>(srcnr*sizeof(src->pdbinfo[0])));
636 /* Increment residue indices */
637 for (l = destnr, j = 0; (j < copies); j++)
639 for (i = 0; (i < srcnr); i++, l++)
641 dest->atom[l].resind = dest->nres+j*src->nres+src->atom[i].resind;
645 if (src->nres <= maxres_renum)
647 /* Single residue molecule, continue counting residues */
648 for (j = 0; (j < copies); j++)
650 for (l = 0; l < src->nres; l++)
652 (*maxresnr)++;
653 dest->resinfo[dest->nres+j*src->nres+l].nr = *maxresnr;
658 dest->nres += copies*src->nres;
659 dest->nr += copies*src->nr;
662 t_atoms gmx_mtop_global_atoms(const gmx_mtop_t *mtop)
664 t_atoms atoms;
666 init_t_atoms(&atoms, 0, FALSE);
668 int maxresnr = mtop->maxresnr;
669 for (const gmx_molblock_t &molb : mtop->molblock)
671 atomcat(&atoms, &mtop->moltype[molb.type].atoms, molb.nmol,
672 mtop->maxres_renum, &maxresnr);
675 return atoms;
679 * The cat routines below are old code from src/kernel/topcat.c
682 static void blockcat(t_block *dest, const t_block *src, int copies)
684 int i, j, l, nra, size;
686 if (src->nr)
688 size = (dest->nr+copies*src->nr+1);
689 srenew(dest->index, size);
692 nra = dest->index[dest->nr];
693 for (l = dest->nr, j = 0; (j < copies); j++)
695 for (i = 0; (i < src->nr); i++)
697 dest->index[l++] = nra + src->index[i];
699 if (src->nr > 0)
701 nra += src->index[src->nr];
704 dest->nr += copies*src->nr;
705 dest->index[dest->nr] = nra;
708 static void blockacat(t_blocka *dest, const t_blocka *src, int copies,
709 int dnum, int snum)
711 int i, j, l, size;
712 int destnr = dest->nr;
713 int destnra = dest->nra;
715 if (src->nr)
717 size = (dest->nr+copies*src->nr+1);
718 srenew(dest->index, size);
720 if (src->nra)
722 size = (dest->nra+copies*src->nra);
723 srenew(dest->a, size);
726 for (l = destnr, j = 0; (j < copies); j++)
728 for (i = 0; (i < src->nr); i++)
730 dest->index[l++] = dest->nra+src->index[i];
732 dest->nra += src->nra;
734 for (l = destnra, j = 0; (j < copies); j++)
736 for (i = 0; (i < src->nra); i++)
738 dest->a[l++] = dnum+src->a[i];
740 dnum += snum;
741 dest->nr += src->nr;
743 dest->index[dest->nr] = dest->nra;
744 dest->nalloc_index = dest->nr;
745 dest->nalloc_a = dest->nra;
748 static void ilistcat(int ftype,
749 t_ilist *dest,
750 const InteractionList &src,
751 int copies,
752 int dnum,
753 int snum)
755 int nral, c, i, a;
757 nral = NRAL(ftype);
759 dest->nalloc = dest->nr + copies*src.size();
760 srenew(dest->iatoms, dest->nalloc);
762 for (c = 0; c < copies; c++)
764 for (i = 0; i < src.size(); )
766 dest->iatoms[dest->nr++] = src.iatoms[i++];
767 for (a = 0; a < nral; a++)
769 dest->iatoms[dest->nr++] = dnum + src.iatoms[i++];
772 dnum += snum;
776 static void set_posres_params(t_idef *idef, const gmx_molblock_t *molb,
777 int i0, int a_offset)
779 t_ilist *il;
780 int i1, i, a_molb;
781 t_iparams *ip;
783 il = &idef->il[F_POSRES];
784 i1 = il->nr/2;
785 idef->iparams_posres_nalloc = i1;
786 srenew(idef->iparams_posres, idef->iparams_posres_nalloc);
787 for (i = i0; i < i1; i++)
789 ip = &idef->iparams_posres[i];
790 /* Copy the force constants */
791 *ip = idef->iparams[il->iatoms[i*2]];
792 a_molb = il->iatoms[i*2+1] - a_offset;
793 if (molb->posres_xA.empty())
795 gmx_incons("Position restraint coordinates are missing");
797 ip->posres.pos0A[XX] = molb->posres_xA[a_molb][XX];
798 ip->posres.pos0A[YY] = molb->posres_xA[a_molb][YY];
799 ip->posres.pos0A[ZZ] = molb->posres_xA[a_molb][ZZ];
800 if (!molb->posres_xB.empty())
802 ip->posres.pos0B[XX] = molb->posres_xB[a_molb][XX];
803 ip->posres.pos0B[YY] = molb->posres_xB[a_molb][YY];
804 ip->posres.pos0B[ZZ] = molb->posres_xB[a_molb][ZZ];
806 else
808 ip->posres.pos0B[XX] = ip->posres.pos0A[XX];
809 ip->posres.pos0B[YY] = ip->posres.pos0A[YY];
810 ip->posres.pos0B[ZZ] = ip->posres.pos0A[ZZ];
812 /* Set the parameter index for idef->iparams_posre */
813 il->iatoms[i*2] = i;
817 static void set_fbposres_params(t_idef *idef, const gmx_molblock_t *molb,
818 int i0, int a_offset)
820 t_ilist *il;
821 int i1, i, a_molb;
822 t_iparams *ip;
824 il = &idef->il[F_FBPOSRES];
825 i1 = il->nr/2;
826 idef->iparams_fbposres_nalloc = i1;
827 srenew(idef->iparams_fbposres, idef->iparams_fbposres_nalloc);
828 for (i = i0; i < i1; i++)
830 ip = &idef->iparams_fbposres[i];
831 /* Copy the force constants */
832 *ip = idef->iparams[il->iatoms[i*2]];
833 a_molb = il->iatoms[i*2+1] - a_offset;
834 if (molb->posres_xA.empty())
836 gmx_incons("Position restraint coordinates are missing");
838 /* Take flat-bottom posres reference from normal position restraints */
839 ip->fbposres.pos0[XX] = molb->posres_xA[a_molb][XX];
840 ip->fbposres.pos0[YY] = molb->posres_xA[a_molb][YY];
841 ip->fbposres.pos0[ZZ] = molb->posres_xA[a_molb][ZZ];
842 /* Note: no B-type for flat-bottom posres */
844 /* Set the parameter index for idef->iparams_posre */
845 il->iatoms[i*2] = i;
849 /*! \brief Copy idef structure from mtop.
851 * Makes a deep copy of an idef data structure from a gmx_mtop_t.
852 * Used to initialize legacy topology types.
854 * \param[in] mtop Reference to input mtop.
855 * \param[in] idef Pointer to idef to populate.
856 * \param[in] mergeConstr Decide if constraints will be merged.
857 * \param[in] freeEnergyInteractionsAtEnd Decide if free energy stuff should
858 * be added at the end.
860 static void copyIdefFromMtop(const gmx_mtop_t &mtop,
861 t_idef *idef,
862 bool freeEnergyInteractionsAtEnd,
863 bool mergeConstr)
865 const gmx_ffparams_t *ffp = &mtop.ffparams;
867 idef->ntypes = ffp->numTypes();
868 idef->atnr = ffp->atnr;
869 /* we can no longer copy the pointers to the mtop members,
870 * because they will become invalid as soon as mtop gets free'd.
871 * We also need to make sure to only operate on valid data!
874 if (!ffp->functype.empty())
876 snew(idef->functype, ffp->functype.size());
877 std::copy(ffp->functype.data(), ffp->functype.data() + ffp->functype.size(), idef->functype);
879 else
881 idef->functype = nullptr;
883 if (!ffp->iparams.empty())
885 snew(idef->iparams, ffp->iparams.size());
886 std::copy(ffp->iparams.data(), ffp->iparams.data() + ffp->iparams.size(), idef->iparams);
888 else
890 idef->iparams = nullptr;
892 idef->iparams_posres = nullptr;
893 idef->iparams_posres_nalloc = 0;
894 idef->iparams_fbposres = nullptr;
895 idef->iparams_fbposres_nalloc = 0;
896 idef->fudgeQQ = ffp->fudgeQQ;
897 idef->cmap_grid = new gmx_cmap_t;
898 *idef->cmap_grid = ffp->cmap_grid;
899 idef->ilsort = ilsortUNKNOWN;
901 for (int ftype = 0; ftype < F_NRE; ftype++)
903 idef->il[ftype].nr = 0;
904 idef->il[ftype].nalloc = 0;
905 idef->il[ftype].iatoms = nullptr;
908 int natoms = 0;
909 for (const gmx_molblock_t &molb : mtop.molblock)
911 const gmx_moltype_t &molt = mtop.moltype[molb.type];
913 int srcnr = molt.atoms.nr;
914 int destnr = natoms;
916 int nposre_old = idef->il[F_POSRES].nr;
917 int nfbposre_old = idef->il[F_FBPOSRES].nr;
918 for (int ftype = 0; ftype < F_NRE; ftype++)
920 if (mergeConstr &&
921 ftype == F_CONSTR && molt.ilist[F_CONSTRNC].size() > 0)
923 /* Merge all constrains into one ilist.
924 * This simplifies the constraint code.
926 for (int mol = 0; mol < molb.nmol; mol++)
928 ilistcat(ftype, &idef->il[F_CONSTR], molt.ilist[F_CONSTR],
929 1, destnr + mol*srcnr, srcnr);
930 ilistcat(ftype, &idef->il[F_CONSTR], molt.ilist[F_CONSTRNC],
931 1, destnr + mol*srcnr, srcnr);
934 else if (!(mergeConstr && ftype == F_CONSTRNC))
936 ilistcat(ftype, &idef->il[ftype], molt.ilist[ftype],
937 molb.nmol, destnr, srcnr);
940 if (idef->il[F_POSRES].nr > nposre_old)
942 /* Executing this line line stops gmxdump -sys working
943 * correctly. I'm not aware there's an elegant fix. */
944 set_posres_params(idef, &molb, nposre_old/2, natoms);
946 if (idef->il[F_FBPOSRES].nr > nfbposre_old)
948 set_fbposres_params(idef, &molb, nfbposre_old/2, natoms);
951 natoms += molb.nmol*srcnr;
954 if (mtop.bIntermolecularInteractions)
956 for (int ftype = 0; ftype < F_NRE; ftype++)
958 ilistcat(ftype, &idef->il[ftype], (*mtop.intermolecular_ilist)[ftype],
959 1, 0, mtop.natoms);
963 if (freeEnergyInteractionsAtEnd && gmx_mtop_bondeds_free_energy(&mtop))
965 std::vector<real> qA(mtop.natoms);
966 std::vector<real> qB(mtop.natoms);
967 gmx_mtop_atomloop_all_t aloop = gmx_mtop_atomloop_all_init(&mtop);
968 const t_atom *atom;
969 int ag = 0;
970 while (gmx_mtop_atomloop_all_next(aloop, &ag, &atom))
972 qA[ag] = atom->q;
973 qB[ag] = atom->qB;
975 gmx_sort_ilist_fe(idef, qA.data(), qB.data());
977 else
979 idef->ilsort = ilsortNO_FE;
983 /*! \brief Copy atomtypes from mtop
985 * Makes a deep copy of t_atomtypes from gmx_mtop_t.
986 * Used to initialize legacy topology types.
988 * \param[in] mtop Reference to input mtop.
989 * \param[in] atomtypes Pointer to atomtypes to populate.
991 static void copyAtomtypesFromMtop(const gmx_mtop_t &mtop,
992 t_atomtypes *atomtypes)
994 atomtypes->nr = mtop.atomtypes.nr;
995 if (mtop.atomtypes.atomnumber)
997 snew(atomtypes->atomnumber, mtop.atomtypes.nr);
998 std::copy(mtop.atomtypes.atomnumber, mtop.atomtypes.atomnumber + mtop.atomtypes.nr, atomtypes->atomnumber);
1000 else
1002 atomtypes->atomnumber = nullptr;
1006 /*! \brief Copy cgs from mtop.
1008 * Makes a deep copy of cgs(t_block) from gmx_mtop_t.
1009 * Used to initialize legacy topology types.
1011 * \param[in] mtop Reference to input mtop.
1012 * \param[in] cgs Pointer to final cgs data structure.
1014 static void copyCgsFromMtop(const gmx_mtop_t &mtop,
1015 t_block *cgs)
1017 init_block(cgs);
1018 for (const gmx_molblock_t &molb : mtop.molblock)
1020 const gmx_moltype_t &molt = mtop.moltype[molb.type];
1021 blockcat(cgs, &molt.cgs, molb.nmol);
1025 /*! \brief Copy excls from mtop.
1027 * Makes a deep copy of excls(t_blocka) from gmx_mtop_t.
1028 * Used to initialize legacy topology types.
1030 * \param[in] mtop Reference to input mtop.
1031 * \param[in] excls Pointer to final excls data structure.
1033 static void copyExclsFromMtop(const gmx_mtop_t &mtop,
1034 t_blocka *excls)
1036 init_blocka(excls);
1037 int natoms = 0;
1038 for (const gmx_molblock_t &molb : mtop.molblock)
1040 const gmx_moltype_t &molt = mtop.moltype[molb.type];
1042 int srcnr = molt.atoms.nr;
1043 int destnr = natoms;
1045 blockacat(excls, &molt.excls, molb.nmol, destnr, srcnr);
1047 natoms += molb.nmol*srcnr;
1051 /*! \brief Updates inter-molecular exclusion lists
1053 * This function updates inter-molecular exclusions to exclude all
1054 * non-bonded interactions between a given list of atoms
1056 * \param[inout] excls existing exclusions in local topology
1057 * \param[in] ids list of global IDs of atoms
1059 static void addMimicExclusions(t_blocka *excls,
1060 const gmx::ArrayRef<const int> ids)
1062 t_blocka inter_excl {};
1063 init_blocka(&inter_excl);
1064 size_t n_q = ids.size();
1066 inter_excl.nr = excls->nr;
1067 inter_excl.nra = n_q * n_q;
1069 size_t total_nra = n_q * n_q;
1071 snew(inter_excl.index, excls->nr + 1);
1072 snew(inter_excl.a, total_nra);
1074 for (int i = 0; i < excls->nr; ++i)
1076 inter_excl.index[i] = 0;
1079 /* Here we loop over the list of QM atom ids
1080 * and create exclusions between all of them resulting in
1081 * n_q * n_q sized exclusion list
1083 int prev_index = 0;
1084 for (int k = 0; k < inter_excl.nr; ++k)
1086 inter_excl.index[k] = prev_index;
1087 for (long i = 0; i < ids.size(); i++)
1089 if (k != ids[i])
1091 continue;
1093 size_t index = n_q * i;
1094 inter_excl.index[ids[i]] = index;
1095 prev_index = index + n_q;
1096 for (size_t j = 0; j < n_q; ++j)
1098 inter_excl.a[n_q * i + j] = ids[j];
1102 inter_excl.index[ids[n_q - 1] + 1] = n_q * n_q;
1104 inter_excl.index[inter_excl.nr] = n_q * n_q;
1106 gmx::ExclusionBlocks qmexcl2 {};
1107 initExclusionBlocks(&qmexcl2, excls->nr);
1108 gmx::blockaToExclusionBlocks(&inter_excl, &qmexcl2);
1110 // Merge the created exclusion list with the existing one
1111 gmx::mergeExclusions(excls, &qmexcl2);
1112 gmx::doneExclusionBlocks(&qmexcl2);
1115 static void gen_local_top(const gmx_mtop_t &mtop,
1116 bool freeEnergyInteractionsAtEnd,
1117 bool bMergeConstr,
1118 gmx_localtop_t *top)
1120 copyAtomtypesFromMtop(mtop, &top->atomtypes);
1121 copyIdefFromMtop(mtop, &top->idef, freeEnergyInteractionsAtEnd, bMergeConstr);
1122 copyCgsFromMtop(mtop, &top->cgs);
1123 copyExclsFromMtop(mtop, &top->excls);
1124 if (!mtop.intermolecularExclusionGroup.empty())
1126 addMimicExclusions(&top->excls,
1127 mtop.intermolecularExclusionGroup);
1131 gmx_localtop_t *
1132 gmx_mtop_generate_local_top(const gmx_mtop_t *mtop,
1133 bool freeEnergyInteractionsAtEnd)
1135 gmx_localtop_t *top;
1137 snew(top, 1);
1139 gen_local_top(*mtop, freeEnergyInteractionsAtEnd, true, top);
1141 return top;
1144 /*! \brief Fills an array with molecule begin/end atom indices
1146 * \param[in] mtop The global topology
1147 * \param[out] index Array of size nr. of molecules + 1 to be filled with molecule begin/end indices
1149 static void fillMoleculeIndices(const gmx_mtop_t &mtop,
1150 gmx::ArrayRef<int> index)
1152 int globalAtomIndex = 0;
1153 int globalMolIndex = 0;
1154 index[globalMolIndex] = globalAtomIndex;
1155 for (const gmx_molblock_t &molb : mtop.molblock)
1157 int numAtomsPerMolecule = mtop.moltype[molb.type].atoms.nr;
1158 for (int mol = 0; mol < molb.nmol; mol++)
1160 globalAtomIndex += numAtomsPerMolecule;
1161 globalMolIndex += 1;
1162 index[globalMolIndex] = globalAtomIndex;
1167 gmx::RangePartitioning gmx_mtop_molecules(const gmx_mtop_t &mtop)
1169 gmx::RangePartitioning mols;
1171 for (const gmx_molblock_t &molb : mtop.molblock)
1173 int numAtomsPerMolecule = mtop.moltype[molb.type].atoms.nr;
1174 for (int mol = 0; mol < molb.nmol; mol++)
1176 mols.appendBlock(numAtomsPerMolecule);
1180 return mols;
1183 /*! \brief Creates and returns a deprecated t_block struct with molecule indices
1185 * \param[in] mtop The global topology
1187 static t_block gmx_mtop_molecules_t_block(const gmx_mtop_t &mtop)
1189 t_block mols;
1191 mols.nr = gmx_mtop_num_molecules(mtop);
1192 mols.nalloc_index = mols.nr + 1;
1193 snew(mols.index, mols.nalloc_index);
1195 fillMoleculeIndices(mtop, gmx::arrayRefFromArray(mols.index, mols.nr + 1));
1197 return mols;
1200 static void gen_t_topology(const gmx_mtop_t &mtop,
1201 bool freeEnergyInteractionsAtEnd,
1202 bool bMergeConstr,
1203 t_topology *top)
1205 copyAtomtypesFromMtop(mtop, &top->atomtypes);
1206 copyIdefFromMtop(mtop, &top->idef, freeEnergyInteractionsAtEnd, bMergeConstr);
1207 copyCgsFromMtop(mtop, &top->cgs);
1208 copyExclsFromMtop(mtop, &top->excls);
1210 top->name = mtop.name;
1211 top->atoms = gmx_mtop_global_atoms(&mtop);
1212 top->mols = gmx_mtop_molecules_t_block(mtop);
1213 top->bIntermolecularInteractions = mtop.bIntermolecularInteractions;
1214 top->symtab = mtop.symtab;
1217 t_topology gmx_mtop_t_to_t_topology(gmx_mtop_t *mtop, bool freeMTop)
1219 t_topology top;
1221 gen_t_topology(*mtop, false, false, &top);
1223 if (freeMTop)
1225 // Clear pointers and counts, such that the pointers copied to top
1226 // keep pointing to valid data after destroying mtop.
1227 mtop->symtab.symbuf = nullptr;
1228 mtop->symtab.nr = 0;
1230 return top;
1233 std::vector<int> get_atom_index(const gmx_mtop_t *mtop)
1236 std::vector<int> atom_index;
1237 gmx_mtop_atomloop_block_t aloopb = gmx_mtop_atomloop_block_init(mtop);
1238 const t_atom *atom;
1239 int nmol, j = 0;
1240 while (gmx_mtop_atomloop_block_next(aloopb, &atom, &nmol))
1242 if (atom->ptype == eptAtom)
1244 atom_index.push_back(j);
1246 j++;
1248 return atom_index;
1251 void convertAtomsToMtop(t_symtab *symtab,
1252 char **name,
1253 t_atoms *atoms,
1254 gmx_mtop_t *mtop)
1256 mtop->symtab = *symtab;
1258 mtop->name = name;
1260 mtop->moltype.clear();
1261 mtop->moltype.resize(1);
1262 mtop->moltype.back().atoms = *atoms;
1264 mtop->molblock.resize(1);
1265 mtop->molblock[0].type = 0;
1266 mtop->molblock[0].nmol = 1;
1268 mtop->bIntermolecularInteractions = FALSE;
1270 mtop->natoms = atoms->nr;
1272 mtop->haveMoleculeIndices = false;
1274 gmx_mtop_finalize(mtop);