clang-tidy modernize
[alexxy/gromacs.git] / src / gromacs / domdec / domdec_topology.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2006,2007,2008,2009,2010,2011,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
36 /*! \internal \file
37  *
38  * \brief This file defines functions used by the domdec module
39  * while managing the construction, use and error checking for
40  * topologies local to a DD rank.
41  *
42  * \author Berk Hess <hess@kth.se>
43  * \ingroup module_domdec
44  */
45
46 #include "gmxpre.h"
47
48 #include <cassert>
49 #include <cstdlib>
50 #include <cstring>
51
52 #include <algorithm>
53 #include <string>
54
55 #include "gromacs/domdec/domdec.h"
56 #include "gromacs/domdec/domdec_network.h"
57 #include "gromacs/domdec/ga2la.h"
58 #include "gromacs/gmxlib/chargegroup.h"
59 #include "gromacs/gmxlib/network.h"
60 #include "gromacs/math/vec.h"
61 #include "gromacs/mdlib/forcerec.h"
62 #include "gromacs/mdlib/gmx_omp_nthreads.h"
63 #include "gromacs/mdlib/vsite.h"
64 #include "gromacs/mdtypes/commrec.h"
65 #include "gromacs/mdtypes/inputrec.h"
66 #include "gromacs/mdtypes/md_enums.h"
67 #include "gromacs/mdtypes/mdatom.h"
68 #include "gromacs/mdtypes/state.h"
69 #include "gromacs/pbcutil/mshift.h"
70 #include "gromacs/pbcutil/pbc.h"
71 #include "gromacs/topology/ifunc.h"
72 #include "gromacs/topology/mtop_util.h"
73 #include "gromacs/topology/topsort.h"
74 #include "gromacs/utility/cstringutil.h"
75 #include "gromacs/utility/exceptions.h"
76 #include "gromacs/utility/fatalerror.h"
77 #include "gromacs/utility/gmxassert.h"
78 #include "gromacs/utility/smalloc.h"
79 #include "gromacs/utility/strconvert.h"
80 #include "gromacs/utility/stringutil.h"
81
82 #include "domdec_constraints.h"
83 #include "domdec_internal.h"
84 #include "domdec_vsite.h"
85
86 /*! \brief The number of integer item in the local state, used for broadcasting of the state */
87 #define NITEM_DD_INIT_LOCAL_STATE 5
88
89 struct reverse_ilist_t
90 {
91     int  *index;              /* Index for each atom into il          */
92     int  *il;                 /* ftype|type|a0|...|an|ftype|...       */
93     int   numAtomsInMolecule; /* The number of atoms in this molecule */
94 };
95
96 typedef struct {
97     int  a_start;
98     int  a_end;
99     int  natoms_mol;
100     int  type;
101 } molblock_ind_t;
102
103 /*! \brief Struct for thread local work data for local topology generation */
104 typedef struct {
105     t_idef     idef;             /**< Partial local topology */
106     int      **vsite_pbc;        /**< vsite PBC structure */
107     int       *vsite_pbc_nalloc; /**< Allocation sizes for vsite_pbc */
108     int        nbonded;          /**< The number of bondeds in this struct */
109     t_blocka   excl;             /**< List of exclusions */
110     int        excl_count;       /**< The total exclusion count for \p excl */
111 } thread_work_t;
112
113 /*! \brief Struct for the reverse topology: links bonded interactions to atomsx */
114 struct gmx_reverse_top_t
115 {
116     //! @cond Doxygen_Suppress
117     gmx_bool         bExclRequired;               /**< Do we require all exclusions to be assigned? */
118     int              n_excl_at_max;               /**< The maximum number of exclusions one atom can have */
119     gmx_bool         bConstr;                     /**< Are there constraints in this revserse top?  */
120     gmx_bool         bSettle;                     /**< Are there settles in this revserse top?  */
121     gmx_bool         bBCheck;                     /**< All bonded interactions have to be assigned? */
122     gmx_bool         bInterCGInteractions;        /**< Are there bondeds/exclusions between charge-groups? */
123     reverse_ilist_t *ril_mt;                      /**< Reverse ilist for all moltypes      */
124     int              ril_mt_tot_size;             /**< The size of ril_mt[?].index summed over all entries */
125     int              ilsort;                      /**< The sorting state of bondeds for free energy */
126     molblock_ind_t  *mbi;                         /**< molblock to global atom index for quick lookup of molblocks on atom index */
127     int              nmolblock;                   /**< The number of molblocks, size of \p mbi */
128
129     gmx_bool         bIntermolecularInteractions; /**< Do we have intermolecular interactions? */
130     reverse_ilist_t  ril_intermol;                /**< Intermolecular reverse ilist */
131
132     /* Work data structures for multi-threading */
133     int            nthread;           /**< The number of threads to be used */
134     thread_work_t *th_work;           /**< Thread work array for local topology generation */
135     //! @endcond
136 };
137
138 /*! \brief Returns the number of atom entries for il in gmx_reverse_top_t */
139 static int nral_rt(int ftype)
140 {
141     int nral;
142
143     nral = NRAL(ftype);
144     if (interaction_function[ftype].flags & IF_VSITE)
145     {
146         /* With vsites the reverse topology contains
147          * two extra entries for PBC.
148          */
149         nral += 2;
150     }
151
152     return nral;
153 }
154
155 /*! \brief Return whether interactions of type \p ftype need to be assigned exactly once */
156 static gmx_bool dd_check_ftype(int ftype, gmx_bool bBCheck,
157                                gmx_bool bConstr, gmx_bool bSettle)
158 {
159     return (((interaction_function[ftype].flags & IF_BOND) &&
160              !(interaction_function[ftype].flags & IF_VSITE) &&
161              (bBCheck || !(interaction_function[ftype].flags & IF_LIMZERO))) ||
162             (bConstr && (ftype == F_CONSTR || ftype == F_CONSTRNC)) ||
163             (bSettle && ftype == F_SETTLE));
164 }
165
166 /*! \brief Print a header on error messages */
167 static void print_error_header(FILE *fplog, const char *moltypename, int nprint)
168 {
169     fprintf(fplog, "\nMolecule type '%s'\n", moltypename);
170     fprintf(stderr, "\nMolecule type '%s'\n", moltypename);
171     fprintf(fplog,
172             "the first %d missing interactions, except for exclusions:\n",
173             nprint);
174     fprintf(stderr,
175             "the first %d missing interactions, except for exclusions:\n",
176             nprint);
177 }
178
179 /*! \brief Help print error output when interactions are missing */
180 static void print_missing_interactions_mb(FILE *fplog, t_commrec *cr,
181                                           const gmx_reverse_top_t *rt,
182                                           const char *moltypename,
183                                           const reverse_ilist_t *ril,
184                                           int a_start, int a_end,
185                                           int nat_mol, int nmol,
186                                           const t_idef *idef)
187 {
188     int *assigned;
189     int  nril_mol = ril->index[nat_mol];
190     snew(assigned, nmol*nril_mol);
191
192     gmx::ArrayRef<const int> gatindex = cr->dd->globalAtomIndices;
193     for (int ftype = 0; ftype < F_NRE; ftype++)
194     {
195         if (dd_check_ftype(ftype, rt->bBCheck, rt->bConstr, rt->bSettle))
196         {
197             int            nral = NRAL(ftype);
198             const t_ilist *il   = &idef->il[ftype];
199             const t_iatom *ia   = il->iatoms;
200             for (int i = 0; i < il->nr; i += 1+nral)
201             {
202                 int a0 = gatindex[ia[1]];
203                 /* Check if this interaction is in
204                  * the currently checked molblock.
205                  */
206                 if (a0 >= a_start && a0 < a_end)
207                 {
208                     int  mol    = (a0 - a_start)/nat_mol;
209                     int  a0_mol = (a0 - a_start) - mol*nat_mol;
210                     int  j_mol  = ril->index[a0_mol];
211                     bool found  = false;
212                     while (j_mol < ril->index[a0_mol+1] && !found)
213                     {
214                         int j       = mol*nril_mol + j_mol;
215                         int ftype_j = ril->il[j_mol];
216                         /* Here we need to check if this interaction has
217                          * not already been assigned, since we could have
218                          * multiply defined interactions.
219                          */
220                         if (ftype == ftype_j && ia[0] == ril->il[j_mol+1] &&
221                             assigned[j] == 0)
222                         {
223                             /* Check the atoms */
224                             found = true;
225                             for (int a = 0; a < nral; a++)
226                             {
227                                 if (gatindex[ia[1+a]] !=
228                                     a_start + mol*nat_mol + ril->il[j_mol+2+a])
229                                 {
230                                     found = false;
231                                 }
232                             }
233                             if (found)
234                             {
235                                 assigned[j] = 1;
236                             }
237                         }
238                         j_mol += 2 + nral_rt(ftype_j);
239                     }
240                     if (!found)
241                     {
242                         gmx_incons("Some interactions seem to be assigned multiple times");
243                     }
244                 }
245                 ia += 1 + nral;
246             }
247         }
248     }
249
250     gmx_sumi(nmol*nril_mol, assigned, cr);
251
252     int nprint = 10;
253     int i      = 0;
254     for (int mol = 0; mol < nmol; mol++)
255     {
256         int j_mol = 0;
257         while (j_mol < nril_mol)
258         {
259             int ftype = ril->il[j_mol];
260             int nral  = NRAL(ftype);
261             int j     = mol*nril_mol + j_mol;
262             if (assigned[j] == 0 &&
263                 !(interaction_function[ftype].flags & IF_VSITE))
264             {
265                 if (DDMASTER(cr->dd))
266                 {
267                     if (i == 0)
268                     {
269                         print_error_header(fplog, moltypename, nprint);
270                     }
271                     fprintf(fplog, "%20s atoms",
272                             interaction_function[ftype].longname);
273                     fprintf(stderr, "%20s atoms",
274                             interaction_function[ftype].longname);
275                     int a;
276                     for (a = 0; a < nral; a++)
277                     {
278                         fprintf(fplog, "%5d", ril->il[j_mol+2+a]+1);
279                         fprintf(stderr, "%5d", ril->il[j_mol+2+a]+1);
280                     }
281                     while (a < 4)
282                     {
283                         fprintf(fplog, "     ");
284                         fprintf(stderr, "     ");
285                         a++;
286                     }
287                     fprintf(fplog, " global");
288                     fprintf(stderr, " global");
289                     for (a = 0; a < nral; a++)
290                     {
291                         fprintf(fplog, "%6d",
292                                 a_start+mol*nat_mol+ril->il[j_mol+2+a]+1);
293                         fprintf(stderr, "%6d",
294                                 a_start+mol*nat_mol+ril->il[j_mol+2+a]+1);
295                     }
296                     fprintf(fplog, "\n");
297                     fprintf(stderr, "\n");
298                 }
299                 i++;
300                 if (i >= nprint)
301                 {
302                     break;
303                 }
304             }
305             j_mol += 2 + nral_rt(ftype);
306         }
307     }
308
309     sfree(assigned);
310 }
311
312 /*! \brief Help print error output when interactions are missing */
313 static void print_missing_interactions_atoms(FILE *fplog, t_commrec *cr,
314                                              const gmx_mtop_t *mtop,
315                                              const t_idef *idef)
316 {
317     const gmx_reverse_top_t *rt = cr->dd->reverse_top;
318
319     /* Print the atoms in the missing interactions per molblock */
320     int a_end = 0;
321     for (const gmx_molblock_t &molb :  mtop->molblock)
322     {
323         const gmx_moltype_t &moltype  = mtop->moltype[molb.type];
324         int                  a_start  = a_end;
325         a_end                        = a_start + molb.nmol*moltype.atoms.nr;
326
327         print_missing_interactions_mb(fplog, cr, rt,
328                                       *(moltype.name),
329                                       &rt->ril_mt[molb.type],
330                                       a_start, a_end, moltype.atoms.nr,
331                                       molb.nmol,
332                                       idef);
333     }
334 }
335
336 void dd_print_missing_interactions(FILE *fplog, t_commrec *cr,
337                                    int local_count,
338                                    const gmx_mtop_t *top_global,
339                                    const gmx_localtop_t *top_local,
340                                    const t_state *state_local)
341 {
342     int             ndiff_tot, cl[F_NRE], n, ndiff, rest_global, rest_local;
343     int             ftype, nral;
344     char            buf[STRLEN];
345     gmx_domdec_t   *dd;
346
347     dd = cr->dd;
348
349     if (fplog)
350     {
351         fprintf(fplog, "\nNot all bonded interactions have been properly assigned to the domain decomposition cells\n");
352         fflush(fplog);
353     }
354
355     ndiff_tot = local_count - dd->nbonded_global;
356
357     for (ftype = 0; ftype < F_NRE; ftype++)
358     {
359         nral      = NRAL(ftype);
360         cl[ftype] = top_local->idef.il[ftype].nr/(1+nral);
361     }
362
363     gmx_sumi(F_NRE, cl, cr);
364
365     if (DDMASTER(dd))
366     {
367         if (fplog)
368         {
369             fprintf(fplog, "\nA list of missing interactions:\n");
370         }
371         fprintf(stderr, "\nA list of missing interactions:\n");
372         rest_global = dd->nbonded_global;
373         rest_local  = local_count;
374         for (ftype = 0; ftype < F_NRE; ftype++)
375         {
376             /* In the reverse and local top all constraints are merged
377              * into F_CONSTR. So in the if statement we skip F_CONSTRNC
378              * and add these constraints when doing F_CONSTR.
379              */
380             if (((interaction_function[ftype].flags & IF_BOND) &&
381                  (dd->reverse_top->bBCheck
382                   || !(interaction_function[ftype].flags & IF_LIMZERO)))
383                 || (dd->reverse_top->bConstr && ftype == F_CONSTR)
384                 || (dd->reverse_top->bSettle && ftype == F_SETTLE))
385             {
386                 n    = gmx_mtop_ftype_count(top_global, ftype);
387                 if (ftype == F_CONSTR)
388                 {
389                     n += gmx_mtop_ftype_count(top_global, F_CONSTRNC);
390                 }
391                 ndiff = cl[ftype] - n;
392                 if (ndiff != 0)
393                 {
394                     sprintf(buf, "%20s of %6d missing %6d",
395                             interaction_function[ftype].longname, n, -ndiff);
396                     if (fplog)
397                     {
398                         fprintf(fplog, "%s\n", buf);
399                     }
400                     fprintf(stderr, "%s\n", buf);
401                 }
402                 rest_global -= n;
403                 rest_local  -= cl[ftype];
404             }
405         }
406
407         ndiff = rest_local - rest_global;
408         if (ndiff != 0)
409         {
410             sprintf(buf, "%20s of %6d missing %6d", "exclusions",
411                     rest_global, -ndiff);
412             if (fplog)
413             {
414                 fprintf(fplog, "%s\n", buf);
415             }
416             fprintf(stderr, "%s\n", buf);
417         }
418     }
419
420     print_missing_interactions_atoms(fplog, cr, top_global, &top_local->idef);
421     write_dd_pdb("dd_dump_err", 0, "dump", top_global, cr,
422                  -1, as_rvec_array(state_local->x.data()), state_local->box);
423
424     std::string errorMessage;
425
426     if (ndiff_tot > 0)
427     {
428         errorMessage = "One or more interactions were assigned to multiple domains of the domain decompostion. Please report this bug.";
429     }
430     else
431     {
432         errorMessage = gmx::formatString("%d of the %d bonded interactions could not be calculated because some atoms involved moved further apart than the multi-body cut-off distance (%g nm) or the two-body cut-off distance (%g nm), see option -rdd, for pairs and tabulated bonds also see option -ddcheck", -ndiff_tot, cr->dd->nbonded_global, dd_cutoff_multibody(dd), dd_cutoff_twobody(dd));
433     }
434     gmx_fatal_collective(FARGS, cr->mpi_comm_mygroup, MASTER(cr), "%s", errorMessage.c_str());
435 }
436
437 /*! \brief Return global topology molecule information for global atom index \p i_gl */
438 static void global_atomnr_to_moltype_ind(gmx_reverse_top_t *rt, int i_gl,
439                                          int *mb, int *mt, int *mol, int *i_mol)
440 {
441     molblock_ind_t *mbi   = rt->mbi;
442     int             start = 0;
443     int             end   = rt->nmolblock; /* exclusive */
444     int             mid;
445
446     /* binary search for molblock_ind */
447     while (TRUE)
448     {
449         mid = (start+end)/2;
450         if (i_gl >= mbi[mid].a_end)
451         {
452             start = mid+1;
453         }
454         else if (i_gl < mbi[mid].a_start)
455         {
456             end = mid;
457         }
458         else
459         {
460             break;
461         }
462     }
463
464     *mb  = mid;
465     mbi += mid;
466
467     *mt    = mbi->type;
468     *mol   = (i_gl - mbi->a_start) / mbi->natoms_mol;
469     *i_mol = (i_gl - mbi->a_start) - (*mol)*mbi->natoms_mol;
470 }
471
472 /*! \brief Count the exclusions for all atoms in \p cgs */
473 static void count_excls(const t_block *cgs, const t_blocka *excls,
474                         int *n_excl, int *n_intercg_excl, int *n_excl_at_max)
475 {
476     int cg, at0, at1, at, excl, atj;
477
478     *n_excl         = 0;
479     *n_intercg_excl = 0;
480     *n_excl_at_max  = 0;
481     for (cg = 0; cg < cgs->nr; cg++)
482     {
483         at0 = cgs->index[cg];
484         at1 = cgs->index[cg+1];
485         for (at = at0; at < at1; at++)
486         {
487             for (excl = excls->index[at]; excl < excls->index[at+1]; excl++)
488             {
489                 atj = excls->a[excl];
490                 if (atj > at)
491                 {
492                     (*n_excl)++;
493                     if (atj < at0 || atj >= at1)
494                     {
495                         (*n_intercg_excl)++;
496                     }
497                 }
498             }
499
500             *n_excl_at_max = std::max(*n_excl_at_max,
501                                       excls->index[at+1] - excls->index[at]);
502         }
503     }
504 }
505
506 /*! \brief Run the reverse ilist generation and store it in r_il when \p bAssign = TRUE */
507 static int low_make_reverse_ilist(const t_ilist *il_mt, const t_atom *atom,
508                                   const int * const * vsite_pbc,
509                                   int *count,
510                                   gmx_bool bConstr, gmx_bool bSettle,
511                                   gmx_bool bBCheck,
512                                   const int *r_index, int *r_il,
513                                   gmx_bool bLinkToAllAtoms,
514                                   gmx_bool bAssign)
515 {
516     int            ftype, nral, i, j, nlink, link;
517     const t_ilist *il;
518     const t_iatom *ia;
519     int            a;
520     int            nint;
521     gmx_bool       bVSite;
522
523     nint = 0;
524     for (ftype = 0; ftype < F_NRE; ftype++)
525     {
526         if ((interaction_function[ftype].flags & (IF_BOND | IF_VSITE)) ||
527             (bConstr && (ftype == F_CONSTR || ftype == F_CONSTRNC)) ||
528             (bSettle && ftype == F_SETTLE))
529         {
530             bVSite = (interaction_function[ftype].flags & IF_VSITE);
531             nral   = NRAL(ftype);
532             il     = &il_mt[ftype];
533             for (i = 0; i < il->nr; i += 1+nral)
534             {
535                 ia = il->iatoms + i;
536                 if (bLinkToAllAtoms)
537                 {
538                     if (bVSite)
539                     {
540                         /* We don't need the virtual sites for the cg-links */
541                         nlink = 0;
542                     }
543                     else
544                     {
545                         nlink = nral;
546                     }
547                 }
548                 else
549                 {
550                     /* Couple to the first atom in the interaction */
551                     nlink = 1;
552                 }
553                 for (link = 0; link < nlink; link++)
554                 {
555                     a = ia[1+link];
556                     if (bAssign)
557                     {
558                         assert(r_il); //with bAssign not allowed to be null
559                         assert(r_index);
560                         r_il[r_index[a]+count[a]] =
561                             (ftype == F_CONSTRNC ? F_CONSTR : ftype);
562                         r_il[r_index[a]+count[a]+1] = ia[0];
563                         for (j = 1; j < 1+nral; j++)
564                         {
565                             /* Store the molecular atom number */
566                             r_il[r_index[a]+count[a]+1+j] = ia[j];
567                         }
568                     }
569                     if (interaction_function[ftype].flags & IF_VSITE)
570                     {
571                         if (bAssign)
572                         {
573                             /* Add an entry to iatoms for storing
574                              * which of the constructing atoms are
575                              * vsites again.
576                              */
577                             r_il[r_index[a]+count[a]+2+nral] = 0;
578                             for (j = 2; j < 1+nral; j++)
579                             {
580                                 if (atom[ia[j]].ptype == eptVSite)
581                                 {
582                                     r_il[r_index[a]+count[a]+2+nral] |= (2<<j);
583                                 }
584                             }
585                             /* Store vsite pbc atom in a second extra entry */
586                             r_il[r_index[a]+count[a]+2+nral+1] =
587                                 (vsite_pbc ? vsite_pbc[ftype-F_VSITE2][i/(1+nral)] : -2);
588                         }
589                     }
590                     else
591                     {
592                         /* We do not count vsites since they are always
593                          * uniquely assigned and can be assigned
594                          * to multiple nodes with recursive vsites.
595                          */
596                         if (bBCheck ||
597                             !(interaction_function[ftype].flags & IF_LIMZERO))
598                         {
599                             nint++;
600                         }
601                     }
602                     count[a] += 2 + nral_rt(ftype);
603                 }
604             }
605         }
606     }
607
608     return nint;
609 }
610
611 /*! \brief Make the reverse ilist: a list of bonded interactions linked to atoms */
612 static int make_reverse_ilist(const t_ilist *ilist,
613                               const t_atoms *atoms,
614                               const int * const * vsite_pbc,
615                               gmx_bool bConstr, gmx_bool bSettle,
616                               gmx_bool bBCheck,
617                               gmx_bool bLinkToAllAtoms,
618                               reverse_ilist_t *ril_mt)
619 {
620     int nat_mt, *count, i, nint_mt;
621
622     /* Count the interactions */
623     nat_mt = atoms->nr;
624     snew(count, nat_mt);
625     low_make_reverse_ilist(ilist, atoms->atom, vsite_pbc,
626                            count,
627                            bConstr, bSettle, bBCheck, nullptr, nullptr,
628                            bLinkToAllAtoms, FALSE);
629
630     snew(ril_mt->index, nat_mt+1);
631     ril_mt->index[0] = 0;
632     for (i = 0; i < nat_mt; i++)
633     {
634         ril_mt->index[i+1] = ril_mt->index[i] + count[i];
635         count[i]           = 0;
636     }
637     snew(ril_mt->il, ril_mt->index[nat_mt]);
638
639     /* Store the interactions */
640     nint_mt =
641         low_make_reverse_ilist(ilist, atoms->atom, vsite_pbc,
642                                count,
643                                bConstr, bSettle, bBCheck,
644                                ril_mt->index, ril_mt->il,
645                                bLinkToAllAtoms, TRUE);
646
647     sfree(count);
648
649     ril_mt->numAtomsInMolecule = atoms->nr;
650
651     return nint_mt;
652 }
653
654 /*! \brief Destroys a reverse_ilist_t struct */
655 static void destroy_reverse_ilist(reverse_ilist_t *ril)
656 {
657     sfree(ril->index);
658     sfree(ril->il);
659 }
660
661 /*! \brief Generate the reverse topology */
662 static gmx_reverse_top_t *make_reverse_top(const gmx_mtop_t *mtop, gmx_bool bFE,
663                                            const int * const * const * vsite_pbc_molt,
664                                            gmx_bool bConstr, gmx_bool bSettle,
665                                            gmx_bool bBCheck, int *nint)
666 {
667     gmx_reverse_top_t *rt;
668     int               *nint_mt;
669     int                thread;
670
671     snew(rt, 1);
672
673     /* Should we include constraints (for SHAKE) in rt? */
674     rt->bConstr = bConstr;
675     rt->bSettle = bSettle;
676     rt->bBCheck = bBCheck;
677
678     rt->bInterCGInteractions = mtop->bIntermolecularInteractions;
679     snew(nint_mt, mtop->moltype.size());
680     snew(rt->ril_mt, mtop->moltype.size());
681     rt->ril_mt_tot_size = 0;
682     for (size_t mt = 0; mt < mtop->moltype.size(); mt++)
683     {
684         const gmx_moltype_t &molt = mtop->moltype[mt];
685         if (molt.cgs.nr > 1)
686         {
687             rt->bInterCGInteractions = TRUE;
688         }
689
690         /* Make the atom to interaction list for this molecule type */
691         nint_mt[mt] =
692             make_reverse_ilist(molt.ilist, &molt.atoms,
693                                vsite_pbc_molt ? vsite_pbc_molt[mt] : nullptr,
694                                rt->bConstr, rt->bSettle, rt->bBCheck, FALSE,
695                                &rt->ril_mt[mt]);
696
697         rt->ril_mt_tot_size += rt->ril_mt[mt].index[molt.atoms.nr];
698     }
699     if (debug)
700     {
701         fprintf(debug, "The total size of the atom to interaction index is %d integers\n", rt->ril_mt_tot_size);
702     }
703
704     *nint = 0;
705     for (const gmx_molblock_t &molblock : mtop->molblock)
706     {
707         *nint += molblock.nmol*nint_mt[molblock.type];
708     }
709     sfree(nint_mt);
710
711     /* Make an intermolecular reverse top, if necessary */
712     rt->bIntermolecularInteractions = mtop->bIntermolecularInteractions;
713     if (rt->bIntermolecularInteractions)
714     {
715         t_atoms atoms_global;
716
717         rt->ril_intermol.index = nullptr;
718         rt->ril_intermol.il    = nullptr;
719
720         atoms_global.nr   = mtop->natoms;
721         atoms_global.atom = nullptr; /* Only used with virtual sites */
722
723         *nint +=
724             make_reverse_ilist(mtop->intermolecular_ilist, &atoms_global,
725                                nullptr,
726                                rt->bConstr, rt->bSettle, rt->bBCheck, FALSE,
727                                &rt->ril_intermol);
728     }
729
730     if (bFE && gmx_mtop_bondeds_free_energy(mtop))
731     {
732         rt->ilsort = ilsortFE_UNSORTED;
733     }
734     else
735     {
736         rt->ilsort = ilsortNO_FE;
737     }
738
739     /* Make a molblock index for fast searching */
740     snew(rt->mbi, mtop->molblock.size());
741     rt->nmolblock = mtop->molblock.size();
742     int i         = 0;
743     for (size_t mb = 0; mb < mtop->molblock.size(); mb++)
744     {
745         const gmx_molblock_t &molb           = mtop->molblock[mb];
746         int                   numAtomsPerMol = mtop->moltype[molb.type].atoms.nr;
747         rt->mbi[mb].a_start                  = i;
748         i                                   += molb.nmol*numAtomsPerMol;
749         rt->mbi[mb].a_end                    = i;
750         rt->mbi[mb].natoms_mol               = numAtomsPerMol;
751         rt->mbi[mb].type                     = molb.type;
752     }
753
754     rt->nthread = gmx_omp_nthreads_get(emntDomdec);
755     snew(rt->th_work, rt->nthread);
756     if (vsite_pbc_molt != nullptr)
757     {
758         for (thread = 0; thread < rt->nthread; thread++)
759         {
760             snew(rt->th_work[thread].vsite_pbc, F_VSITEN-F_VSITE2+1);
761             snew(rt->th_work[thread].vsite_pbc_nalloc, F_VSITEN-F_VSITE2+1);
762         }
763     }
764
765     return rt;
766 }
767
768 void dd_make_reverse_top(FILE *fplog,
769                          gmx_domdec_t *dd, const gmx_mtop_t *mtop,
770                          const gmx_vsite_t *vsite,
771                          const t_inputrec *ir, gmx_bool bBCheck)
772 {
773     if (fplog)
774     {
775         fprintf(fplog, "\nLinking all bonded interactions to atoms\n");
776     }
777
778     /* If normal and/or settle constraints act only within charge groups,
779      * we can store them in the reverse top and simply assign them to domains.
780      * Otherwise we need to assign them to multiple domains and set up
781      * the parallel version constraint algorithm(s).
782      */
783
784     dd->reverse_top = make_reverse_top(mtop, ir->efep != efepNO,
785                                        vsite ? vsite->vsite_pbc_molt : nullptr,
786                                        !dd->bInterCGcons, !dd->bInterCGsettles,
787                                        bBCheck, &dd->nbonded_global);
788
789     gmx_reverse_top_t *rt = dd->reverse_top;
790
791     /* With the Verlet scheme, exclusions are handled in the non-bonded
792      * kernels and only exclusions inside the cut-off lead to exclusion
793      * forces. Since each atom pair is treated at most once in the non-bonded
794      * kernels, it doesn't matter if the exclusions for the same atom pair
795      * appear multiple times in the exclusion list. In contrast, the, old,
796      * group cut-off scheme loops over a list of exclusions, so there each
797      * excluded pair should appear exactly once.
798      */
799     rt->bExclRequired = (ir->cutoff_scheme == ecutsGROUP &&
800                          inputrecExclForces(ir));
801
802     int nexcl          = 0;
803     dd->n_intercg_excl = 0;
804     rt->n_excl_at_max  = 0;
805     for (const gmx_molblock_t &molb : mtop->molblock)
806     {
807         int                  n_excl_mol, n_excl_icg, n_excl_at_max;
808
809         const gmx_moltype_t &molt = mtop->moltype[molb.type];
810         count_excls(&molt.cgs, &molt.excls,
811                     &n_excl_mol, &n_excl_icg, &n_excl_at_max);
812         nexcl              += molb.nmol*n_excl_mol;
813         dd->n_intercg_excl += molb.nmol*n_excl_icg;
814         rt->n_excl_at_max   = std::max(rt->n_excl_at_max, n_excl_at_max);
815     }
816     if (rt->bExclRequired)
817     {
818         dd->nbonded_global += nexcl;
819         if (EEL_FULL(ir->coulombtype) && dd->n_intercg_excl > 0 && fplog)
820         {
821             fprintf(fplog, "There are %d inter charge-group exclusions,\n"
822                     "will use an extra communication step for exclusion forces for %s\n",
823                     dd->n_intercg_excl, eel_names[ir->coulombtype]);
824         }
825     }
826
827     if (vsite && vsite->n_intercg_vsite > 0)
828     {
829         if (fplog)
830         {
831             fprintf(fplog, "There are %d inter charge-group virtual sites,\n"
832                     "will an extra communication step for selected coordinates and forces\n",
833                     vsite->n_intercg_vsite);
834         }
835         init_domdec_vsites(dd, vsite->n_intercg_vsite);
836     }
837
838     if (dd->bInterCGcons || dd->bInterCGsettles)
839     {
840         init_domdec_constraints(dd, mtop);
841     }
842     if (fplog)
843     {
844         fprintf(fplog, "\n");
845     }
846 }
847
848 /*! \brief Store a vsite interaction at the end of \p il
849  *
850  * This routine is very similar to add_ifunc, but vsites interactions
851  * have more work to do than other kinds of interactions, and the
852  * complex way nral (and thus vector contents) depends on ftype
853  * confuses static analysis tools unless we fuse the vsite
854  * atom-indexing organization code with the ifunc-adding code, so that
855  * they can see that nral is the same value. */
856 static inline void
857 add_ifunc_for_vsites(t_iatom *tiatoms, gmx_ga2la_t *ga2la,
858                      int nral, gmx_bool bHomeA,
859                      int a, int a_gl, int a_mol,
860                      const t_iatom *iatoms,
861                      t_ilist *il)
862 {
863     t_iatom *liatoms;
864
865     if (il->nr+1+nral > il->nalloc)
866     {
867         il->nalloc = over_alloc_large(il->nr+1+nral);
868         srenew(il->iatoms, il->nalloc);
869     }
870     liatoms = il->iatoms + il->nr;
871     il->nr += 1 + nral;
872
873     /* Copy the type */
874     tiatoms[0] = iatoms[0];
875
876     if (bHomeA)
877     {
878         /* We know the local index of the first atom */
879         tiatoms[1] = a;
880     }
881     else
882     {
883         /* Convert later in make_local_vsites */
884         tiatoms[1] = -a_gl - 1;
885     }
886
887     for (int k = 2; k < 1+nral; k++)
888     {
889         int ak_gl = a_gl + iatoms[k] - a_mol;
890         if (!ga2la_get_home(ga2la, ak_gl, &tiatoms[k]))
891         {
892             /* Copy the global index, convert later in make_local_vsites */
893             tiatoms[k] = -(ak_gl + 1);
894         }
895         // Note that ga2la_get_home always sets the third parameter if
896         // it returns TRUE
897     }
898     for (int k = 0; k < 1+nral; k++)
899     {
900         liatoms[k] = tiatoms[k];
901     }
902 }
903
904 /*! \brief Store a bonded interaction at the end of \p il */
905 static inline void add_ifunc(int nral, const t_iatom *tiatoms, t_ilist *il)
906 {
907     t_iatom *liatoms;
908     int      k;
909
910     if (il->nr+1+nral > il->nalloc)
911     {
912         il->nalloc = over_alloc_large(il->nr+1+nral);
913         srenew(il->iatoms, il->nalloc);
914     }
915     liatoms = il->iatoms + il->nr;
916     for (k = 0; k <= nral; k++)
917     {
918         liatoms[k] = tiatoms[k];
919     }
920     il->nr += 1 + nral;
921 }
922
923 /*! \brief Store a position restraint in idef and iatoms, complex because the parameters are different for each entry */
924 static void add_posres(int mol, int a_mol, int numAtomsInMolecule,
925                        const gmx_molblock_t *molb,
926                        t_iatom *iatoms, const t_iparams *ip_in,
927                        t_idef *idef)
928 {
929     int        n, a_molb;
930     t_iparams *ip;
931
932     /* This position restraint has not been added yet,
933      * so it's index is the current number of position restraints.
934      */
935     n = idef->il[F_POSRES].nr/2;
936     if (n+1 > idef->iparams_posres_nalloc)
937     {
938         idef->iparams_posres_nalloc = over_alloc_dd(n+1);
939         srenew(idef->iparams_posres, idef->iparams_posres_nalloc);
940     }
941     ip = &idef->iparams_posres[n];
942     /* Copy the force constants */
943     *ip = ip_in[iatoms[0]];
944
945     /* Get the position restraint coordinates from the molblock */
946     a_molb = mol*numAtomsInMolecule + a_mol;
947     GMX_ASSERT(a_molb < static_cast<int>(molb->posres_xA.size()), "We need a sufficient number of position restraint coordinates");
948     ip->posres.pos0A[XX] = molb->posres_xA[a_molb][XX];
949     ip->posres.pos0A[YY] = molb->posres_xA[a_molb][YY];
950     ip->posres.pos0A[ZZ] = molb->posres_xA[a_molb][ZZ];
951     if (!molb->posres_xB.empty())
952     {
953         ip->posres.pos0B[XX] = molb->posres_xB[a_molb][XX];
954         ip->posres.pos0B[YY] = molb->posres_xB[a_molb][YY];
955         ip->posres.pos0B[ZZ] = molb->posres_xB[a_molb][ZZ];
956     }
957     else
958     {
959         ip->posres.pos0B[XX] = ip->posres.pos0A[XX];
960         ip->posres.pos0B[YY] = ip->posres.pos0A[YY];
961         ip->posres.pos0B[ZZ] = ip->posres.pos0A[ZZ];
962     }
963     /* Set the parameter index for idef->iparams_posre */
964     iatoms[0] = n;
965 }
966
967 /*! \brief Store a flat-bottomed position restraint in idef and iatoms, complex because the parameters are different for each entry */
968 static void add_fbposres(int mol, int a_mol, int numAtomsInMolecule,
969                          const gmx_molblock_t *molb,
970                          t_iatom *iatoms, const t_iparams *ip_in,
971                          t_idef *idef)
972 {
973     int        n, a_molb;
974     t_iparams *ip;
975
976     /* This flat-bottom position restraint has not been added yet,
977      * so it's index is the current number of position restraints.
978      */
979     n = idef->il[F_FBPOSRES].nr/2;
980     if (n+1 > idef->iparams_fbposres_nalloc)
981     {
982         idef->iparams_fbposres_nalloc = over_alloc_dd(n+1);
983         srenew(idef->iparams_fbposres, idef->iparams_fbposres_nalloc);
984     }
985     ip = &idef->iparams_fbposres[n];
986     /* Copy the force constants */
987     *ip = ip_in[iatoms[0]];
988
989     /* Get the position restraint coordinats from the molblock */
990     a_molb = mol*numAtomsInMolecule + a_mol;
991     GMX_ASSERT(a_molb < static_cast<int>(molb->posres_xA.size()), "We need a sufficient number of position restraint coordinates");
992     /* Take reference positions from A position of normal posres */
993     ip->fbposres.pos0[XX] = molb->posres_xA[a_molb][XX];
994     ip->fbposres.pos0[YY] = molb->posres_xA[a_molb][YY];
995     ip->fbposres.pos0[ZZ] = molb->posres_xA[a_molb][ZZ];
996
997     /* Note: no B-type for flat-bottom posres */
998
999     /* Set the parameter index for idef->iparams_posre */
1000     iatoms[0] = n;
1001 }
1002
1003 /*! \brief Store a virtual site interaction, complex because of PBC and recursion */
1004 static void add_vsite(gmx_ga2la_t *ga2la, const int *index, const int *rtil,
1005                       int ftype, int nral,
1006                       gmx_bool bHomeA, int a, int a_gl, int a_mol,
1007                       const t_iatom *iatoms,
1008                       t_idef *idef, int **vsite_pbc, int *vsite_pbc_nalloc)
1009 {
1010     int     k, vsi, pbc_a_mol;
1011     t_iatom tiatoms[1+MAXATOMLIST];
1012     int     j, ftype_r, nral_r;
1013
1014     /* Add this interaction to the local topology */
1015     add_ifunc_for_vsites(tiatoms, ga2la, nral, bHomeA, a, a_gl, a_mol, iatoms, &idef->il[ftype]);
1016
1017     if (vsite_pbc)
1018     {
1019         vsi = idef->il[ftype].nr/(1+nral) - 1;
1020         if (vsi >= vsite_pbc_nalloc[ftype-F_VSITE2])
1021         {
1022             vsite_pbc_nalloc[ftype-F_VSITE2] = over_alloc_large(vsi+1);
1023             srenew(vsite_pbc[ftype-F_VSITE2], vsite_pbc_nalloc[ftype-F_VSITE2]);
1024         }
1025         if (bHomeA)
1026         {
1027             pbc_a_mol = iatoms[1+nral+1];
1028             if (pbc_a_mol < 0)
1029             {
1030                 /* The pbc flag is one of the following two options:
1031                  * -2: vsite and all constructing atoms are within the same cg, no pbc
1032                  * -1: vsite and its first constructing atom are in the same cg, do pbc
1033                  */
1034                 vsite_pbc[ftype-F_VSITE2][vsi] = pbc_a_mol;
1035             }
1036             else
1037             {
1038                 /* Set the pbc atom for this vsite so we can make its pbc
1039                  * identical to the rest of the atoms in its charge group.
1040                  * Since the order of the atoms does not change within a charge
1041                  * group, we do not need the global to local atom index.
1042                  */
1043                 vsite_pbc[ftype-F_VSITE2][vsi] = a + pbc_a_mol - iatoms[1];
1044             }
1045         }
1046         else
1047         {
1048             /* This vsite is non-home (required for recursion),
1049              * and therefore there is no charge group to match pbc with.
1050              * But we always turn on full_pbc to assure that higher order
1051              * recursion works correctly.
1052              */
1053             vsite_pbc[ftype-F_VSITE2][vsi] = -1;
1054         }
1055     }
1056
1057     if (iatoms[1+nral])
1058     {
1059         /* Check for recursion */
1060         for (k = 2; k < 1+nral; k++)
1061         {
1062             if ((iatoms[1+nral] & (2<<k)) && (tiatoms[k] < 0))
1063             {
1064                 /* This construction atoms is a vsite and not a home atom */
1065                 if (gmx_debug_at)
1066                 {
1067                     fprintf(debug, "Constructing atom %d of vsite atom %d is a vsite and non-home\n", iatoms[k]+1, a_mol+1);
1068                 }
1069                 /* Find the vsite construction */
1070
1071                 /* Check all interactions assigned to this atom */
1072                 j = index[iatoms[k]];
1073                 while (j < index[iatoms[k]+1])
1074                 {
1075                     ftype_r = rtil[j++];
1076                     nral_r  = NRAL(ftype_r);
1077                     if (interaction_function[ftype_r].flags & IF_VSITE)
1078                     {
1079                         /* Add this vsite (recursion) */
1080                         add_vsite(ga2la, index, rtil, ftype_r, nral_r,
1081                                   FALSE, -1, a_gl+iatoms[k]-iatoms[1], iatoms[k],
1082                                   rtil+j, idef, vsite_pbc, vsite_pbc_nalloc);
1083                         j += 1 + nral_r + 2;
1084                     }
1085                     else
1086                     {
1087                         j += 1 + nral_r;
1088                     }
1089                 }
1090             }
1091         }
1092     }
1093 }
1094
1095 /*! \brief Build the index that maps each local atom to its local atom group */
1096 static void makeLocalAtomGroupsFromAtoms(gmx_domdec_t *dd)
1097 {
1098     const gmx::RangePartitioning &atomGrouping = dd->atomGrouping();
1099
1100     dd->localAtomGroupFromAtom.clear();
1101
1102     for (size_t g = 0; g < dd->globalAtomGroupIndices.size(); g++)
1103     {
1104         for (int gmx_unused a : atomGrouping.block(g))
1105         {
1106             dd->localAtomGroupFromAtom.push_back(g);
1107         }
1108     }
1109 }
1110
1111 /*! \brief Returns the squared distance between charge groups \p i and \p j */
1112 static real dd_dist2(t_pbc *pbc_null, rvec *cg_cm, const int *la2lc, int i, int j)
1113 {
1114     rvec dx;
1115
1116     if (pbc_null)
1117     {
1118         pbc_dx_aiuc(pbc_null, cg_cm[la2lc[i]], cg_cm[la2lc[j]], dx);
1119     }
1120     else
1121     {
1122         rvec_sub(cg_cm[la2lc[i]], cg_cm[la2lc[j]], dx);
1123     }
1124
1125     return norm2(dx);
1126 }
1127
1128 /*! \brief Append t_blocka block structures 1 to nsrc in src to *dest */
1129 static void combine_blocka(t_blocka *dest, const thread_work_t *src, int nsrc)
1130 {
1131     int ni, na, s, i;
1132
1133     ni = src[nsrc-1].excl.nr;
1134     na = 0;
1135     for (s = 0; s < nsrc; s++)
1136     {
1137         na += src[s].excl.nra;
1138     }
1139     if (ni + 1 > dest->nalloc_index)
1140     {
1141         dest->nalloc_index = over_alloc_large(ni+1);
1142         srenew(dest->index, dest->nalloc_index);
1143     }
1144     if (dest->nra + na > dest->nalloc_a)
1145     {
1146         dest->nalloc_a = over_alloc_large(dest->nra+na);
1147         srenew(dest->a, dest->nalloc_a);
1148     }
1149     for (s = 1; s < nsrc; s++)
1150     {
1151         for (i = dest->nr+1; i < src[s].excl.nr+1; i++)
1152         {
1153             dest->index[i] = dest->nra + src[s].excl.index[i];
1154         }
1155         for (i = 0; i < src[s].excl.nra; i++)
1156         {
1157             dest->a[dest->nra+i] = src[s].excl.a[i];
1158         }
1159         dest->nr   = src[s].excl.nr;
1160         dest->nra += src[s].excl.nra;
1161     }
1162 }
1163
1164 /*! \brief Append t_idef structures 1 to nsrc in src to *dest,
1165  * virtual sites need special attention, as pbc info differs per vsite.
1166  */
1167 static void combine_idef(t_idef *dest, const thread_work_t *src, int nsrc,
1168                          gmx_vsite_t *vsite)
1169 {
1170     int ftype;
1171
1172     for (ftype = 0; ftype < F_NRE; ftype++)
1173     {
1174         int n, s;
1175
1176         n = 0;
1177         for (s = 1; s < nsrc; s++)
1178         {
1179             n += src[s].idef.il[ftype].nr;
1180         }
1181         if (n > 0)
1182         {
1183             t_ilist *ild;
1184
1185             ild = &dest->il[ftype];
1186
1187             if (ild->nr + n > ild->nalloc)
1188             {
1189                 ild->nalloc = over_alloc_large(ild->nr+n);
1190                 srenew(ild->iatoms, ild->nalloc);
1191             }
1192
1193             gmx_bool vpbc;
1194             int      nral1 = 0, ftv = 0;
1195
1196             vpbc = ((interaction_function[ftype].flags & IF_VSITE) &&
1197                     vsite->vsite_pbc_loc != nullptr);
1198             if (vpbc)
1199             {
1200                 nral1 = 1 + NRAL(ftype);
1201                 ftv   = ftype - F_VSITE2;
1202                 if ((ild->nr + n)/nral1 > vsite->vsite_pbc_loc_nalloc[ftv])
1203                 {
1204                     vsite->vsite_pbc_loc_nalloc[ftv] =
1205                         over_alloc_large((ild->nr + n)/nral1);
1206                     srenew(vsite->vsite_pbc_loc[ftv],
1207                            vsite->vsite_pbc_loc_nalloc[ftv]);
1208                 }
1209             }
1210
1211             for (s = 1; s < nsrc; s++)
1212             {
1213                 const t_ilist *ils;
1214                 int            i;
1215
1216                 ils = &src[s].idef.il[ftype];
1217                 for (i = 0; i < ils->nr; i++)
1218                 {
1219                     ild->iatoms[ild->nr+i] = ils->iatoms[i];
1220                 }
1221                 if (vpbc)
1222                 {
1223                     for (i = 0; i < ils->nr; i += nral1)
1224                     {
1225                         vsite->vsite_pbc_loc[ftv][(ild->nr+i)/nral1] =
1226                             src[s].vsite_pbc[ftv][i/nral1];
1227                     }
1228                 }
1229
1230                 ild->nr += ils->nr;
1231             }
1232
1233             /* Position restraints need an additional treatment */
1234             if (ftype == F_POSRES || ftype == F_FBPOSRES)
1235             {
1236                 int          nposres       = dest->il[ftype].nr/2;
1237                 // TODO: Simplify this code using std::vector
1238                 t_iparams * &iparams_dest  = (ftype == F_POSRES ? dest->iparams_posres : dest->iparams_fbposres);
1239                 int         &posres_nalloc = (ftype == F_POSRES ? dest->iparams_posres_nalloc : dest->iparams_fbposres_nalloc);
1240                 if (nposres > posres_nalloc)
1241                 {
1242                     posres_nalloc = over_alloc_large(nposres);
1243                     srenew(iparams_dest, posres_nalloc);
1244                 }
1245
1246                 /* Set nposres to the number of original position restraints in dest */
1247                 for (int s = 1; s < nsrc; s++)
1248                 {
1249                     nposres -= src[s].idef.il[ftype].nr/2;
1250                 }
1251
1252                 for (int s = 1; s < nsrc; s++)
1253                 {
1254                     const t_iparams *iparams_src = (ftype == F_POSRES ? src[s].idef.iparams_posres : src[s].idef.iparams_fbposres);
1255
1256                     for (int i = 0; i < src[s].idef.il[ftype].nr/2; i++)
1257                     {
1258                         /* Correct the index into iparams_posres */
1259                         dest->il[ftype].iatoms[nposres*2] = nposres;
1260                         /* Copy the position restraint force parameters */
1261                         iparams_dest[nposres]             = iparams_src[i];
1262                         nposres++;
1263                     }
1264                 }
1265             }
1266         }
1267     }
1268 }
1269
1270 /*! \brief Check and when available assign bonded interactions for local atom i
1271  */
1272 static inline void
1273 check_assign_interactions_atom(int i, int i_gl,
1274                                int mol, int i_mol,
1275                                int numAtomsInMolecule,
1276                                const int *index, const int *rtil,
1277                                gmx_bool bInterMolInteractions,
1278                                int ind_start, int ind_end,
1279                                const gmx_domdec_t *dd,
1280                                const gmx_domdec_zones_t *zones,
1281                                const gmx_molblock_t *molb,
1282                                gmx_bool bRCheckMB, const ivec rcheck, gmx_bool bRCheck2B,
1283                                real rc2,
1284                                int *la2lc,
1285                                t_pbc *pbc_null,
1286                                rvec *cg_cm,
1287                                const t_iparams *ip_in,
1288                                t_idef *idef,
1289                                int **vsite_pbc, int *vsite_pbc_nalloc,
1290                                int iz,
1291                                gmx_bool bBCheck,
1292                                int *nbonded_local)
1293 {
1294     int j;
1295
1296     j = ind_start;
1297     while (j < ind_end)
1298     {
1299         int            ftype;
1300         const t_iatom *iatoms;
1301         int            nral;
1302         t_iatom        tiatoms[1 + MAXATOMLIST];
1303
1304         ftype  = rtil[j++];
1305         iatoms = rtil + j;
1306         nral   = NRAL(ftype);
1307         if (ftype == F_SETTLE)
1308         {
1309             /* Settles are only in the reverse top when they
1310              * operate within a charge group. So we can assign
1311              * them without checks. We do this only for performance
1312              * reasons; it could be handled by the code below.
1313              */
1314             if (iz == 0)
1315             {
1316                 /* Home zone: add this settle to the local topology */
1317                 tiatoms[0] = iatoms[0];
1318                 tiatoms[1] = i;
1319                 tiatoms[2] = i + iatoms[2] - iatoms[1];
1320                 tiatoms[3] = i + iatoms[3] - iatoms[1];
1321                 add_ifunc(nral, tiatoms, &idef->il[ftype]);
1322                 (*nbonded_local)++;
1323             }
1324             j += 1 + nral;
1325         }
1326         else if (interaction_function[ftype].flags & IF_VSITE)
1327         {
1328             assert(!bInterMolInteractions);
1329             /* The vsite construction goes where the vsite itself is */
1330             if (iz == 0)
1331             {
1332                 add_vsite(dd->ga2la, index, rtil, ftype, nral,
1333                           TRUE, i, i_gl, i_mol,
1334                           iatoms, idef, vsite_pbc, vsite_pbc_nalloc);
1335             }
1336             j += 1 + nral + 2;
1337         }
1338         else
1339         {
1340             gmx_bool bUse;
1341
1342             /* Copy the type */
1343             tiatoms[0] = iatoms[0];
1344
1345             if (nral == 1)
1346             {
1347                 assert(!bInterMolInteractions);
1348                 /* Assign single-body interactions to the home zone */
1349                 if (iz == 0)
1350                 {
1351                     bUse       = TRUE;
1352                     tiatoms[1] = i;
1353                     if (ftype == F_POSRES)
1354                     {
1355                         add_posres(mol, i_mol, numAtomsInMolecule,
1356                                    molb, tiatoms, ip_in, idef);
1357                     }
1358                     else if (ftype == F_FBPOSRES)
1359                     {
1360                         add_fbposres(mol, i_mol, numAtomsInMolecule,
1361                                      molb, tiatoms, ip_in, idef);
1362                     }
1363                 }
1364                 else
1365                 {
1366                     bUse = FALSE;
1367                 }
1368             }
1369             else if (nral == 2)
1370             {
1371                 /* This is a two-body interaction, we can assign
1372                  * analogous to the non-bonded assignments.
1373                  */
1374                 int k_gl, a_loc, kz;
1375
1376                 if (!bInterMolInteractions)
1377                 {
1378                     /* Get the global index using the offset in the molecule */
1379                     k_gl = i_gl + iatoms[2] - i_mol;
1380                 }
1381                 else
1382                 {
1383                     k_gl = iatoms[2];
1384                 }
1385                 if (!ga2la_get(dd->ga2la, k_gl, &a_loc, &kz))
1386                 {
1387                     bUse = FALSE;
1388                 }
1389                 else
1390                 {
1391                     if (kz >= zones->n)
1392                     {
1393                         kz -= zones->n;
1394                     }
1395                     /* Check zone interaction assignments */
1396                     bUse = ((iz < zones->nizone &&
1397                              iz <= kz &&
1398                              kz >= zones->izone[iz].j0 &&
1399                              kz <  zones->izone[iz].j1) ||
1400                             (kz < zones->nizone &&
1401                                   iz > kz &&
1402                              iz >= zones->izone[kz].j0 &&
1403                              iz <  zones->izone[kz].j1));
1404                     if (bUse)
1405                     {
1406                         tiatoms[1] = i;
1407                         tiatoms[2] = a_loc;
1408                         /* If necessary check the cgcm distance */
1409                         if (bRCheck2B &&
1410                             dd_dist2(pbc_null, cg_cm, la2lc,
1411                                      tiatoms[1], tiatoms[2]) >= rc2)
1412                         {
1413                             bUse = FALSE;
1414                         }
1415                     }
1416                 }
1417             }
1418             else
1419             {
1420                 /* Assign this multi-body bonded interaction to
1421                  * the local node if we have all the atoms involved
1422                  * (local or communicated) and the minimum zone shift
1423                  * in each dimension is zero, for dimensions
1424                  * with 2 DD cells an extra check may be necessary.
1425                  */
1426                 ivec k_zero, k_plus;
1427                 int  k;
1428
1429                 bUse = TRUE;
1430                 clear_ivec(k_zero);
1431                 clear_ivec(k_plus);
1432                 for (k = 1; k <= nral && bUse; k++)
1433                 {
1434                     gmx_bool bLocal;
1435                     int      k_gl, a_loc;
1436                     int      kz;
1437
1438                     if (!bInterMolInteractions)
1439                     {
1440                         /* Get the global index using the offset in the molecule */
1441                         k_gl = i_gl + iatoms[k] - i_mol;
1442                     }
1443                     else
1444                     {
1445                         k_gl = iatoms[k];
1446                     }
1447                     bLocal = ga2la_get(dd->ga2la, k_gl, &a_loc, &kz);
1448                     if (!bLocal || kz >= zones->n)
1449                     {
1450                         /* We do not have this atom of this interaction
1451                          * locally, or it comes from more than one cell
1452                          * away.
1453                          */
1454                         bUse = FALSE;
1455                     }
1456                     else
1457                     {
1458                         int d;
1459
1460                         tiatoms[k] = a_loc;
1461                         for (d = 0; d < DIM; d++)
1462                         {
1463                             if (zones->shift[kz][d] == 0)
1464                             {
1465                                 k_zero[d] = k;
1466                             }
1467                             else
1468                             {
1469                                 k_plus[d] = k;
1470                             }
1471                         }
1472                     }
1473                 }
1474                 bUse = (bUse &&
1475                         k_zero[XX] && k_zero[YY] && k_zero[ZZ]);
1476                 if (bRCheckMB)
1477                 {
1478                     int d;
1479
1480                     for (d = 0; (d < DIM && bUse); d++)
1481                     {
1482                         /* Check if the cg_cm distance falls within
1483                          * the cut-off to avoid possible multiple
1484                          * assignments of bonded interactions.
1485                          */
1486                         if (rcheck[d] &&
1487                             k_plus[d] &&
1488                             dd_dist2(pbc_null, cg_cm, la2lc,
1489                                      tiatoms[k_zero[d]], tiatoms[k_plus[d]]) >= rc2)
1490                         {
1491                             bUse = FALSE;
1492                         }
1493                     }
1494                 }
1495             }
1496             if (bUse)
1497             {
1498                 /* Add this interaction to the local topology */
1499                 add_ifunc(nral, tiatoms, &idef->il[ftype]);
1500                 /* Sum so we can check in global_stat
1501                  * if we have everything.
1502                  */
1503                 if (bBCheck ||
1504                     !(interaction_function[ftype].flags & IF_LIMZERO))
1505                 {
1506                     (*nbonded_local)++;
1507                 }
1508             }
1509             j += 1 + nral;
1510         }
1511     }
1512 }
1513
1514 /*! \brief This function looks up and assigns bonded interactions for zone iz.
1515  *
1516  * With thread parallelizing each thread acts on a different atom range:
1517  * at_start to at_end.
1518  */
1519 static int make_bondeds_zone(gmx_domdec_t *dd,
1520                              const gmx_domdec_zones_t *zones,
1521                              const std::vector<gmx_molblock_t> &molb,
1522                              gmx_bool bRCheckMB, ivec rcheck, gmx_bool bRCheck2B,
1523                              real rc2,
1524                              int *la2lc, t_pbc *pbc_null, rvec *cg_cm,
1525                              const t_iparams *ip_in,
1526                              t_idef *idef,
1527                              int **vsite_pbc,
1528                              int *vsite_pbc_nalloc,
1529                              int izone,
1530                              gmx::RangePartitioning::Block atomRange)
1531 {
1532     int                mb, mt, mol, i_mol;
1533     int               *index, *rtil;
1534     gmx_bool           bBCheck;
1535     gmx_reverse_top_t *rt;
1536     int                nbonded_local;
1537
1538     rt = dd->reverse_top;
1539
1540     bBCheck = rt->bBCheck;
1541
1542     nbonded_local = 0;
1543
1544     for (int i : atomRange)
1545     {
1546         /* Get the global atom number */
1547         const int i_gl = dd->globalAtomIndices[i];
1548         global_atomnr_to_moltype_ind(rt, i_gl, &mb, &mt, &mol, &i_mol);
1549         /* Check all intramolecular interactions assigned to this atom */
1550         index = rt->ril_mt[mt].index;
1551         rtil  = rt->ril_mt[mt].il;
1552
1553         check_assign_interactions_atom(i, i_gl, mol, i_mol,
1554                                        rt->ril_mt[mt].numAtomsInMolecule,
1555                                        index, rtil, FALSE,
1556                                        index[i_mol], index[i_mol+1],
1557                                        dd, zones,
1558                                        &molb[mb],
1559                                        bRCheckMB, rcheck, bRCheck2B, rc2,
1560                                        la2lc,
1561                                        pbc_null,
1562                                        cg_cm,
1563                                        ip_in,
1564                                        idef, vsite_pbc, vsite_pbc_nalloc,
1565                                        izone,
1566                                        bBCheck,
1567                                        &nbonded_local);
1568
1569
1570         if (rt->bIntermolecularInteractions)
1571         {
1572             /* Check all intermolecular interactions assigned to this atom */
1573             index = rt->ril_intermol.index;
1574             rtil  = rt->ril_intermol.il;
1575
1576             check_assign_interactions_atom(i, i_gl, mol, i_mol,
1577                                            rt->ril_mt[mt].numAtomsInMolecule,
1578                                            index, rtil, TRUE,
1579                                            index[i_gl], index[i_gl + 1],
1580                                            dd, zones,
1581                                            &molb[mb],
1582                                            bRCheckMB, rcheck, bRCheck2B, rc2,
1583                                            la2lc,
1584                                            pbc_null,
1585                                            cg_cm,
1586                                            ip_in,
1587                                            idef, vsite_pbc, vsite_pbc_nalloc,
1588                                            izone,
1589                                            bBCheck,
1590                                            &nbonded_local);
1591         }
1592     }
1593
1594     return nbonded_local;
1595 }
1596
1597 /*! \brief Set the exclusion data for i-zone \p iz for the case of no exclusions */
1598 static void set_no_exclusions_zone(const gmx_domdec_t       *dd,
1599                                    const gmx_domdec_zones_t *zones,
1600                                    int                       iz,
1601                                    t_blocka                 *lexcls)
1602 {
1603     const auto zone = dd->atomGrouping().subRange(zones->cg_range[iz],
1604                                                   zones->cg_range[iz + 1]);
1605
1606     for (int a : zone)
1607     {
1608         lexcls->index[a + 1] = lexcls->nra;
1609     }
1610 }
1611
1612 /*! \brief Set the exclusion data for i-zone \p iz
1613  *
1614  * This is a legacy version for the group scheme of the same routine below.
1615  * Here charge groups and distance checks to ensure unique exclusions
1616  * are supported.
1617  */
1618 static int make_exclusions_zone_cg(gmx_domdec_t *dd, gmx_domdec_zones_t *zones,
1619                                    const std::vector<gmx_moltype_t> &moltype,
1620                                    gmx_bool bRCheck, real rc2,
1621                                    int *la2lc, t_pbc *pbc_null, rvec *cg_cm,
1622                                    const int *cginfo,
1623                                    t_blocka *lexcls,
1624                                    int iz,
1625                                    int cg_start, int cg_end)
1626 {
1627     int               n_excl_at_max;
1628     int               mb, mt, mol;
1629     const t_blocka   *excls;
1630     gmx_ga2la_t      *ga2la;
1631     int               cell;
1632
1633     ga2la = dd->ga2la;
1634
1635     const auto jRange = dd->atomGrouping().subRange(zones->izone[iz].jcg0,
1636                                                     zones->izone[iz].jcg1);
1637
1638     n_excl_at_max = dd->reverse_top->n_excl_at_max;
1639
1640     /* We set the end index, but note that we might not start at zero here */
1641     lexcls->nr = dd->atomGrouping().subRange(0, cg_end).size();
1642
1643     int n     = lexcls->nra;
1644     int count = 0;
1645     for (int cg = cg_start; cg < cg_end; cg++)
1646     {
1647         if (n + (cg_end - cg_start)*n_excl_at_max > lexcls->nalloc_a)
1648         {
1649             lexcls->nalloc_a = over_alloc_large(n + (cg_end - cg_start)*n_excl_at_max);
1650             srenew(lexcls->a, lexcls->nalloc_a);
1651         }
1652         const auto atomGroup = dd->atomGrouping().block(cg);
1653         if (GET_CGINFO_EXCL_INTER(cginfo[cg]) ||
1654             !GET_CGINFO_EXCL_INTRA(cginfo[cg]))
1655         {
1656             /* Copy the exclusions from the global top */
1657             for (int la : atomGroup)
1658             {
1659                 lexcls->index[la] = n;
1660                 int a_gl          = dd->globalAtomIndices[la];
1661                 int a_mol;
1662                 global_atomnr_to_moltype_ind(dd->reverse_top, a_gl, &mb, &mt, &mol, &a_mol);
1663                 excls = &moltype[mt].excls;
1664                 for (int j = excls->index[a_mol]; j < excls->index[a_mol+1]; j++)
1665                 {
1666                     int aj_mol = excls->a[j];
1667                     /* This computation of jla is only correct intra-cg */
1668                     int jla = la + aj_mol - a_mol;
1669                     if (atomGroup.inRange(jla))
1670                     {
1671                         /* This is an intra-cg exclusion. We can skip
1672                          *  the global indexing and distance checking.
1673                          */
1674                         /* Intra-cg exclusions are only required
1675                          * for the home zone.
1676                          */
1677                         if (iz == 0)
1678                         {
1679                             lexcls->a[n++] = jla;
1680                             /* Check to avoid double counts */
1681                             if (jla > la)
1682                             {
1683                                 count++;
1684                             }
1685                         }
1686                     }
1687                     else
1688                     {
1689                         /* This is a inter-cg exclusion */
1690                         /* Since exclusions are pair interactions,
1691                          * just like non-bonded interactions,
1692                          * they can be assigned properly up
1693                          * to the DD cutoff (not cutoff_min as
1694                          * for the other bonded interactions).
1695                          */
1696                         if (ga2la_get(ga2la, a_gl+aj_mol-a_mol, &jla, &cell))
1697                         {
1698                             if (iz == 0 && cell == 0)
1699                             {
1700                                 lexcls->a[n++] = jla;
1701                                 /* Check to avoid double counts */
1702                                 if (jla > la)
1703                                 {
1704                                     count++;
1705                                 }
1706                             }
1707                             else if (jRange.inRange(jla) &&
1708                                      (!bRCheck ||
1709                                       dd_dist2(pbc_null, cg_cm, la2lc, la, jla) < rc2))
1710                             {
1711                                 /* jla > la, since jRange.begin() > la */
1712                                 lexcls->a[n++] = jla;
1713                                 count++;
1714                             }
1715                         }
1716                     }
1717                 }
1718             }
1719         }
1720         else
1721         {
1722             /* There are no inter-cg excls and this cg is self-excluded.
1723              * These exclusions are only required for zone 0,
1724              * since other zones do not see themselves.
1725              */
1726             if (iz == 0)
1727             {
1728                 for (int la : atomGroup)
1729                 {
1730                     lexcls->index[la] = n;
1731                     for (int j : atomGroup)
1732                     {
1733                         lexcls->a[n++] = j;
1734                     }
1735                 }
1736                 count += (atomGroup.size()*(atomGroup.size() - 1))/2;
1737             }
1738             else
1739             {
1740                 /* We don't need exclusions for this cg */
1741                 for (int la : atomGroup)
1742                 {
1743                     lexcls->index[la] = n;
1744                 }
1745             }
1746         }
1747     }
1748
1749     lexcls->index[lexcls->nr] = n;
1750     lexcls->nra               = n;
1751
1752     return count;
1753 }
1754
1755 /*! \brief Set the exclusion data for i-zone \p iz */
1756 static void make_exclusions_zone(gmx_domdec_t *dd,
1757                                  gmx_domdec_zones_t *zones,
1758                                  const std::vector<gmx_moltype_t> &moltype,
1759                                  const int *cginfo,
1760                                  t_blocka *lexcls,
1761                                  int iz,
1762                                  int at_start, int at_end)
1763 {
1764     gmx_ga2la_t *ga2la;
1765     int          n_excl_at_max, n, at;
1766
1767     ga2la = dd->ga2la;
1768
1769     const auto jRange = dd->atomGrouping().subRange(zones->izone[iz].jcg0,
1770                                                     zones->izone[iz].jcg1);
1771
1772     n_excl_at_max = dd->reverse_top->n_excl_at_max;
1773
1774     /* We set the end index, but note that we might not start at zero here */
1775     lexcls->nr = at_end;
1776
1777     n = lexcls->nra;
1778     for (at = at_start; at < at_end; at++)
1779     {
1780         if (n + 1000 > lexcls->nalloc_a)
1781         {
1782             lexcls->nalloc_a = over_alloc_large(n + 1000);
1783             srenew(lexcls->a, lexcls->nalloc_a);
1784         }
1785         if (GET_CGINFO_EXCL_INTER(cginfo[at]))
1786         {
1787             int             a_gl, mb, mt, mol, a_mol, j;
1788             const t_blocka *excls;
1789
1790             if (n + n_excl_at_max > lexcls->nalloc_a)
1791             {
1792                 lexcls->nalloc_a = over_alloc_large(n + n_excl_at_max);
1793                 srenew(lexcls->a, lexcls->nalloc_a);
1794             }
1795
1796             /* Copy the exclusions from the global top */
1797             lexcls->index[at] = n;
1798             a_gl              = dd->globalAtomIndices[at];
1799             global_atomnr_to_moltype_ind(dd->reverse_top, a_gl,
1800                                          &mb, &mt, &mol, &a_mol);
1801             excls = &moltype[mt].excls;
1802             for (j = excls->index[a_mol]; j < excls->index[a_mol + 1]; j++)
1803             {
1804                 int aj_mol, at_j, cell;
1805
1806                 aj_mol = excls->a[j];
1807
1808                 if (ga2la_get(ga2la, a_gl + aj_mol - a_mol, &at_j, &cell))
1809                 {
1810                     /* This check is not necessary, but it can reduce
1811                      * the number of exclusions in the list, which in turn
1812                      * can speed up the pair list construction a bit.
1813                      */
1814                     if (jRange.inRange(at_j))
1815                     {
1816                         lexcls->a[n++] = at_j;
1817                     }
1818                 }
1819             }
1820         }
1821         else
1822         {
1823             /* We don't need exclusions for this atom */
1824             lexcls->index[at] = n;
1825         }
1826     }
1827
1828     lexcls->index[lexcls->nr] = n;
1829     lexcls->nra               = n;
1830 }
1831
1832
1833 /*! \brief Ensure we have enough space in \p ba for \p nindex_max indices */
1834 static void check_alloc_index(t_blocka *ba, int nindex_max)
1835 {
1836     if (nindex_max+1 > ba->nalloc_index)
1837     {
1838         ba->nalloc_index = over_alloc_dd(nindex_max+1);
1839         srenew(ba->index, ba->nalloc_index);
1840     }
1841 }
1842
1843 /*! \brief Ensure that we have enough space for exclusion storate in \p lexcls */
1844 static void check_exclusions_alloc(gmx_domdec_t *dd, gmx_domdec_zones_t *zones,
1845                                    t_blocka *lexcls)
1846 {
1847     int nr = dd->atomGrouping().subRange(0, zones->izone[zones->nizone - 1].cg1).size();
1848
1849     check_alloc_index(lexcls, nr);
1850
1851     for (int thread = 1; thread < dd->reverse_top->nthread; thread++)
1852     {
1853         check_alloc_index(&dd->reverse_top->th_work[thread].excl, nr);
1854     }
1855 }
1856
1857 /*! \brief Set the total count indexes for the local exclusions, needed by several functions */
1858 static void finish_local_exclusions(gmx_domdec_t *dd, gmx_domdec_zones_t *zones,
1859                                     t_blocka *lexcls)
1860 {
1861     const auto nonhomeIzonesAtomRange =
1862         dd->atomGrouping().subRange(zones->izone[0].cg1,
1863                                     zones->izone[zones->nizone - 1].cg1);
1864
1865     if (dd->n_intercg_excl == 0)
1866     {
1867         /* There are no exclusions involving non-home charge groups,
1868          * but we need to set the indices for neighborsearching.
1869          */
1870         for (int la : nonhomeIzonesAtomRange)
1871         {
1872             lexcls->index[la] = lexcls->nra;
1873         }
1874
1875         /* nr is only used to loop over the exclusions for Ewald and RF,
1876          * so we can set it to the number of home atoms for efficiency.
1877          */
1878         lexcls->nr = nonhomeIzonesAtomRange.begin();
1879     }
1880     else
1881     {
1882         lexcls->nr = nonhomeIzonesAtomRange.end();
1883     }
1884 }
1885
1886 /*! \brief Clear a t_idef struct */
1887 static void clear_idef(t_idef *idef)
1888 {
1889     int  ftype;
1890
1891     /* Clear the counts */
1892     for (ftype = 0; ftype < F_NRE; ftype++)
1893     {
1894         idef->il[ftype].nr = 0;
1895     }
1896 }
1897
1898 /*! \brief Generate and store all required local bonded interactions in \p idef and local exclusions in \p lexcls */
1899 static int make_local_bondeds_excls(gmx_domdec_t *dd,
1900                                     gmx_domdec_zones_t *zones,
1901                                     const gmx_mtop_t *mtop,
1902                                     const int *cginfo,
1903                                     gmx_bool bRCheckMB, ivec rcheck, gmx_bool bRCheck2B,
1904                                     real rc,
1905                                     int *la2lc, t_pbc *pbc_null, rvec *cg_cm,
1906                                     t_idef *idef, gmx_vsite_t *vsite,
1907                                     t_blocka *lexcls, int *excl_count)
1908 {
1909     int                nzone_bondeds, nzone_excl;
1910     int                izone, cg0, cg1;
1911     real               rc2;
1912     int                nbonded_local;
1913     int                thread;
1914     gmx_reverse_top_t *rt;
1915
1916     if (dd->reverse_top->bInterCGInteractions)
1917     {
1918         nzone_bondeds = zones->n;
1919     }
1920     else
1921     {
1922         /* Only single charge group (or atom) molecules, so interactions don't
1923          * cross zone boundaries and we only need to assign in the home zone.
1924          */
1925         nzone_bondeds = 1;
1926     }
1927
1928     if (dd->n_intercg_excl > 0)
1929     {
1930         /* We only use exclusions from i-zones to i- and j-zones */
1931         nzone_excl = zones->nizone;
1932     }
1933     else
1934     {
1935         /* There are no inter-cg exclusions and only zone 0 sees itself */
1936         nzone_excl = 1;
1937     }
1938
1939     check_exclusions_alloc(dd, zones, lexcls);
1940
1941     rt = dd->reverse_top;
1942
1943     rc2 = rc*rc;
1944
1945     /* Clear the counts */
1946     clear_idef(idef);
1947     nbonded_local = 0;
1948
1949     lexcls->nr    = 0;
1950     lexcls->nra   = 0;
1951     *excl_count   = 0;
1952
1953     for (izone = 0; izone < nzone_bondeds; izone++)
1954     {
1955         cg0 = zones->cg_range[izone];
1956         cg1 = zones->cg_range[izone + 1];
1957
1958 #pragma omp parallel for num_threads(rt->nthread) schedule(static)
1959         for (thread = 0; thread < rt->nthread; thread++)
1960         {
1961             try
1962             {
1963                 int       cg0t, cg1t;
1964                 t_idef   *idef_t;
1965                 int     **vsite_pbc;
1966                 int      *vsite_pbc_nalloc;
1967                 t_blocka *excl_t;
1968
1969                 cg0t = cg0 + ((cg1 - cg0)* thread   )/rt->nthread;
1970                 cg1t = cg0 + ((cg1 - cg0)*(thread+1))/rt->nthread;
1971
1972                 if (thread == 0)
1973                 {
1974                     idef_t = idef;
1975                 }
1976                 else
1977                 {
1978                     idef_t = &rt->th_work[thread].idef;
1979                     clear_idef(idef_t);
1980                 }
1981
1982                 if (vsite && vsite->bHaveChargeGroups && vsite->n_intercg_vsite > 0)
1983                 {
1984                     if (thread == 0)
1985                     {
1986                         vsite_pbc        = vsite->vsite_pbc_loc;
1987                         vsite_pbc_nalloc = vsite->vsite_pbc_loc_nalloc;
1988                     }
1989                     else
1990                     {
1991                         vsite_pbc        = rt->th_work[thread].vsite_pbc;
1992                         vsite_pbc_nalloc = rt->th_work[thread].vsite_pbc_nalloc;
1993                     }
1994                 }
1995                 else
1996                 {
1997                     vsite_pbc        = nullptr;
1998                     vsite_pbc_nalloc = nullptr;
1999                 }
2000
2001                 rt->th_work[thread].nbonded =
2002                     make_bondeds_zone(dd, zones,
2003                                       mtop->molblock,
2004                                       bRCheckMB, rcheck, bRCheck2B, rc2,
2005                                       la2lc, pbc_null, cg_cm, idef->iparams,
2006                                       idef_t,
2007                                       vsite_pbc, vsite_pbc_nalloc,
2008                                       izone,
2009                                       dd->atomGrouping().subRange(cg0t, cg1t));
2010
2011                 if (izone < nzone_excl)
2012                 {
2013                     if (thread == 0)
2014                     {
2015                         excl_t = lexcls;
2016                     }
2017                     else
2018                     {
2019                         excl_t      = &rt->th_work[thread].excl;
2020                         excl_t->nr  = 0;
2021                         excl_t->nra = 0;
2022                     }
2023
2024                     if (dd->atomGrouping().allBlocksHaveSizeOne() &&
2025                         !rt->bExclRequired)
2026                     {
2027                         /* No charge groups and no distance check required */
2028                         make_exclusions_zone(dd, zones,
2029                                              mtop->moltype, cginfo,
2030                                              excl_t,
2031                                              izone,
2032                                              cg0t, cg1t);
2033                     }
2034                     else
2035                     {
2036                         rt->th_work[thread].excl_count =
2037                             make_exclusions_zone_cg(dd, zones,
2038                                                     mtop->moltype, bRCheck2B, rc2,
2039                                                     la2lc, pbc_null, cg_cm, cginfo,
2040                                                     excl_t,
2041                                                     izone,
2042                                                     cg0t, cg1t);
2043                     }
2044                 }
2045             }
2046             GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
2047         }
2048
2049         if (rt->nthread > 1)
2050         {
2051             combine_idef(idef, rt->th_work, rt->nthread, vsite);
2052         }
2053
2054         for (thread = 0; thread < rt->nthread; thread++)
2055         {
2056             nbonded_local += rt->th_work[thread].nbonded;
2057         }
2058
2059         if (izone < nzone_excl)
2060         {
2061             if (rt->nthread > 1)
2062             {
2063                 combine_blocka(lexcls, rt->th_work, rt->nthread);
2064             }
2065
2066             for (thread = 0; thread < rt->nthread; thread++)
2067             {
2068                 *excl_count += rt->th_work[thread].excl_count;
2069             }
2070         }
2071     }
2072
2073     /* Some zones might not have exclusions, but some code still needs to
2074      * loop over the index, so we set the indices here.
2075      */
2076     for (izone = nzone_excl; izone < zones->nizone; izone++)
2077     {
2078         set_no_exclusions_zone(dd, zones, izone, lexcls);
2079     }
2080
2081     finish_local_exclusions(dd, zones, lexcls);
2082     if (debug)
2083     {
2084         fprintf(debug, "We have %d exclusions, check count %d\n",
2085                 lexcls->nra, *excl_count);
2086     }
2087
2088     return nbonded_local;
2089 }
2090
2091 void dd_make_local_cgs(gmx_domdec_t *dd, t_block *lcgs)
2092 {
2093     lcgs->nr    = dd->globalAtomGroupIndices.size();
2094     lcgs->index = dd->atomGrouping_.rawIndex().data();
2095 }
2096
2097 void dd_make_local_top(gmx_domdec_t *dd, gmx_domdec_zones_t *zones,
2098                        int npbcdim, matrix box,
2099                        rvec cellsize_min, const ivec npulse,
2100                        t_forcerec *fr,
2101                        rvec *cgcm_or_x,
2102                        gmx_vsite_t *vsite,
2103                        const gmx_mtop_t *mtop, gmx_localtop_t *ltop)
2104 {
2105     gmx_bool bRCheckMB, bRCheck2B;
2106     real     rc = -1;
2107     ivec     rcheck;
2108     int      d, nexcl;
2109     t_pbc    pbc, *pbc_null = nullptr;
2110
2111     if (debug)
2112     {
2113         fprintf(debug, "Making local topology\n");
2114     }
2115
2116     dd_make_local_cgs(dd, &ltop->cgs);
2117
2118     bRCheckMB   = FALSE;
2119     bRCheck2B   = FALSE;
2120
2121     if (dd->reverse_top->bInterCGInteractions)
2122     {
2123         /* We need to check to which cell bondeds should be assigned */
2124         rc = dd_cutoff_twobody(dd);
2125         if (debug)
2126         {
2127             fprintf(debug, "Two-body bonded cut-off distance is %g\n", rc);
2128         }
2129
2130         /* Should we check cg_cm distances when assigning bonded interactions? */
2131         for (d = 0; d < DIM; d++)
2132         {
2133             rcheck[d] = FALSE;
2134             /* Only need to check for dimensions where the part of the box
2135              * that is not communicated is smaller than the cut-off.
2136              */
2137             if (d < npbcdim && dd->nc[d] > 1 &&
2138                 (dd->nc[d] - npulse[d])*cellsize_min[d] < 2*rc)
2139             {
2140                 if (dd->nc[d] == 2)
2141                 {
2142                     rcheck[d] = TRUE;
2143                     bRCheckMB = TRUE;
2144                 }
2145                 /* Check for interactions between two atoms,
2146                  * where we can allow interactions up to the cut-off,
2147                  * instead of up to the smallest cell dimension.
2148                  */
2149                 bRCheck2B = TRUE;
2150             }
2151             if (debug)
2152             {
2153                 fprintf(debug,
2154                         "dim %d cellmin %f bonded rcheck[%d] = %d, bRCheck2B = %s\n",
2155                         d, cellsize_min[d], d, rcheck[d], gmx::boolToString(bRCheck2B));
2156             }
2157         }
2158         if (bRCheckMB || bRCheck2B)
2159         {
2160             makeLocalAtomGroupsFromAtoms(dd);
2161             if (fr->bMolPBC)
2162             {
2163                 pbc_null = set_pbc_dd(&pbc, fr->ePBC, dd->nc, TRUE, box);
2164             }
2165             else
2166             {
2167                 pbc_null = nullptr;
2168             }
2169         }
2170     }
2171
2172     dd->nbonded_local =
2173         make_local_bondeds_excls(dd, zones, mtop, fr->cginfo,
2174                                  bRCheckMB, rcheck, bRCheck2B, rc,
2175                                  dd->localAtomGroupFromAtom.data(),
2176                                  pbc_null, cgcm_or_x,
2177                                  &ltop->idef, vsite,
2178                                  &ltop->excls, &nexcl);
2179
2180     /* The ilist is not sorted yet,
2181      * we can only do this when we have the charge arrays.
2182      */
2183     ltop->idef.ilsort = ilsortUNKNOWN;
2184
2185     if (dd->reverse_top->bExclRequired)
2186     {
2187         dd->nbonded_local += nexcl;
2188     }
2189
2190     ltop->atomtypes  = mtop->atomtypes;
2191 }
2192
2193 void dd_sort_local_top(gmx_domdec_t *dd, const t_mdatoms *mdatoms,
2194                        gmx_localtop_t *ltop)
2195 {
2196     if (dd->reverse_top->ilsort == ilsortNO_FE)
2197     {
2198         ltop->idef.ilsort = ilsortNO_FE;
2199     }
2200     else
2201     {
2202         gmx_sort_ilist_fe(&ltop->idef, mdatoms->chargeA, mdatoms->chargeB);
2203     }
2204 }
2205
2206 gmx_localtop_t *dd_init_local_top(const gmx_mtop_t *top_global)
2207 {
2208     gmx_localtop_t *top;
2209     int             i;
2210
2211     snew(top, 1);
2212
2213     top->idef.ntypes    = top_global->ffparams.ntypes;
2214     top->idef.atnr      = top_global->ffparams.atnr;
2215     top->idef.functype  = top_global->ffparams.functype;
2216     top->idef.iparams   = top_global->ffparams.iparams;
2217     top->idef.fudgeQQ   = top_global->ffparams.fudgeQQ;
2218     top->idef.cmap_grid = top_global->ffparams.cmap_grid;
2219
2220     for (i = 0; i < F_NRE; i++)
2221     {
2222         top->idef.il[i].iatoms = nullptr;
2223         top->idef.il[i].nalloc = 0;
2224     }
2225     top->idef.ilsort   = ilsortUNKNOWN;
2226
2227     return top;
2228 }
2229
2230 void dd_init_local_state(gmx_domdec_t *dd,
2231                          t_state *state_global, t_state *state_local)
2232 {
2233     int buf[NITEM_DD_INIT_LOCAL_STATE];
2234
2235     if (DDMASTER(dd))
2236     {
2237         buf[0] = state_global->flags;
2238         buf[1] = state_global->ngtc;
2239         buf[2] = state_global->nnhpres;
2240         buf[3] = state_global->nhchainlength;
2241         buf[4] = state_global->dfhist ? state_global->dfhist->nlambda : 0;
2242     }
2243     dd_bcast(dd, NITEM_DD_INIT_LOCAL_STATE*sizeof(int), buf);
2244
2245     init_gtc_state(state_local, buf[1], buf[2], buf[3]);
2246     init_dfhist_state(state_local, buf[4]);
2247     state_local->flags = buf[0];
2248 }
2249
2250 /*! \brief Check if a link is stored in \p link between charge groups \p cg_gl and \p cg_gl_j and if not so, store a link */
2251 static void check_link(t_blocka *link, int cg_gl, int cg_gl_j)
2252 {
2253     int      k;
2254     gmx_bool bFound;
2255
2256     bFound = FALSE;
2257     for (k = link->index[cg_gl]; k < link->index[cg_gl+1]; k++)
2258     {
2259         GMX_RELEASE_ASSERT(link->a, "Inconsistent NULL pointer while making charge-group links");
2260         if (link->a[k] == cg_gl_j)
2261         {
2262             bFound = TRUE;
2263         }
2264     }
2265     if (!bFound)
2266     {
2267         GMX_RELEASE_ASSERT(link->a || link->index[cg_gl+1]+1 > link->nalloc_a,
2268                            "Inconsistent allocation of link");
2269         /* Add this charge group link */
2270         if (link->index[cg_gl+1]+1 > link->nalloc_a)
2271         {
2272             link->nalloc_a = over_alloc_large(link->index[cg_gl+1]+1);
2273             srenew(link->a, link->nalloc_a);
2274         }
2275         link->a[link->index[cg_gl+1]] = cg_gl_j;
2276         link->index[cg_gl+1]++;
2277     }
2278 }
2279
2280 /*! \brief Return a vector of the charge group index for all atoms */
2281 static std::vector<int> make_at2cg(const t_block &cgs)
2282 {
2283     std::vector<int> at2cg(cgs.index[cgs.nr]);
2284     for (int cg = 0; cg < cgs.nr; cg++)
2285     {
2286         for (int a = cgs.index[cg]; a < cgs.index[cg + 1]; a++)
2287         {
2288             at2cg[a] = cg;
2289         }
2290     }
2291
2292     return at2cg;
2293 }
2294
2295 t_blocka *make_charge_group_links(const gmx_mtop_t *mtop, gmx_domdec_t *dd,
2296                                   cginfo_mb_t *cginfo_mb)
2297 {
2298     gmx_bool            bExclRequired;
2299     reverse_ilist_t     ril, ril_intermol;
2300     t_blocka           *link;
2301     cginfo_mb_t        *cgi_mb;
2302
2303     /* For each charge group make a list of other charge groups
2304      * in the system that a linked to it via bonded interactions
2305      * which are also stored in reverse_top.
2306      */
2307
2308     bExclRequired = dd->reverse_top->bExclRequired;
2309
2310     if (mtop->bIntermolecularInteractions)
2311     {
2312         if (ncg_mtop(mtop) < mtop->natoms)
2313         {
2314             gmx_fatal(FARGS, "The combination of intermolecular interactions, charge groups and domain decomposition is not supported. Use cutoff-scheme=Verlet (which removes the charge groups) or run without domain decomposition.");
2315         }
2316
2317         t_atoms atoms;
2318
2319         atoms.nr   = mtop->natoms;
2320         atoms.atom = nullptr;
2321
2322         make_reverse_ilist(mtop->intermolecular_ilist, &atoms,
2323                            nullptr, FALSE, FALSE, FALSE, TRUE, &ril_intermol);
2324     }
2325
2326     snew(link, 1);
2327     snew(link->index, ncg_mtop(mtop)+1);
2328     link->nalloc_a = 0;
2329     link->a        = nullptr;
2330
2331     link->index[0] = 0;
2332     int cg_offset  = 0;
2333     int ncgi       = 0;
2334     for (size_t mb = 0; mb < mtop->molblock.size(); mb++)
2335     {
2336         const gmx_molblock_t &molb = mtop->molblock[mb];
2337         if (molb.nmol == 0)
2338         {
2339             continue;
2340         }
2341         const gmx_moltype_t &molt  = mtop->moltype[molb.type];
2342         const t_block       &cgs   = molt.cgs;
2343         const t_blocka      &excls = molt.excls;
2344         std::vector<int>     a2c   = make_at2cg(cgs);
2345         /* Make a reverse ilist in which the interactions are linked
2346          * to all atoms, not only the first atom as in gmx_reverse_top.
2347          * The constraints are discarded here.
2348          */
2349         make_reverse_ilist(molt.ilist, &molt.atoms,
2350                            nullptr, FALSE, FALSE, FALSE, TRUE, &ril);
2351
2352         cgi_mb = &cginfo_mb[mb];
2353
2354         int mol;
2355         for (mol = 0; mol < (mtop->bIntermolecularInteractions ? molb.nmol : 1); mol++)
2356         {
2357             for (int cg = 0; cg < cgs.nr; cg++)
2358             {
2359                 int cg_gl            = cg_offset + cg;
2360                 link->index[cg_gl+1] = link->index[cg_gl];
2361                 for (int a = cgs.index[cg]; a < cgs.index[cg + 1]; a++)
2362                 {
2363                     int i = ril.index[a];
2364                     while (i < ril.index[a+1])
2365                     {
2366                         int ftype = ril.il[i++];
2367                         int nral  = NRAL(ftype);
2368                         /* Skip the ifunc index */
2369                         i++;
2370                         for (int j = 0; j < nral; j++)
2371                         {
2372                             int aj = ril.il[i + j];
2373                             if (a2c[aj] != cg)
2374                             {
2375                                 check_link(link, cg_gl, cg_offset+a2c[aj]);
2376                             }
2377                         }
2378                         i += nral_rt(ftype);
2379                     }
2380                     if (bExclRequired)
2381                     {
2382                         /* Exclusions always go both ways */
2383                         for (int j = excls.index[a]; j < excls.index[a + 1]; j++)
2384                         {
2385                             int aj = excls.a[j];
2386                             if (a2c[aj] != cg)
2387                             {
2388                                 check_link(link, cg_gl, cg_offset+a2c[aj]);
2389                             }
2390                         }
2391                     }
2392
2393                     if (mtop->bIntermolecularInteractions)
2394                     {
2395                         int i = ril_intermol.index[a];
2396                         while (i < ril_intermol.index[a+1])
2397                         {
2398                             int ftype = ril_intermol.il[i++];
2399                             int nral  = NRAL(ftype);
2400                             /* Skip the ifunc index */
2401                             i++;
2402                             for (int j = 0; j < nral; j++)
2403                             {
2404                                 /* Here we assume we have no charge groups;
2405                                  * this has been checked above.
2406                                  */
2407                                 int aj = ril_intermol.il[i + j];
2408                                 check_link(link, cg_gl, aj);
2409                             }
2410                             i += nral_rt(ftype);
2411                         }
2412                     }
2413                 }
2414                 if (link->index[cg_gl+1] - link->index[cg_gl] > 0)
2415                 {
2416                     SET_CGINFO_BOND_INTER(cgi_mb->cginfo[cg]);
2417                     ncgi++;
2418                 }
2419             }
2420
2421             cg_offset += cgs.nr;
2422         }
2423         int nlink_mol = link->index[cg_offset] - link->index[cg_offset - cgs.nr];
2424
2425         destroy_reverse_ilist(&ril);
2426
2427         if (debug)
2428         {
2429             fprintf(debug, "molecule type '%s' %d cgs has %d cg links through bonded interac.\n", *molt.name, cgs.nr, nlink_mol);
2430         }
2431
2432         if (molb.nmol > mol)
2433         {
2434             /* Copy the data for the rest of the molecules in this block */
2435             link->nalloc_a += (molb.nmol - mol)*nlink_mol;
2436             srenew(link->a, link->nalloc_a);
2437             for (; mol < molb.nmol; mol++)
2438             {
2439                 for (int cg = 0; cg < cgs.nr; cg++)
2440                 {
2441                     int cg_gl              = cg_offset + cg;
2442                     link->index[cg_gl + 1] =
2443                         link->index[cg_gl + 1 - cgs.nr] + nlink_mol;
2444                     for (int j = link->index[cg_gl]; j < link->index[cg_gl+1]; j++)
2445                     {
2446                         link->a[j] = link->a[j - nlink_mol] + cgs.nr;
2447                     }
2448                     if (link->index[cg_gl+1] - link->index[cg_gl] > 0 &&
2449                         cg_gl - cgi_mb->cg_start < cgi_mb->cg_mod)
2450                     {
2451                         SET_CGINFO_BOND_INTER(cgi_mb->cginfo[cg_gl - cgi_mb->cg_start]);
2452                         ncgi++;
2453                     }
2454                 }
2455                 cg_offset += cgs.nr;
2456             }
2457         }
2458     }
2459
2460     if (mtop->bIntermolecularInteractions)
2461     {
2462         destroy_reverse_ilist(&ril_intermol);
2463     }
2464
2465     if (debug)
2466     {
2467         fprintf(debug, "Of the %d charge groups %d are linked via bonded interactions\n", ncg_mtop(mtop), ncgi);
2468     }
2469
2470     return link;
2471 }
2472
2473 typedef struct {
2474     real r2;
2475     int  ftype;
2476     int  a1;
2477     int  a2;
2478 } bonded_distance_t;
2479
2480 /*! \brief Compare distance^2 \p r2 against the distance in \p bd and if larger store it along with \p ftype and atom indices \p a1 and \p a2 */
2481 static void update_max_bonded_distance(real r2, int ftype, int a1, int a2,
2482                                        bonded_distance_t *bd)
2483 {
2484     if (r2 > bd->r2)
2485     {
2486         bd->r2    = r2;
2487         bd->ftype = ftype;
2488         bd->a1    = a1;
2489         bd->a2    = a2;
2490     }
2491 }
2492
2493 /*! \brief Set the distance, function type and atom indices for the longest distance between charge-groups of molecule type \p molt for two-body and multi-body bonded interactions */
2494 static void bonded_cg_distance_mol(const gmx_moltype_t *molt,
2495                                    const std::vector<int> &at2cg,
2496                                    gmx_bool bBCheck, gmx_bool bExcl, rvec *cg_cm,
2497                                    bonded_distance_t *bd_2b,
2498                                    bonded_distance_t *bd_mb)
2499 {
2500     for (int ftype = 0; ftype < F_NRE; ftype++)
2501     {
2502         if (dd_check_ftype(ftype, bBCheck, FALSE, FALSE))
2503         {
2504             const t_ilist *il   = &molt->ilist[ftype];
2505             int            nral = NRAL(ftype);
2506             if (nral > 1)
2507             {
2508                 for (int i = 0; i < il->nr; i += 1+nral)
2509                 {
2510                     for (int ai = 0; ai < nral; ai++)
2511                     {
2512                         int cgi = at2cg[il->iatoms[i+1+ai]];
2513                         for (int aj = ai + 1; aj < nral; aj++)
2514                         {
2515                             int cgj = at2cg[il->iatoms[i+1+aj]];
2516                             if (cgi != cgj)
2517                             {
2518                                 real rij2 = distance2(cg_cm[cgi], cg_cm[cgj]);
2519
2520                                 update_max_bonded_distance(rij2, ftype,
2521                                                            il->iatoms[i+1+ai],
2522                                                            il->iatoms[i+1+aj],
2523                                                            (nral == 2) ? bd_2b : bd_mb);
2524                             }
2525                         }
2526                     }
2527                 }
2528             }
2529         }
2530     }
2531     if (bExcl)
2532     {
2533         const t_blocka *excls = &molt->excls;
2534         for (int ai = 0; ai < excls->nr; ai++)
2535         {
2536             int cgi = at2cg[ai];
2537             for (int j = excls->index[ai]; j < excls->index[ai+1]; j++)
2538             {
2539                 int cgj = at2cg[excls->a[j]];
2540                 if (cgi != cgj)
2541                 {
2542                     real rij2 = distance2(cg_cm[cgi], cg_cm[cgj]);
2543
2544                     /* There is no function type for exclusions, use -1 */
2545                     update_max_bonded_distance(rij2, -1, ai, excls->a[j], bd_2b);
2546                 }
2547             }
2548         }
2549     }
2550 }
2551
2552 /*! \brief Set the distance, function type and atom indices for the longest atom distance involved in intermolecular interactions for two-body and multi-body bonded interactions */
2553 static void bonded_distance_intermol(const t_ilist *ilists_intermol,
2554                                      gmx_bool bBCheck,
2555                                      const rvec *x, int ePBC, const matrix box,
2556                                      bonded_distance_t *bd_2b,
2557                                      bonded_distance_t *bd_mb)
2558 {
2559     t_pbc pbc;
2560
2561     set_pbc(&pbc, ePBC, box);
2562
2563     for (int ftype = 0; ftype < F_NRE; ftype++)
2564     {
2565         if (dd_check_ftype(ftype, bBCheck, FALSE, FALSE))
2566         {
2567             const t_ilist *il   = &ilists_intermol[ftype];
2568             int            nral = NRAL(ftype);
2569
2570             /* No nral>1 check here, since intermol interactions always
2571              * have nral>=2 (and the code is also correct for nral=1).
2572              */
2573             for (int i = 0; i < il->nr; i += 1+nral)
2574             {
2575                 for (int ai = 0; ai < nral; ai++)
2576                 {
2577                     int atom_i = il->iatoms[i + 1 + ai];
2578
2579                     for (int aj = ai + 1; aj < nral; aj++)
2580                     {
2581                         rvec dx;
2582                         real rij2;
2583
2584                         int  atom_j = il->iatoms[i + 1 + aj];
2585
2586                         pbc_dx(&pbc, x[atom_i], x[atom_j], dx);
2587
2588                         rij2 = norm2(dx);
2589
2590                         update_max_bonded_distance(rij2, ftype,
2591                                                    atom_i, atom_j,
2592                                                    (nral == 2) ? bd_2b : bd_mb);
2593                     }
2594                 }
2595             }
2596         }
2597     }
2598 }
2599
2600 //! Returns whether \p molt has at least one virtual site
2601 static bool moltypeHasVsite(const gmx_moltype_t &molt)
2602 {
2603     bool hasVsite = false;
2604     for (int i = 0; i < F_NRE; i++)
2605     {
2606         if ((interaction_function[i].flags & IF_VSITE) &&
2607             molt.ilist[i].nr > 0)
2608         {
2609             hasVsite = true;
2610         }
2611     }
2612
2613     return hasVsite;
2614 }
2615
2616 //! Compute charge group centers of mass for molecule \p molt
2617 static void get_cgcm_mol(const gmx_moltype_t *molt,
2618                          const gmx_ffparams_t *ffparams,
2619                          int ePBC, t_graph *graph, const matrix box,
2620                          const rvec *x, rvec *xs, rvec *cg_cm)
2621 {
2622     int n, i;
2623
2624     if (ePBC != epbcNONE)
2625     {
2626         mk_mshift(nullptr, graph, ePBC, box, x);
2627
2628         shift_x(graph, box, x, xs);
2629         /* By doing an extra mk_mshift the molecules that are broken
2630          * because they were e.g. imported from another software
2631          * will be made whole again. Such are the healing powers
2632          * of GROMACS.
2633          */
2634         mk_mshift(nullptr, graph, ePBC, box, xs);
2635     }
2636     else
2637     {
2638         /* We copy the coordinates so the original coordinates remain
2639          * unchanged, just to be 100% sure that we do not affect
2640          * binary reproducibility of simulations.
2641          */
2642         n = molt->cgs.index[molt->cgs.nr];
2643         for (i = 0; i < n; i++)
2644         {
2645             copy_rvec(x[i], xs[i]);
2646         }
2647     }
2648
2649     if (moltypeHasVsite(*molt))
2650     {
2651         construct_vsites(nullptr, xs, 0.0, nullptr,
2652                          ffparams->iparams, molt->ilist,
2653                          epbcNONE, TRUE, nullptr, nullptr);
2654     }
2655
2656     calc_cgcm(nullptr, 0, molt->cgs.nr, &molt->cgs, xs, cg_cm);
2657 }
2658
2659 void dd_bonded_cg_distance(FILE *fplog,
2660                            const gmx_mtop_t *mtop,
2661                            const t_inputrec *ir,
2662                            const rvec *x, const matrix box,
2663                            gmx_bool bBCheck,
2664                            real *r_2b, real *r_mb)
2665 {
2666     gmx_bool           bExclRequired;
2667     int                at_offset;
2668     t_graph            graph;
2669     rvec              *xs, *cg_cm;
2670     bonded_distance_t  bd_2b = { 0, -1, -1, -1 };
2671     bonded_distance_t  bd_mb = { 0, -1, -1, -1 };
2672
2673     bExclRequired = inputrecExclForces(ir);
2674
2675     *r_2b     = 0;
2676     *r_mb     = 0;
2677     at_offset = 0;
2678     for (const gmx_molblock_t &molb : mtop->molblock)
2679     {
2680         const gmx_moltype_t &molt = mtop->moltype[molb.type];
2681         if (molt.cgs.nr == 1 || molb.nmol == 0)
2682         {
2683             at_offset += molb.nmol*molt.atoms.nr;
2684         }
2685         else
2686         {
2687             if (ir->ePBC != epbcNONE)
2688             {
2689                 mk_graph_ilist(nullptr, molt.ilist, 0, molt.atoms.nr, FALSE, FALSE,
2690                                &graph);
2691             }
2692
2693             std::vector<int> at2cg = make_at2cg(molt.cgs);
2694             snew(xs, molt.atoms.nr);
2695             snew(cg_cm, molt.cgs.nr);
2696             for (int mol = 0; mol < molb.nmol; mol++)
2697             {
2698                 get_cgcm_mol(&molt, &mtop->ffparams, ir->ePBC, &graph, box,
2699                              x+at_offset, xs, cg_cm);
2700
2701                 bonded_distance_t bd_mol_2b = { 0, -1, -1, -1 };
2702                 bonded_distance_t bd_mol_mb = { 0, -1, -1, -1 };
2703
2704                 bonded_cg_distance_mol(&molt, at2cg, bBCheck, bExclRequired, cg_cm,
2705                                        &bd_mol_2b, &bd_mol_mb);
2706
2707                 /* Process the mol data adding the atom index offset */
2708                 update_max_bonded_distance(bd_mol_2b.r2, bd_mol_2b.ftype,
2709                                            at_offset + bd_mol_2b.a1,
2710                                            at_offset + bd_mol_2b.a2,
2711                                            &bd_2b);
2712                 update_max_bonded_distance(bd_mol_mb.r2, bd_mol_mb.ftype,
2713                                            at_offset + bd_mol_mb.a1,
2714                                            at_offset + bd_mol_mb.a2,
2715                                            &bd_mb);
2716
2717                 at_offset += molt.atoms.nr;
2718             }
2719             sfree(cg_cm);
2720             sfree(xs);
2721             if (ir->ePBC != epbcNONE)
2722             {
2723                 done_graph(&graph);
2724             }
2725         }
2726     }
2727
2728     if (mtop->bIntermolecularInteractions)
2729     {
2730         if (ncg_mtop(mtop) < mtop->natoms)
2731         {
2732             gmx_fatal(FARGS, "The combination of intermolecular interactions, charge groups and domain decomposition is not supported. Use cutoff-scheme=Verlet (which removes the charge groups) or run without domain decomposition.");
2733         }
2734
2735         bonded_distance_intermol(mtop->intermolecular_ilist,
2736                                  bBCheck,
2737                                  x, ir->ePBC, box,
2738                                  &bd_2b, &bd_mb);
2739     }
2740
2741     *r_2b = sqrt(bd_2b.r2);
2742     *r_mb = sqrt(bd_mb.r2);
2743
2744     if (fplog && (*r_2b > 0 || *r_mb > 0))
2745     {
2746         fprintf(fplog,
2747                 "Initial maximum inter charge-group distances:\n");
2748         if (*r_2b > 0)
2749         {
2750             fprintf(fplog,
2751                     "    two-body bonded interactions: %5.3f nm, %s, atoms %d %d\n",
2752                     *r_2b, (bd_2b.ftype >= 0) ? interaction_function[bd_2b.ftype].longname : "Exclusion",
2753                     bd_2b.a1 + 1, bd_2b.a2 + 1);
2754         }
2755         if (*r_mb > 0)
2756         {
2757             fprintf(fplog,
2758                     "  multi-body bonded interactions: %5.3f nm, %s, atoms %d %d\n",
2759                     *r_mb, interaction_function[bd_mb.ftype].longname,
2760                     bd_mb.a1 + 1, bd_mb.a2 + 1);
2761         }
2762     }
2763 }