Convert gmx_cmap_t to C++
[alexxy/gromacs.git] / src / gromacs / topology / mtop_util.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
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.
8  *
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.
13  *
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.
18  *
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.
23  *
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.
31  *
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.
34  */
35 #include "gmxpre.h"
36
37 #include "mtop_util.h"
38
39 #include <climits>
40 #include <cstddef>
41 #include <cstdio>
42 #include <cstdlib>
43 #include <cstring>
44
45 #include "gromacs/math/vectypes.h"
46 #include "gromacs/topology/atoms.h"
47 #include "gromacs/topology/block.h"
48 #include "gromacs/topology/idef.h"
49 #include "gromacs/topology/ifunc.h"
50 #include "gromacs/topology/topology.h"
51 #include "gromacs/topology/topsort.h"
52 #include "gromacs/utility/arrayref.h"
53 #include "gromacs/utility/fatalerror.h"
54 #include "gromacs/utility/real.h"
55 #include "gromacs/utility/smalloc.h"
56
57 static int gmx_mtop_maxresnr(const gmx_mtop_t *mtop, int maxres_renum)
58 {
59     int maxresnr = 0;
60
61     for (const gmx_moltype_t &moltype : mtop->moltype)
62     {
63         const t_atoms &atoms = moltype.atoms;
64         if (atoms.nres > maxres_renum)
65         {
66             for (int r = 0; r < atoms.nres; r++)
67             {
68                 if (atoms.resinfo[r].nr > maxresnr)
69                 {
70                     maxresnr = atoms.resinfo[r].nr;
71                 }
72             }
73         }
74     }
75
76     return maxresnr;
77 }
78
79 static void buildMolblockIndices(gmx_mtop_t *mtop)
80 {
81     mtop->moleculeBlockIndices.resize(mtop->molblock.size());
82
83     int atomIndex          = 0;
84     int residueIndex       = 0;
85     int residueNumberStart = mtop->maxresnr + 1;
86     int moleculeIndexStart = 0;
87     for (size_t mb = 0; mb < mtop->molblock.size(); mb++)
88     {
89         const gmx_molblock_t &molb         = mtop->molblock[mb];
90         MoleculeBlockIndices &indices      = mtop->moleculeBlockIndices[mb];
91         const int             numResPerMol = mtop->moltype[molb.type].atoms.nres;
92
93         indices.numAtomsPerMolecule   = mtop->moltype[molb.type].atoms.nr;
94         indices.globalAtomStart       = atomIndex;
95         indices.globalResidueStart    = residueIndex;
96         atomIndex                    += molb.nmol*indices.numAtomsPerMolecule;
97         residueIndex                 += molb.nmol*numResPerMol;
98         indices.globalAtomEnd         = atomIndex;
99         indices.residueNumberStart    = residueNumberStart;
100         if (numResPerMol <= mtop->maxres_renum)
101         {
102             residueNumberStart       += molb.nmol*numResPerMol;
103         }
104         indices.moleculeIndexStart    = moleculeIndexStart;
105         moleculeIndexStart           += molb.nmol;
106     }
107 }
108
109 void gmx_mtop_finalize(gmx_mtop_t *mtop)
110 {
111     char *env;
112
113     if (mtop->molblock.size() == 1 && mtop->molblock[0].nmol == 1)
114     {
115         /* We have a single molecule only, no renumbering needed.
116          * This case also covers an mtop converted from pdb/gro/... input,
117          * so we retain the original residue numbering.
118          */
119         mtop->maxres_renum = 0;
120     }
121     else
122     {
123         /* We only renumber single residue molecules. Their intra-molecular
124          * residue numbering is anyhow irrelevant.
125          */
126         mtop->maxres_renum = 1;
127     }
128
129     env = getenv("GMX_MAXRESRENUM");
130     if (env != nullptr)
131     {
132         sscanf(env, "%d", &mtop->maxres_renum);
133     }
134     if (mtop->maxres_renum == -1)
135     {
136         /* -1 signals renumber residues in all molecules */
137         mtop->maxres_renum = INT_MAX;
138     }
139
140     mtop->maxresnr = gmx_mtop_maxresnr(mtop, mtop->maxres_renum);
141
142     buildMolblockIndices(mtop);
143 }
144
145 void gmx_mtop_count_atomtypes(const gmx_mtop_t *mtop, int state, int typecount[])
146 {
147     for (int i = 0; i < mtop->ffparams.atnr; ++i)
148     {
149         typecount[i] = 0;
150     }
151     for (const gmx_molblock_t &molb : mtop->molblock)
152     {
153         const t_atoms &atoms = mtop->moltype[molb.type].atoms;
154         for (int i = 0; i < atoms.nr; ++i)
155         {
156             int tpi;
157             if (state == 0)
158             {
159                 tpi = atoms.atom[i].type;
160             }
161             else
162             {
163                 tpi = atoms.atom[i].typeB;
164             }
165             typecount[tpi] += molb.nmol;
166         }
167     }
168 }
169
170 int ncg_mtop(const gmx_mtop_t *mtop)
171 {
172     int ncg = 0;
173     for (const gmx_molblock_t &molb : mtop->molblock)
174     {
175         ncg += molb.nmol*mtop->moltype[molb.type].cgs.nr;
176     }
177
178     return ncg;
179 }
180
181 int gmx_mtop_num_molecules(const gmx_mtop_t &mtop)
182 {
183     int numMolecules = 0;
184     for (const gmx_molblock_t &molb : mtop.molblock)
185     {
186         numMolecules += molb.nmol;
187     }
188     return numMolecules;
189 }
190
191 int gmx_mtop_nres(const gmx_mtop_t *mtop)
192 {
193     int nres = 0;
194     for (const gmx_molblock_t &molb : mtop->molblock)
195     {
196         nres += molb.nmol*mtop->moltype[molb.type].atoms.nres;
197     }
198     return nres;
199 }
200
201 void gmx_mtop_remove_chargegroups(gmx_mtop_t *mtop)
202 {
203     for (gmx_moltype_t &molt : mtop->moltype)
204     {
205         t_block &cgs = molt.cgs;
206         if (cgs.nr < molt.atoms.nr)
207         {
208             cgs.nr = molt.atoms.nr;
209             srenew(cgs.index, cgs.nr + 1);
210             for (int i = 0; i < cgs.nr + 1; i++)
211             {
212                 cgs.index[i] = i;
213             }
214         }
215     }
216 }
217
218 typedef struct gmx_mtop_atomloop_all
219 {
220     const gmx_mtop_t *mtop;
221     size_t            mblock;
222     const t_atoms    *atoms;
223     int               mol;
224     int               maxresnr;
225     int               at_local;
226     int               at_global;
227 } t_gmx_mtop_atomloop_all;
228
229 gmx_mtop_atomloop_all_t
230 gmx_mtop_atomloop_all_init(const gmx_mtop_t *mtop)
231 {
232     struct gmx_mtop_atomloop_all *aloop;
233
234     snew(aloop, 1);
235
236     aloop->mtop         = mtop;
237     aloop->mblock       = 0;
238     aloop->atoms        =
239         &mtop->moltype[mtop->molblock[aloop->mblock].type].atoms;
240     aloop->mol          = 0;
241     aloop->maxresnr     = mtop->maxresnr;
242     aloop->at_local     = -1;
243     aloop->at_global    = -1;
244
245     return aloop;
246 }
247
248 static void gmx_mtop_atomloop_all_destroy(gmx_mtop_atomloop_all_t aloop)
249 {
250     sfree(aloop);
251 }
252
253 gmx_bool gmx_mtop_atomloop_all_next(gmx_mtop_atomloop_all_t aloop,
254                                     int *at_global, const t_atom **atom)
255 {
256     if (aloop == nullptr)
257     {
258         gmx_incons("gmx_mtop_atomloop_all_next called without calling gmx_mtop_atomloop_all_init");
259     }
260
261     aloop->at_local++;
262     aloop->at_global++;
263
264     if (aloop->at_local >= aloop->atoms->nr)
265     {
266         if (aloop->atoms->nres <= aloop->mtop->maxres_renum)
267         {
268             /* Single residue molecule, increase the count with one */
269             aloop->maxresnr += aloop->atoms->nres;
270         }
271         aloop->mol++;
272         aloop->at_local = 0;
273         if (aloop->mol >= aloop->mtop->molblock[aloop->mblock].nmol)
274         {
275             aloop->mblock++;
276             if (aloop->mblock >= aloop->mtop->molblock.size())
277             {
278                 gmx_mtop_atomloop_all_destroy(aloop);
279                 return FALSE;
280             }
281             aloop->atoms = &aloop->mtop->moltype[aloop->mtop->molblock[aloop->mblock].type].atoms;
282             aloop->mol   = 0;
283         }
284     }
285
286     *at_global = aloop->at_global;
287     *atom      = &aloop->atoms->atom[aloop->at_local];
288
289     return TRUE;
290 }
291
292 void gmx_mtop_atomloop_all_names(gmx_mtop_atomloop_all_t aloop,
293                                  char **atomname, int *resnr, char **resname)
294 {
295     int resind_mol;
296
297     *atomname  = *(aloop->atoms->atomname[aloop->at_local]);
298     resind_mol = aloop->atoms->atom[aloop->at_local].resind;
299     *resnr     = aloop->atoms->resinfo[resind_mol].nr;
300     if (aloop->atoms->nres <= aloop->mtop->maxres_renum)
301     {
302         *resnr = aloop->maxresnr + 1 + resind_mol;
303     }
304     *resname  = *(aloop->atoms->resinfo[resind_mol].name);
305 }
306
307 void gmx_mtop_atomloop_all_moltype(gmx_mtop_atomloop_all_t   aloop,
308                                    const gmx_moltype_t     **moltype,
309                                    int                      *at_mol)
310 {
311     *moltype = &aloop->mtop->moltype[aloop->mtop->molblock[aloop->mblock].type];
312     *at_mol  = aloop->at_local;
313 }
314
315 typedef struct gmx_mtop_atomloop_block
316 {
317     const gmx_mtop_t *mtop;
318     size_t            mblock;
319     const t_atoms    *atoms;
320     int               at_local;
321 } t_gmx_mtop_atomloop_block;
322
323 gmx_mtop_atomloop_block_t
324 gmx_mtop_atomloop_block_init(const gmx_mtop_t *mtop)
325 {
326     struct gmx_mtop_atomloop_block *aloop;
327
328     snew(aloop, 1);
329
330     aloop->mtop      = mtop;
331     aloop->mblock    = 0;
332     aloop->atoms     = &mtop->moltype[mtop->molblock[aloop->mblock].type].atoms;
333     aloop->at_local  = -1;
334
335     return aloop;
336 }
337
338 static void gmx_mtop_atomloop_block_destroy(gmx_mtop_atomloop_block_t aloop)
339 {
340     sfree(aloop);
341 }
342
343 gmx_bool gmx_mtop_atomloop_block_next(gmx_mtop_atomloop_block_t aloop,
344                                       const t_atom **atom, int *nmol)
345 {
346     if (aloop == nullptr)
347     {
348         gmx_incons("gmx_mtop_atomloop_all_next called without calling gmx_mtop_atomloop_all_init");
349     }
350
351     aloop->at_local++;
352
353     if (aloop->at_local >= aloop->atoms->nr)
354     {
355         aloop->mblock++;
356         if (aloop->mblock >= aloop->mtop->molblock.size())
357         {
358             gmx_mtop_atomloop_block_destroy(aloop);
359             return FALSE;
360         }
361         aloop->atoms    = &aloop->mtop->moltype[aloop->mtop->molblock[aloop->mblock].type].atoms;
362         aloop->at_local = 0;
363     }
364
365     *atom = &aloop->atoms->atom[aloop->at_local];
366     *nmol = aloop->mtop->molblock[aloop->mblock].nmol;
367
368     return TRUE;
369 }
370
371 typedef struct gmx_mtop_ilistloop
372 {
373     const gmx_mtop_t *mtop;
374     int               mblock;
375 } t_gmx_mtop_ilist;
376
377 gmx_mtop_ilistloop_t
378 gmx_mtop_ilistloop_init(const gmx_mtop_t *mtop)
379 {
380     struct gmx_mtop_ilistloop *iloop;
381
382     snew(iloop, 1);
383
384     iloop->mtop      = mtop;
385     iloop->mblock    = -1;
386
387     return iloop;
388 }
389
390 gmx_mtop_ilistloop_t
391 gmx_mtop_ilistloop_init(const gmx_mtop_t &mtop)
392 {
393     return gmx_mtop_ilistloop_init(&mtop);
394 }
395
396 static void gmx_mtop_ilistloop_destroy(gmx_mtop_ilistloop_t iloop)
397 {
398     sfree(iloop);
399 }
400
401 const InteractionLists *
402 gmx_mtop_ilistloop_next(gmx_mtop_ilistloop_t    iloop,
403                         int                    *nmol)
404 {
405     if (iloop == nullptr)
406     {
407         gmx_incons("gmx_mtop_ilistloop_next called without calling gmx_mtop_ilistloop_init");
408     }
409
410     iloop->mblock++;
411     if (iloop->mblock >= static_cast<int>(iloop->mtop->molblock.size()))
412     {
413         if (iloop->mblock == static_cast<int>(iloop->mtop->molblock.size()) &&
414             iloop->mtop->bIntermolecularInteractions)
415         {
416             *nmol      = 1;
417             return iloop->mtop->intermolecular_ilist.get();
418         }
419
420         gmx_mtop_ilistloop_destroy(iloop);
421         return nullptr;
422     }
423
424     *nmol = iloop->mtop->molblock[iloop->mblock].nmol;
425
426     return
427         &iloop->mtop->moltype[iloop->mtop->molblock[iloop->mblock].type].ilist;
428 }
429 typedef struct gmx_mtop_ilistloop_all
430 {
431     const gmx_mtop_t *mtop;
432     size_t            mblock;
433     int               mol;
434     int               a_offset;
435 } t_gmx_mtop_ilist_all;
436
437 gmx_mtop_ilistloop_all_t
438 gmx_mtop_ilistloop_all_init(const gmx_mtop_t *mtop)
439 {
440     struct gmx_mtop_ilistloop_all *iloop;
441
442     snew(iloop, 1);
443
444     iloop->mtop      = mtop;
445     iloop->mblock    = 0;
446     iloop->mol       = -1;
447     iloop->a_offset  = 0;
448
449     return iloop;
450 }
451
452 static void gmx_mtop_ilistloop_all_destroy(gmx_mtop_ilistloop_all_t iloop)
453 {
454     sfree(iloop);
455 }
456
457 const InteractionLists *
458 gmx_mtop_ilistloop_all_next(gmx_mtop_ilistloop_all_t   iloop,
459                             int                       *atnr_offset)
460 {
461
462     if (iloop == nullptr)
463     {
464         gmx_incons("gmx_mtop_ilistloop_all_next called without calling gmx_mtop_ilistloop_all_init");
465     }
466
467     if (iloop->mol >= 0)
468     {
469         iloop->a_offset += iloop->mtop->moleculeBlockIndices[iloop->mblock].numAtomsPerMolecule;
470     }
471
472     iloop->mol++;
473
474     /* Inter-molecular interactions, if present, are indexed with
475      * iloop->mblock == iloop->mtop->nmolblock, thus we should separately
476      * check for this value in this conditional.
477      */
478     if (iloop->mblock == iloop->mtop->molblock.size() ||
479         iloop->mol >= iloop->mtop->molblock[iloop->mblock].nmol)
480     {
481         iloop->mblock++;
482         iloop->mol = 0;
483         if (iloop->mblock >= iloop->mtop->molblock.size())
484         {
485             if (iloop->mblock == iloop->mtop->molblock.size() &&
486                 iloop->mtop->bIntermolecularInteractions)
487             {
488                 *atnr_offset = 0;
489                 return iloop->mtop->intermolecular_ilist.get();
490             }
491
492             gmx_mtop_ilistloop_all_destroy(iloop);
493             return nullptr;
494         }
495     }
496
497     *atnr_offset = iloop->a_offset;
498
499     return
500         &iloop->mtop->moltype[iloop->mtop->molblock[iloop->mblock].type].ilist;
501 }
502
503 int gmx_mtop_ftype_count(const gmx_mtop_t *mtop, int ftype)
504 {
505     gmx_mtop_ilistloop_t   iloop;
506     int                    n, nmol;
507
508     n = 0;
509
510     iloop = gmx_mtop_ilistloop_init(mtop);
511     while (const InteractionLists *il = gmx_mtop_ilistloop_next(iloop, &nmol))
512     {
513         n += nmol*(*il)[ftype].size()/(1+NRAL(ftype));
514     }
515
516     if (mtop->bIntermolecularInteractions)
517     {
518         n += (*mtop->intermolecular_ilist)[ftype].size()/(1+NRAL(ftype));
519     }
520
521     return n;
522 }
523
524 int gmx_mtop_ftype_count(const gmx_mtop_t &mtop, int ftype)
525 {
526     return gmx_mtop_ftype_count(&mtop, ftype);
527 }
528
529 t_block gmx_mtop_global_cgs(const gmx_mtop_t *mtop)
530 {
531     t_block cgs_gl;
532     /* In most cases this is too much, but we realloc at the end */
533     snew(cgs_gl.index, mtop->natoms+1);
534
535     cgs_gl.nr       = 0;
536     cgs_gl.index[0] = 0;
537     for (const gmx_molblock_t &molb : mtop->molblock)
538     {
539         const t_block &cgs_mol = mtop->moltype[molb.type].cgs;
540         for (int mol = 0; mol < molb.nmol; mol++)
541         {
542             for (int cg = 0; cg < cgs_mol.nr; cg++)
543             {
544                 cgs_gl.index[cgs_gl.nr + 1] =
545                     cgs_gl.index[cgs_gl.nr] +
546                     cgs_mol.index[cg + 1] - cgs_mol.index[cg];
547                 cgs_gl.nr++;
548             }
549         }
550     }
551     cgs_gl.nalloc_index = cgs_gl.nr + 1;
552     srenew(cgs_gl.index, cgs_gl.nalloc_index);
553
554     return cgs_gl;
555 }
556
557 static void atomcat(t_atoms *dest, const t_atoms *src, int copies,
558                     int maxres_renum, int *maxresnr)
559 {
560     int i, j, l, size;
561     int srcnr  = src->nr;
562     int destnr = dest->nr;
563
564     if (dest->nr == 0)
565     {
566         dest->haveMass    = src->haveMass;
567         dest->haveType    = src->haveType;
568         dest->haveCharge  = src->haveCharge;
569         dest->haveBState  = src->haveBState;
570         dest->havePdbInfo = src->havePdbInfo;
571     }
572     else
573     {
574         dest->haveMass    = dest->haveMass    && src->haveMass;
575         dest->haveType    = dest->haveType    && src->haveType;
576         dest->haveCharge  = dest->haveCharge  && src->haveCharge;
577         dest->haveBState  = dest->haveBState  && src->haveBState;
578         dest->havePdbInfo = dest->havePdbInfo && src->havePdbInfo;
579     }
580
581     if (srcnr)
582     {
583         size = destnr+copies*srcnr;
584         srenew(dest->atom, size);
585         srenew(dest->atomname, size);
586         if (dest->haveType)
587         {
588             srenew(dest->atomtype, size);
589             if (dest->haveBState)
590             {
591                 srenew(dest->atomtypeB, size);
592             }
593         }
594         if (dest->havePdbInfo)
595         {
596             srenew(dest->pdbinfo, size);
597         }
598     }
599     if (src->nres)
600     {
601         size = dest->nres+copies*src->nres;
602         srenew(dest->resinfo, size);
603     }
604
605     /* residue information */
606     for (l = dest->nres, j = 0; (j < copies); j++, l += src->nres)
607     {
608         memcpy(reinterpret_cast<char *>(&(dest->resinfo[l])), reinterpret_cast<char *>(&(src->resinfo[0])),
609                static_cast<size_t>(src->nres*sizeof(src->resinfo[0])));
610     }
611
612     for (l = destnr, j = 0; (j < copies); j++, l += srcnr)
613     {
614         memcpy(reinterpret_cast<char *>(&(dest->atom[l])), reinterpret_cast<char *>(&(src->atom[0])),
615                static_cast<size_t>(srcnr*sizeof(src->atom[0])));
616         memcpy(reinterpret_cast<char *>(&(dest->atomname[l])), reinterpret_cast<char *>(&(src->atomname[0])),
617                static_cast<size_t>(srcnr*sizeof(src->atomname[0])));
618         if (dest->haveType)
619         {
620             memcpy(reinterpret_cast<char *>(&(dest->atomtype[l])), reinterpret_cast<char *>(&(src->atomtype[0])),
621                    static_cast<size_t>(srcnr*sizeof(src->atomtype[0])));
622             if (dest->haveBState)
623             {
624                 memcpy(reinterpret_cast<char *>(&(dest->atomtypeB[l])), reinterpret_cast<char *>(&(src->atomtypeB[0])),
625                        static_cast<size_t>(srcnr*sizeof(src->atomtypeB[0])));
626             }
627         }
628         if (dest->havePdbInfo)
629         {
630             memcpy(reinterpret_cast<char *>(&(dest->pdbinfo[l])), reinterpret_cast<char *>(&(src->pdbinfo[0])),
631                    static_cast<size_t>(srcnr*sizeof(src->pdbinfo[0])));
632         }
633     }
634
635     /* Increment residue indices */
636     for (l = destnr, j = 0; (j < copies); j++)
637     {
638         for (i = 0; (i < srcnr); i++, l++)
639         {
640             dest->atom[l].resind = dest->nres+j*src->nres+src->atom[i].resind;
641         }
642     }
643
644     if (src->nres <= maxres_renum)
645     {
646         /* Single residue molecule, continue counting residues */
647         for (j = 0; (j < copies); j++)
648         {
649             for (l = 0; l < src->nres; l++)
650             {
651                 (*maxresnr)++;
652                 dest->resinfo[dest->nres+j*src->nres+l].nr = *maxresnr;
653             }
654         }
655     }
656
657     dest->nres += copies*src->nres;
658     dest->nr   += copies*src->nr;
659 }
660
661 t_atoms gmx_mtop_global_atoms(const gmx_mtop_t *mtop)
662 {
663     t_atoms         atoms;
664
665     init_t_atoms(&atoms, 0, FALSE);
666
667     int maxresnr = mtop->maxresnr;
668     for (const gmx_molblock_t &molb : mtop->molblock)
669     {
670         atomcat(&atoms, &mtop->moltype[molb.type].atoms, molb.nmol,
671                 mtop->maxres_renum, &maxresnr);
672     }
673
674     return atoms;
675 }
676
677 /*
678  * The cat routines below are old code from src/kernel/topcat.c
679  */
680
681 static void blockcat(t_block *dest, const t_block *src, int copies)
682 {
683     int i, j, l, nra, size;
684
685     if (src->nr)
686     {
687         size = (dest->nr+copies*src->nr+1);
688         srenew(dest->index, size);
689     }
690
691     nra = dest->index[dest->nr];
692     for (l = dest->nr, j = 0; (j < copies); j++)
693     {
694         for (i = 0; (i < src->nr); i++)
695         {
696             dest->index[l++] = nra + src->index[i];
697         }
698         if (src->nr > 0)
699         {
700             nra += src->index[src->nr];
701         }
702     }
703     dest->nr             += copies*src->nr;
704     dest->index[dest->nr] = nra;
705 }
706
707 static void blockacat(t_blocka *dest, const t_blocka *src, int copies,
708                       int dnum, int snum)
709 {
710     int i, j, l, size;
711     int destnr  = dest->nr;
712     int destnra = dest->nra;
713
714     if (src->nr)
715     {
716         size = (dest->nr+copies*src->nr+1);
717         srenew(dest->index, size);
718     }
719     if (src->nra)
720     {
721         size = (dest->nra+copies*src->nra);
722         srenew(dest->a, size);
723     }
724
725     for (l = destnr, j = 0; (j < copies); j++)
726     {
727         for (i = 0; (i < src->nr); i++)
728         {
729             dest->index[l++] = dest->nra+src->index[i];
730         }
731         dest->nra += src->nra;
732     }
733     for (l = destnra, j = 0; (j < copies); j++)
734     {
735         for (i = 0; (i < src->nra); i++)
736         {
737             dest->a[l++] = dnum+src->a[i];
738         }
739         dnum     += snum;
740         dest->nr += src->nr;
741     }
742     dest->index[dest->nr] = dest->nra;
743 }
744
745 static void ilistcat(int                    ftype,
746                      t_ilist               *dest,
747                      const InteractionList &src,
748                      int                    copies,
749                      int                    dnum,
750                      int                    snum)
751 {
752     int nral, c, i, a;
753
754     nral = NRAL(ftype);
755
756     dest->nalloc = dest->nr + copies*src.size();
757     srenew(dest->iatoms, dest->nalloc);
758
759     for (c = 0; c < copies; c++)
760     {
761         for (i = 0; i < src.size(); )
762         {
763             dest->iatoms[dest->nr++] = src.iatoms[i++];
764             for (a = 0; a < nral; a++)
765             {
766                 dest->iatoms[dest->nr++] = dnum + src.iatoms[i++];
767             }
768         }
769         dnum += snum;
770     }
771 }
772
773 static void set_posres_params(t_idef *idef, const gmx_molblock_t *molb,
774                               int i0, int a_offset)
775 {
776     t_ilist   *il;
777     int        i1, i, a_molb;
778     t_iparams *ip;
779
780     il = &idef->il[F_POSRES];
781     i1 = il->nr/2;
782     idef->iparams_posres_nalloc = i1;
783     srenew(idef->iparams_posres, idef->iparams_posres_nalloc);
784     for (i = i0; i < i1; i++)
785     {
786         ip = &idef->iparams_posres[i];
787         /* Copy the force constants */
788         *ip    = idef->iparams[il->iatoms[i*2]];
789         a_molb = il->iatoms[i*2+1] - a_offset;
790         if (molb->posres_xA.empty())
791         {
792             gmx_incons("Position restraint coordinates are missing");
793         }
794         ip->posres.pos0A[XX] = molb->posres_xA[a_molb][XX];
795         ip->posres.pos0A[YY] = molb->posres_xA[a_molb][YY];
796         ip->posres.pos0A[ZZ] = molb->posres_xA[a_molb][ZZ];
797         if (!molb->posres_xB.empty())
798         {
799             ip->posres.pos0B[XX] = molb->posres_xB[a_molb][XX];
800             ip->posres.pos0B[YY] = molb->posres_xB[a_molb][YY];
801             ip->posres.pos0B[ZZ] = molb->posres_xB[a_molb][ZZ];
802         }
803         else
804         {
805             ip->posres.pos0B[XX] = ip->posres.pos0A[XX];
806             ip->posres.pos0B[YY] = ip->posres.pos0A[YY];
807             ip->posres.pos0B[ZZ] = ip->posres.pos0A[ZZ];
808         }
809         /* Set the parameter index for idef->iparams_posre */
810         il->iatoms[i*2] = i;
811     }
812 }
813
814 static void set_fbposres_params(t_idef *idef, const gmx_molblock_t *molb,
815                                 int i0, int a_offset)
816 {
817     t_ilist   *il;
818     int        i1, i, a_molb;
819     t_iparams *ip;
820
821     il = &idef->il[F_FBPOSRES];
822     i1 = il->nr/2;
823     idef->iparams_fbposres_nalloc = i1;
824     srenew(idef->iparams_fbposres, idef->iparams_fbposres_nalloc);
825     for (i = i0; i < i1; i++)
826     {
827         ip = &idef->iparams_fbposres[i];
828         /* Copy the force constants */
829         *ip    = idef->iparams[il->iatoms[i*2]];
830         a_molb = il->iatoms[i*2+1] - a_offset;
831         if (molb->posres_xA.empty())
832         {
833             gmx_incons("Position restraint coordinates are missing");
834         }
835         /* Take flat-bottom posres reference from normal position restraints */
836         ip->fbposres.pos0[XX] = molb->posres_xA[a_molb][XX];
837         ip->fbposres.pos0[YY] = molb->posres_xA[a_molb][YY];
838         ip->fbposres.pos0[ZZ] = molb->posres_xA[a_molb][ZZ];
839         /* Note: no B-type for flat-bottom posres */
840
841         /* Set the parameter index for idef->iparams_posre */
842         il->iatoms[i*2] = i;
843     }
844 }
845
846 static void gen_local_top(const gmx_mtop_t *mtop,
847                           bool              freeEnergyInteractionsAtEnd,
848                           bool              bMergeConstr,
849                           gmx_localtop_t   *top)
850 {
851     int                     srcnr, destnr, ftype, natoms, nposre_old, nfbposre_old;
852     const gmx_ffparams_t   *ffp;
853     t_idef                 *idef;
854     real                   *qA, *qB;
855     gmx_mtop_atomloop_all_t aloop;
856     int                     ag;
857
858     /* no copying of pointers possible now */
859
860     top->atomtypes.nr = mtop->atomtypes.nr;
861     if (mtop->atomtypes.atomnumber)
862     {
863         snew(top->atomtypes.atomnumber, top->atomtypes.nr);
864         std::copy(mtop->atomtypes.atomnumber, mtop->atomtypes.atomnumber + top->atomtypes.nr, top->atomtypes.atomnumber);
865     }
866     else
867     {
868         top->atomtypes.atomnumber = nullptr;
869     }
870
871     ffp = &mtop->ffparams;
872
873     idef                          = &top->idef;
874     idef->ntypes                  = ffp->numTypes();
875     idef->atnr                    = ffp->atnr;
876     /* we can no longer copy the pointers to the mtop members,
877      * because they will become invalid as soon as mtop gets free'd.
878      * We also need to make sure to only operate on valid data!
879      */
880
881     if (!ffp->functype.empty())
882     {
883         snew(idef->functype, ffp->functype.size());
884         std::copy(ffp->functype.data(), ffp->functype.data() + ffp->functype.size(), idef->functype);
885     }
886     else
887     {
888         idef->functype = nullptr;
889     }
890     if (!ffp->iparams.empty())
891     {
892         snew(idef->iparams, ffp->iparams.size());
893         std::copy(ffp->iparams.data(), ffp->iparams.data() + ffp->iparams.size(), idef->iparams);
894     }
895     else
896     {
897         idef->iparams = nullptr;
898     }
899     idef->iparams_posres          = nullptr;
900     idef->iparams_posres_nalloc   = 0;
901     idef->iparams_fbposres        = nullptr;
902     idef->iparams_fbposres_nalloc = 0;
903     idef->fudgeQQ                 = ffp->fudgeQQ;
904     idef->cmap_grid               = new gmx_cmap_t;
905     *idef->cmap_grid              = ffp->cmap_grid;
906     idef->ilsort                  = ilsortUNKNOWN;
907
908     init_block(&top->cgs);
909     init_blocka(&top->excls);
910     for (ftype = 0; ftype < F_NRE; ftype++)
911     {
912         idef->il[ftype].nr     = 0;
913         idef->il[ftype].nalloc = 0;
914         idef->il[ftype].iatoms = nullptr;
915     }
916
917     natoms = 0;
918     for (const gmx_molblock_t &molb : mtop->molblock)
919     {
920         const gmx_moltype_t &molt = mtop->moltype[molb.type];
921
922         srcnr  = molt.atoms.nr;
923         destnr = natoms;
924
925         blockcat(&top->cgs, &molt.cgs, molb.nmol);
926
927         blockacat(&top->excls, &molt.excls, molb.nmol, destnr, srcnr);
928
929         nposre_old   = idef->il[F_POSRES].nr;
930         nfbposre_old = idef->il[F_FBPOSRES].nr;
931         for (ftype = 0; ftype < F_NRE; ftype++)
932         {
933             if (bMergeConstr &&
934                 ftype == F_CONSTR && molt.ilist[F_CONSTRNC].size() > 0)
935             {
936                 /* Merge all constrains into one ilist.
937                  * This simplifies the constraint code.
938                  */
939                 for (int mol = 0; mol < molb.nmol; mol++)
940                 {
941                     ilistcat(ftype, &idef->il[F_CONSTR], molt.ilist[F_CONSTR],
942                              1, destnr + mol*srcnr, srcnr);
943                     ilistcat(ftype, &idef->il[F_CONSTR], molt.ilist[F_CONSTRNC],
944                              1, destnr + mol*srcnr, srcnr);
945                 }
946             }
947             else if (!(bMergeConstr && ftype == F_CONSTRNC))
948             {
949                 ilistcat(ftype, &idef->il[ftype], molt.ilist[ftype],
950                          molb.nmol, destnr, srcnr);
951             }
952         }
953         if (idef->il[F_POSRES].nr > nposre_old)
954         {
955             /* Executing this line line stops gmxdump -sys working
956              * correctly. I'm not aware there's an elegant fix. */
957             set_posres_params(idef, &molb, nposre_old/2, natoms);
958         }
959         if (idef->il[F_FBPOSRES].nr > nfbposre_old)
960         {
961             set_fbposres_params(idef, &molb, nfbposre_old/2, natoms);
962         }
963
964         natoms += molb.nmol*srcnr;
965     }
966
967     if (mtop->bIntermolecularInteractions)
968     {
969         for (ftype = 0; ftype < F_NRE; ftype++)
970         {
971             ilistcat(ftype, &idef->il[ftype], (*mtop->intermolecular_ilist)[ftype],
972                      1, 0, mtop->natoms);
973         }
974     }
975
976     if (freeEnergyInteractionsAtEnd && gmx_mtop_bondeds_free_energy(mtop))
977     {
978         snew(qA, mtop->natoms);
979         snew(qB, mtop->natoms);
980         aloop = gmx_mtop_atomloop_all_init(mtop);
981         const t_atom *atom;
982         while (gmx_mtop_atomloop_all_next(aloop, &ag, &atom))
983         {
984             qA[ag] = atom->q;
985             qB[ag] = atom->qB;
986         }
987         gmx_sort_ilist_fe(&top->idef, qA, qB);
988         sfree(qA);
989         sfree(qB);
990     }
991     else
992     {
993         top->idef.ilsort = ilsortNO_FE;
994     }
995 }
996
997 gmx_localtop_t *
998 gmx_mtop_generate_local_top(const gmx_mtop_t *mtop,
999                             bool              freeEnergyInteractionsAtEnd)
1000 {
1001     gmx_localtop_t *top;
1002
1003     snew(top, 1);
1004
1005     gen_local_top(mtop, freeEnergyInteractionsAtEnd, true, top);
1006
1007     return top;
1008 }
1009
1010 /*! \brief Fills an array with molecule begin/end atom indices
1011  *
1012  * \param[in]  mtop   The global topology
1013  * \param[out] index  Array of size nr. of molecules + 1 to be filled with molecule begin/end indices
1014  */
1015 static void fillMoleculeIndices(const gmx_mtop_t  &mtop,
1016                                 gmx::ArrayRef<int> index)
1017 {
1018     int globalAtomIndex   = 0;
1019     int globalMolIndex    = 0;
1020     index[globalMolIndex] = globalAtomIndex;
1021     for (const gmx_molblock_t &molb : mtop.molblock)
1022     {
1023         int numAtomsPerMolecule = mtop.moltype[molb.type].atoms.nr;
1024         for (int mol = 0; mol < molb.nmol; mol++)
1025         {
1026             globalAtomIndex       += numAtomsPerMolecule;
1027             globalMolIndex        += 1;
1028             index[globalMolIndex]  = globalAtomIndex;
1029         }
1030     }
1031 }
1032
1033 gmx::RangePartitioning gmx_mtop_molecules(const gmx_mtop_t &mtop)
1034 {
1035     gmx::RangePartitioning mols;
1036
1037     for (const gmx_molblock_t &molb : mtop.molblock)
1038     {
1039         int numAtomsPerMolecule = mtop.moltype[molb.type].atoms.nr;
1040         for (int mol = 0; mol < molb.nmol; mol++)
1041         {
1042             mols.appendBlock(numAtomsPerMolecule);
1043         }
1044     }
1045
1046     return mols;
1047 }
1048
1049 /*! \brief Creates and returns a deprecated t_block struct with molecule indices
1050  *
1051  * \param[in] mtop  The global topology
1052  */
1053 static t_block gmx_mtop_molecules_t_block(const gmx_mtop_t &mtop)
1054 {
1055     t_block mols;
1056
1057     mols.nr           = gmx_mtop_num_molecules(mtop);
1058     mols.nalloc_index = mols.nr + 1;
1059     snew(mols.index, mols.nalloc_index);
1060
1061     fillMoleculeIndices(mtop, gmx::arrayRefFromArray(mols.index, mols.nr + 1));
1062
1063     return mols;
1064 }
1065
1066 t_topology gmx_mtop_t_to_t_topology(gmx_mtop_t *mtop, bool freeMTop)
1067 {
1068     gmx_localtop_t ltop;
1069     t_topology     top;
1070
1071     gen_local_top(mtop, false, FALSE, &ltop);
1072     ltop.idef.ilsort = ilsortUNKNOWN;
1073
1074     top.name                        = mtop->name;
1075     top.idef                        = ltop.idef;
1076     top.atomtypes                   = ltop.atomtypes;
1077     top.cgs                         = ltop.cgs;
1078     top.excls                       = ltop.excls;
1079     top.atoms                       = gmx_mtop_global_atoms(mtop);
1080     top.mols                        = gmx_mtop_molecules_t_block(*mtop);
1081     top.bIntermolecularInteractions = mtop->bIntermolecularInteractions;
1082     top.symtab                      = mtop->symtab;
1083
1084     if (freeMTop)
1085     {
1086         // Clear pointers and counts, such that the pointers copied to top
1087         // keep pointing to valid data after destroying mtop.
1088         mtop->symtab.symbuf     = nullptr;
1089         mtop->symtab.nr         = 0;
1090     }
1091
1092     return top;
1093 }
1094
1095 std::vector<size_t> get_atom_index(const gmx_mtop_t *mtop)
1096 {
1097
1098     std::vector<size_t>       atom_index;
1099     gmx_mtop_atomloop_block_t aloopb = gmx_mtop_atomloop_block_init(mtop);
1100     const t_atom             *atom;
1101     int                       nmol, j = 0;
1102     while (gmx_mtop_atomloop_block_next(aloopb, &atom, &nmol))
1103     {
1104         if (atom->ptype == eptAtom)
1105         {
1106             atom_index.push_back(j);
1107         }
1108         j++;
1109     }
1110     return atom_index;
1111 }
1112
1113 void convertAtomsToMtop(t_symtab    *symtab,
1114                         char       **name,
1115                         t_atoms     *atoms,
1116                         gmx_mtop_t  *mtop)
1117 {
1118     mtop->symtab                 = *symtab;
1119
1120     mtop->name                   = name;
1121
1122     mtop->moltype.clear();
1123     mtop->moltype.resize(1);
1124     mtop->moltype.back().atoms   = *atoms;
1125
1126     mtop->molblock.resize(1);
1127     mtop->molblock[0].type       = 0;
1128     mtop->molblock[0].nmol       = 1;
1129
1130     mtop->bIntermolecularInteractions = FALSE;
1131
1132     mtop->natoms                 = atoms->nr;
1133
1134     mtop->haveMoleculeIndices    = false;
1135
1136     gmx_mtop_finalize(mtop);
1137 }