Remove commrec from set_ddbox()
[gromacs.git] / src / gromacs / domdec / domdec.cpp
blobbf55c4114177be17eabe2d0852f3c6b2a81c8bd0
1 /*
2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2005,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.
9 * GROMACS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1
12 * of the License, or (at your option) any later version.
14 * GROMACS is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with GROMACS; if not, see
21 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * If you want to redistribute modifications to GROMACS, please
25 * consider that scientific software is very special. Version
26 * control is crucial - bugs must be traceable. We will be happy to
27 * consider code for inclusion in the official distribution, but
28 * derived work must not be called official GROMACS. Details are found
29 * in the README & COPYING files - if they are missing, get the
30 * official version at http://www.gromacs.org.
32 * To help us fund GROMACS development, we humbly ask that you cite
33 * the research papers on the package. Check out http://www.gromacs.org.
36 #include "gmxpre.h"
38 #include "domdec.h"
40 #include "config.h"
42 #include <assert.h>
43 #include <limits.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
48 #include <cmath>
50 #include <algorithm>
52 #include "gromacs/domdec/domdec_network.h"
53 #include "gromacs/domdec/ga2la.h"
54 #include "gromacs/ewald/pme.h"
55 #include "gromacs/fileio/gmxfio.h"
56 #include "gromacs/fileio/pdbio.h"
57 #include "gromacs/gmxlib/chargegroup.h"
58 #include "gromacs/gmxlib/network.h"
59 #include "gromacs/gmxlib/nrnb.h"
60 #include "gromacs/gpu_utils/gpu_utils.h"
61 #include "gromacs/hardware/hw_info.h"
62 #include "gromacs/imd/imd.h"
63 #include "gromacs/listed-forces/manage-threading.h"
64 #include "gromacs/math/functions.h"
65 #include "gromacs/math/vec.h"
66 #include "gromacs/math/vectypes.h"
67 #include "gromacs/mdlib/constr.h"
68 #include "gromacs/mdlib/constraintrange.h"
69 #include "gromacs/mdlib/force.h"
70 #include "gromacs/mdlib/forcerec.h"
71 #include "gromacs/mdlib/gmx_omp_nthreads.h"
72 #include "gromacs/mdlib/lincs.h"
73 #include "gromacs/mdlib/mdatoms.h"
74 #include "gromacs/mdlib/mdrun.h"
75 #include "gromacs/mdlib/mdsetup.h"
76 #include "gromacs/mdlib/nb_verlet.h"
77 #include "gromacs/mdlib/nbnxn_grid.h"
78 #include "gromacs/mdlib/nsgrid.h"
79 #include "gromacs/mdlib/vsite.h"
80 #include "gromacs/mdtypes/commrec.h"
81 #include "gromacs/mdtypes/df_history.h"
82 #include "gromacs/mdtypes/forcerec.h"
83 #include "gromacs/mdtypes/inputrec.h"
84 #include "gromacs/mdtypes/md_enums.h"
85 #include "gromacs/mdtypes/mdatom.h"
86 #include "gromacs/mdtypes/nblist.h"
87 #include "gromacs/mdtypes/state.h"
88 #include "gromacs/pbcutil/ishift.h"
89 #include "gromacs/pbcutil/pbc.h"
90 #include "gromacs/pulling/pull.h"
91 #include "gromacs/pulling/pull_rotation.h"
92 #include "gromacs/swap/swapcoords.h"
93 #include "gromacs/timing/wallcycle.h"
94 #include "gromacs/topology/block.h"
95 #include "gromacs/topology/idef.h"
96 #include "gromacs/topology/ifunc.h"
97 #include "gromacs/topology/mtop_lookup.h"
98 #include "gromacs/topology/mtop_util.h"
99 #include "gromacs/topology/topology.h"
100 #include "gromacs/utility/basedefinitions.h"
101 #include "gromacs/utility/basenetwork.h"
102 #include "gromacs/utility/cstringutil.h"
103 #include "gromacs/utility/exceptions.h"
104 #include "gromacs/utility/fatalerror.h"
105 #include "gromacs/utility/gmxmpi.h"
106 #include "gromacs/utility/qsort_threadsafe.h"
107 #include "gromacs/utility/real.h"
108 #include "gromacs/utility/smalloc.h"
109 #include "gromacs/utility/stringutil.h"
111 #include "domdec_constraints.h"
112 #include "domdec_internal.h"
113 #include "domdec_vsite.h"
115 #define DDRANK(dd, rank) (rank)
116 #define DDMASTERRANK(dd) (dd->masterrank)
118 struct gmx_domdec_master_t
120 /* The cell boundaries */
121 real **cell_x;
122 /* The global charge group division */
123 int *ncg; /* Number of home charge groups for each node */
124 int *index; /* Index of nnodes+1 into cg */
125 int *cg; /* Global charge group index */
126 int *nat; /* Number of home atoms for each node. */
127 int *ibuf; /* Buffer for communication */
128 rvec *vbuf; /* Buffer for state scattering and gathering */
131 #define DD_NLOAD_MAX 9
133 const char *edlbs_names[edlbsNR] = { "off", "auto", "locked", "on", "on" };
135 /* The size per charge group of the cggl_flag buffer in gmx_domdec_comm_t */
136 #define DD_CGIBS 2
138 /* The flags for the cggl_flag buffer in gmx_domdec_comm_t */
139 #define DD_FLAG_NRCG 65535
140 #define DD_FLAG_FW(d) (1<<(16+(d)*2))
141 #define DD_FLAG_BW(d) (1<<(16+(d)*2+1))
143 /* The DD zone order */
144 static const ivec dd_zo[DD_MAXZONE] =
145 {{0, 0, 0}, {1, 0, 0}, {1, 1, 0}, {0, 1, 0}, {0, 1, 1}, {0, 0, 1}, {1, 0, 1}, {1, 1, 1}};
147 /* The non-bonded zone-pair setup for domain decomposition
148 * The first number is the i-zone, the second number the first j-zone seen by
149 * this i-zone, the third number the last+1 j-zone seen by this i-zone.
150 * As is, this is for 3D decomposition, where there are 4 i-zones.
151 * With 2D decomposition use only the first 2 i-zones and a last+1 j-zone of 4.
152 * With 1D decomposition use only the first i-zone and a last+1 j-zone of 2.
154 static const int
155 ddNonbondedZonePairRanges[DD_MAXIZONE][3] = {{0, 0, 8},
156 {1, 3, 6},
157 {2, 5, 6},
158 {3, 5, 7}};
160 /* Factors used to avoid problems due to rounding issues */
161 #define DD_CELL_MARGIN 1.0001
162 #define DD_CELL_MARGIN2 1.00005
163 /* Factor to account for pressure scaling during nstlist steps */
164 #define DD_PRES_SCALE_MARGIN 1.02
166 /* Turn on DLB when the load imbalance causes this amount of total loss.
167 * There is a bit of overhead with DLB and it's difficult to achieve
168 * a load imbalance of less than 2% with DLB.
170 #define DD_PERF_LOSS_DLB_ON 0.02
172 /* Warn about imbalance due to PP or PP/PME load imbalance at this loss */
173 #define DD_PERF_LOSS_WARN 0.05
175 #define DD_CELL_F_SIZE(dd, di) ((dd)->nc[(dd)->dim[(di)]]+1+(di)*2+1+(di))
177 /* Use separate MPI send and receive commands
178 * when nnodes <= GMX_DD_NNODES_SENDRECV.
179 * This saves memory (and some copying for small nnodes).
180 * For high parallelization scatter and gather calls are used.
182 #define GMX_DD_NNODES_SENDRECV 4
185 /* We check if to turn on DLB at the first and every 100 DD partitionings.
186 * With large imbalance DLB will turn on at the first step, so we can
187 * make the interval so large that the MPI overhead of the check is negligible.
189 static const int c_checkTurnDlbOnInterval = 100;
190 /* We need to check if DLB results in worse performance and then turn it off.
191 * We check this more often then for turning DLB on, because the DLB can scale
192 * the domains very rapidly, so if unlucky the load imbalance can go up quickly
193 * and furthermore, we are already synchronizing often with DLB, so
194 * the overhead of the MPI Bcast is not that high.
196 static const int c_checkTurnDlbOffInterval = 20;
198 /* Forward declaration */
199 static void dd_dlb_set_should_check_whether_to_turn_dlb_on(gmx_domdec_t *dd, gmx_bool bValue);
203 #define dd_index(n,i) ((((i)[ZZ]*(n)[YY] + (i)[YY])*(n)[XX]) + (i)[XX])
205 static void index2xyz(ivec nc,int ind,ivec xyz)
207 xyz[XX] = ind % nc[XX];
208 xyz[YY] = (ind / nc[XX]) % nc[YY];
209 xyz[ZZ] = ind / (nc[YY]*nc[XX]);
213 /* This order is required to minimize the coordinate communication in PME
214 * which uses decomposition in the x direction.
216 #define dd_index(n, i) ((((i)[XX]*(n)[YY] + (i)[YY])*(n)[ZZ]) + (i)[ZZ])
218 static void ddindex2xyz(ivec nc, int ind, ivec xyz)
220 xyz[XX] = ind / (nc[YY]*nc[ZZ]);
221 xyz[YY] = (ind / nc[ZZ]) % nc[YY];
222 xyz[ZZ] = ind % nc[ZZ];
225 static int ddcoord2ddnodeid(gmx_domdec_t *dd, ivec c)
227 int ddindex;
228 int ddnodeid = -1;
230 ddindex = dd_index(dd->nc, c);
231 if (dd->comm->bCartesianPP_PME)
233 ddnodeid = dd->comm->ddindex2ddnodeid[ddindex];
235 else if (dd->comm->bCartesianPP)
237 #if GMX_MPI
238 MPI_Cart_rank(dd->mpi_comm_all, c, &ddnodeid);
239 #endif
241 else
243 ddnodeid = ddindex;
246 return ddnodeid;
249 static gmx_bool dynamic_dd_box(const gmx_ddbox_t *ddbox, const t_inputrec *ir)
251 return (ddbox->nboundeddim < DIM || inputrecDynamicBox(ir));
254 int ddglatnr(const gmx_domdec_t *dd, int i)
256 int atnr;
258 if (dd == nullptr)
260 atnr = i + 1;
262 else
264 if (i >= dd->comm->nat[ddnatNR-1])
266 gmx_fatal(FARGS, "glatnr called with %d, which is larger than the local number of atoms (%d)", i, dd->comm->nat[ddnatNR-1]);
268 atnr = dd->gatindex[i] + 1;
271 return atnr;
274 t_block *dd_charge_groups_global(gmx_domdec_t *dd)
276 return &dd->comm->cgs_gl;
279 /*! \brief Returns true if the DLB state indicates that the balancer is on. */
280 static bool isDlbOn(const gmx_domdec_comm_t *comm)
282 return (comm->dlbState == edlbsOnCanTurnOff ||
283 comm->dlbState == edlbsOnUser);
285 /*! \brief Returns true if the DLB state indicates that the balancer is off/disabled.
287 static bool isDlbDisabled(const gmx_domdec_comm_t *comm)
289 return (comm->dlbState == edlbsOffUser ||
290 comm->dlbState == edlbsOffForever);
293 static void vec_rvec_init(vec_rvec_t *v)
295 v->nalloc = 0;
296 v->v = nullptr;
299 static void vec_rvec_check_alloc(vec_rvec_t *v, int n)
301 if (n > v->nalloc)
303 v->nalloc = over_alloc_dd(n);
304 srenew(v->v, v->nalloc);
308 void dd_store_state(gmx_domdec_t *dd, t_state *state)
310 int i;
312 if (state->ddp_count != dd->ddp_count)
314 gmx_incons("The MD state does not match the domain decomposition state");
317 state->cg_gl.resize(dd->ncg_home);
318 for (i = 0; i < dd->ncg_home; i++)
320 state->cg_gl[i] = dd->index_gl[i];
323 state->ddp_count_cg_gl = dd->ddp_count;
326 gmx_domdec_zones_t *domdec_zones(gmx_domdec_t *dd)
328 return &dd->comm->zones;
331 void dd_get_ns_ranges(const gmx_domdec_t *dd, int icg,
332 int *jcg0, int *jcg1, ivec shift0, ivec shift1)
334 gmx_domdec_zones_t *zones;
335 int izone, d, dim;
337 zones = &dd->comm->zones;
339 izone = 0;
340 while (icg >= zones->izone[izone].cg1)
342 izone++;
345 if (izone == 0)
347 *jcg0 = icg;
349 else if (izone < zones->nizone)
351 *jcg0 = zones->izone[izone].jcg0;
353 else
355 gmx_fatal(FARGS, "DD icg %d out of range: izone (%d) >= nizone (%d)",
356 icg, izone, zones->nizone);
359 *jcg1 = zones->izone[izone].jcg1;
361 for (d = 0; d < dd->ndim; d++)
363 dim = dd->dim[d];
364 shift0[dim] = zones->izone[izone].shift0[dim];
365 shift1[dim] = zones->izone[izone].shift1[dim];
366 if (dd->comm->tric_dir[dim] || (isDlbOn(dd->comm) && d > 0))
368 /* A conservative approach, this can be optimized */
369 shift0[dim] -= 1;
370 shift1[dim] += 1;
375 int dd_natoms_mdatoms(const gmx_domdec_t *dd)
377 /* We currently set mdatoms entries for all atoms:
378 * local + non-local + communicated for vsite + constraints
381 return dd->comm->nat[ddnatNR - 1];
384 int dd_natoms_vsite(const gmx_domdec_t *dd)
386 return dd->comm->nat[ddnatVSITE];
389 void dd_get_constraint_range(const gmx_domdec_t *dd, int *at_start, int *at_end)
391 *at_start = dd->comm->nat[ddnatCON-1];
392 *at_end = dd->comm->nat[ddnatCON];
395 void dd_move_x(gmx_domdec_t *dd, matrix box, rvec x[], gmx_wallcycle *wcycle)
397 wallcycle_start(wcycle, ewcMOVEX);
399 int nzone, nat_tot, n, d, p, i, j, at0, at1, zone;
400 int *index, *cgindex;
401 gmx_domdec_comm_t *comm;
402 gmx_domdec_comm_dim_t *cd;
403 gmx_domdec_ind_t *ind;
404 rvec shift = {0, 0, 0}, *buf, *rbuf;
405 gmx_bool bPBC, bScrew;
407 comm = dd->comm;
409 cgindex = dd->cgindex;
411 buf = comm->vbuf.v;
413 nzone = 1;
414 nat_tot = dd->nat_home;
415 for (d = 0; d < dd->ndim; d++)
417 bPBC = (dd->ci[dd->dim[d]] == 0);
418 bScrew = (bPBC && dd->bScrewPBC && dd->dim[d] == XX);
419 if (bPBC)
421 copy_rvec(box[dd->dim[d]], shift);
423 cd = &comm->cd[d];
424 for (p = 0; p < cd->np; p++)
426 ind = &cd->ind[p];
427 index = ind->index;
428 n = 0;
429 if (!bPBC)
431 for (i = 0; i < ind->nsend[nzone]; i++)
433 at0 = cgindex[index[i]];
434 at1 = cgindex[index[i]+1];
435 for (j = at0; j < at1; j++)
437 copy_rvec(x[j], buf[n]);
438 n++;
442 else if (!bScrew)
444 for (i = 0; i < ind->nsend[nzone]; i++)
446 at0 = cgindex[index[i]];
447 at1 = cgindex[index[i]+1];
448 for (j = at0; j < at1; j++)
450 /* We need to shift the coordinates */
451 rvec_add(x[j], shift, buf[n]);
452 n++;
456 else
458 for (i = 0; i < ind->nsend[nzone]; i++)
460 at0 = cgindex[index[i]];
461 at1 = cgindex[index[i]+1];
462 for (j = at0; j < at1; j++)
464 /* Shift x */
465 buf[n][XX] = x[j][XX] + shift[XX];
466 /* Rotate y and z.
467 * This operation requires a special shift force
468 * treatment, which is performed in calc_vir.
470 buf[n][YY] = box[YY][YY] - x[j][YY];
471 buf[n][ZZ] = box[ZZ][ZZ] - x[j][ZZ];
472 n++;
477 if (cd->bInPlace)
479 rbuf = x + nat_tot;
481 else
483 rbuf = comm->vbuf2.v;
485 /* Send and receive the coordinates */
486 dd_sendrecv_rvec(dd, d, dddirBackward,
487 buf, ind->nsend[nzone+1],
488 rbuf, ind->nrecv[nzone+1]);
489 if (!cd->bInPlace)
491 j = 0;
492 for (zone = 0; zone < nzone; zone++)
494 for (i = ind->cell2at0[zone]; i < ind->cell2at1[zone]; i++)
496 copy_rvec(rbuf[j], x[i]);
497 j++;
501 nat_tot += ind->nrecv[nzone+1];
503 nzone += nzone;
506 wallcycle_stop(wcycle, ewcMOVEX);
509 void dd_move_f(gmx_domdec_t *dd, rvec f[], rvec *fshift, gmx_wallcycle *wcycle)
511 wallcycle_start(wcycle, ewcMOVEF);
513 int nzone, nat_tot, n, d, p, i, j, at0, at1, zone;
514 int *index, *cgindex;
515 gmx_domdec_comm_t *comm;
516 gmx_domdec_comm_dim_t *cd;
517 gmx_domdec_ind_t *ind;
518 rvec *buf, *sbuf;
519 ivec vis;
520 int is;
521 gmx_bool bShiftForcesNeedPbc, bScrew;
523 comm = dd->comm;
525 cgindex = dd->cgindex;
527 buf = comm->vbuf.v;
529 nzone = comm->zones.n/2;
530 nat_tot = dd->nat_tot;
531 for (d = dd->ndim-1; d >= 0; d--)
533 /* Only forces in domains near the PBC boundaries need to
534 consider PBC in the treatment of fshift */
535 bShiftForcesNeedPbc = (dd->ci[dd->dim[d]] == 0);
536 bScrew = (bShiftForcesNeedPbc && dd->bScrewPBC && dd->dim[d] == XX);
537 if (fshift == nullptr && !bScrew)
539 bShiftForcesNeedPbc = FALSE;
541 /* Determine which shift vector we need */
542 clear_ivec(vis);
543 vis[dd->dim[d]] = 1;
544 is = IVEC2IS(vis);
546 cd = &comm->cd[d];
547 for (p = cd->np-1; p >= 0; p--)
549 ind = &cd->ind[p];
550 nat_tot -= ind->nrecv[nzone+1];
551 if (cd->bInPlace)
553 sbuf = f + nat_tot;
555 else
557 sbuf = comm->vbuf2.v;
558 j = 0;
559 for (zone = 0; zone < nzone; zone++)
561 for (i = ind->cell2at0[zone]; i < ind->cell2at1[zone]; i++)
563 copy_rvec(f[i], sbuf[j]);
564 j++;
568 /* Communicate the forces */
569 dd_sendrecv_rvec(dd, d, dddirForward,
570 sbuf, ind->nrecv[nzone+1],
571 buf, ind->nsend[nzone+1]);
572 index = ind->index;
573 /* Add the received forces */
574 n = 0;
575 if (!bShiftForcesNeedPbc)
577 for (i = 0; i < ind->nsend[nzone]; i++)
579 at0 = cgindex[index[i]];
580 at1 = cgindex[index[i]+1];
581 for (j = at0; j < at1; j++)
583 rvec_inc(f[j], buf[n]);
584 n++;
588 else if (!bScrew)
590 /* fshift should always be defined if this function is
591 * called when bShiftForcesNeedPbc is true */
592 assert(NULL != fshift);
593 for (i = 0; i < ind->nsend[nzone]; i++)
595 at0 = cgindex[index[i]];
596 at1 = cgindex[index[i]+1];
597 for (j = at0; j < at1; j++)
599 rvec_inc(f[j], buf[n]);
600 /* Add this force to the shift force */
601 rvec_inc(fshift[is], buf[n]);
602 n++;
606 else
608 for (i = 0; i < ind->nsend[nzone]; i++)
610 at0 = cgindex[index[i]];
611 at1 = cgindex[index[i]+1];
612 for (j = at0; j < at1; j++)
614 /* Rotate the force */
615 f[j][XX] += buf[n][XX];
616 f[j][YY] -= buf[n][YY];
617 f[j][ZZ] -= buf[n][ZZ];
618 if (fshift)
620 /* Add this force to the shift force */
621 rvec_inc(fshift[is], buf[n]);
623 n++;
628 nzone /= 2;
630 wallcycle_stop(wcycle, ewcMOVEF);
633 void dd_atom_spread_real(gmx_domdec_t *dd, real v[])
635 int nzone, nat_tot, n, d, p, i, j, at0, at1, zone;
636 int *index, *cgindex;
637 gmx_domdec_comm_t *comm;
638 gmx_domdec_comm_dim_t *cd;
639 gmx_domdec_ind_t *ind;
640 real *buf, *rbuf;
642 comm = dd->comm;
644 cgindex = dd->cgindex;
646 buf = &comm->vbuf.v[0][0];
648 nzone = 1;
649 nat_tot = dd->nat_home;
650 for (d = 0; d < dd->ndim; d++)
652 cd = &comm->cd[d];
653 for (p = 0; p < cd->np; p++)
655 ind = &cd->ind[p];
656 index = ind->index;
657 n = 0;
658 for (i = 0; i < ind->nsend[nzone]; i++)
660 at0 = cgindex[index[i]];
661 at1 = cgindex[index[i]+1];
662 for (j = at0; j < at1; j++)
664 buf[n] = v[j];
665 n++;
669 if (cd->bInPlace)
671 rbuf = v + nat_tot;
673 else
675 rbuf = &comm->vbuf2.v[0][0];
677 /* Send and receive the coordinates */
678 dd_sendrecv_real(dd, d, dddirBackward,
679 buf, ind->nsend[nzone+1],
680 rbuf, ind->nrecv[nzone+1]);
681 if (!cd->bInPlace)
683 j = 0;
684 for (zone = 0; zone < nzone; zone++)
686 for (i = ind->cell2at0[zone]; i < ind->cell2at1[zone]; i++)
688 v[i] = rbuf[j];
689 j++;
693 nat_tot += ind->nrecv[nzone+1];
695 nzone += nzone;
699 void dd_atom_sum_real(gmx_domdec_t *dd, real v[])
701 int nzone, nat_tot, n, d, p, i, j, at0, at1, zone;
702 int *index, *cgindex;
703 gmx_domdec_comm_t *comm;
704 gmx_domdec_comm_dim_t *cd;
705 gmx_domdec_ind_t *ind;
706 real *buf, *sbuf;
708 comm = dd->comm;
710 cgindex = dd->cgindex;
712 buf = &comm->vbuf.v[0][0];
714 nzone = comm->zones.n/2;
715 nat_tot = dd->nat_tot;
716 for (d = dd->ndim-1; d >= 0; d--)
718 cd = &comm->cd[d];
719 for (p = cd->np-1; p >= 0; p--)
721 ind = &cd->ind[p];
722 nat_tot -= ind->nrecv[nzone+1];
723 if (cd->bInPlace)
725 sbuf = v + nat_tot;
727 else
729 sbuf = &comm->vbuf2.v[0][0];
730 j = 0;
731 for (zone = 0; zone < nzone; zone++)
733 for (i = ind->cell2at0[zone]; i < ind->cell2at1[zone]; i++)
735 sbuf[j] = v[i];
736 j++;
740 /* Communicate the forces */
741 dd_sendrecv_real(dd, d, dddirForward,
742 sbuf, ind->nrecv[nzone+1],
743 buf, ind->nsend[nzone+1]);
744 index = ind->index;
745 /* Add the received forces */
746 n = 0;
747 for (i = 0; i < ind->nsend[nzone]; i++)
749 at0 = cgindex[index[i]];
750 at1 = cgindex[index[i]+1];
751 for (j = at0; j < at1; j++)
753 v[j] += buf[n];
754 n++;
758 nzone /= 2;
762 static void print_ddzone(FILE *fp, int d, int i, int j, gmx_ddzone_t *zone)
764 fprintf(fp, "zone d0 %d d1 %d d2 %d min0 %6.3f max1 %6.3f mch0 %6.3f mch1 %6.3f p1_0 %6.3f p1_1 %6.3f\n",
765 d, i, j,
766 zone->min0, zone->max1,
767 zone->mch0, zone->mch0,
768 zone->p1_0, zone->p1_1);
772 #define DDZONECOMM_MAXZONE 5
773 #define DDZONECOMM_BUFSIZE 3
775 static void dd_sendrecv_ddzone(const gmx_domdec_t *dd,
776 int ddimind, int direction,
777 gmx_ddzone_t *buf_s, int n_s,
778 gmx_ddzone_t *buf_r, int n_r)
780 #define ZBS DDZONECOMM_BUFSIZE
781 rvec vbuf_s[DDZONECOMM_MAXZONE*ZBS];
782 rvec vbuf_r[DDZONECOMM_MAXZONE*ZBS];
783 int i;
785 for (i = 0; i < n_s; i++)
787 vbuf_s[i*ZBS ][0] = buf_s[i].min0;
788 vbuf_s[i*ZBS ][1] = buf_s[i].max1;
789 vbuf_s[i*ZBS ][2] = buf_s[i].min1;
790 vbuf_s[i*ZBS+1][0] = buf_s[i].mch0;
791 vbuf_s[i*ZBS+1][1] = buf_s[i].mch1;
792 vbuf_s[i*ZBS+1][2] = 0;
793 vbuf_s[i*ZBS+2][0] = buf_s[i].p1_0;
794 vbuf_s[i*ZBS+2][1] = buf_s[i].p1_1;
795 vbuf_s[i*ZBS+2][2] = 0;
798 dd_sendrecv_rvec(dd, ddimind, direction,
799 vbuf_s, n_s*ZBS,
800 vbuf_r, n_r*ZBS);
802 for (i = 0; i < n_r; i++)
804 buf_r[i].min0 = vbuf_r[i*ZBS ][0];
805 buf_r[i].max1 = vbuf_r[i*ZBS ][1];
806 buf_r[i].min1 = vbuf_r[i*ZBS ][2];
807 buf_r[i].mch0 = vbuf_r[i*ZBS+1][0];
808 buf_r[i].mch1 = vbuf_r[i*ZBS+1][1];
809 buf_r[i].p1_0 = vbuf_r[i*ZBS+2][0];
810 buf_r[i].p1_1 = vbuf_r[i*ZBS+2][1];
813 #undef ZBS
816 static void dd_move_cellx(gmx_domdec_t *dd, gmx_ddbox_t *ddbox,
817 rvec cell_ns_x0, rvec cell_ns_x1)
819 int d, d1, dim, pos, buf_size, i, j, p, npulse, npulse_min;
820 gmx_ddzone_t *zp;
821 gmx_ddzone_t buf_s[DDZONECOMM_MAXZONE];
822 gmx_ddzone_t buf_r[DDZONECOMM_MAXZONE];
823 gmx_ddzone_t buf_e[DDZONECOMM_MAXZONE];
824 rvec extr_s[2], extr_r[2];
825 rvec dh;
826 real dist_d, c = 0, det;
827 gmx_domdec_comm_t *comm;
828 gmx_bool bPBC, bUse;
830 comm = dd->comm;
832 for (d = 1; d < dd->ndim; d++)
834 dim = dd->dim[d];
835 zp = (d == 1) ? &comm->zone_d1[0] : &comm->zone_d2[0][0];
836 zp->min0 = cell_ns_x0[dim];
837 zp->max1 = cell_ns_x1[dim];
838 zp->min1 = cell_ns_x1[dim];
839 zp->mch0 = cell_ns_x0[dim];
840 zp->mch1 = cell_ns_x1[dim];
841 zp->p1_0 = cell_ns_x0[dim];
842 zp->p1_1 = cell_ns_x1[dim];
845 for (d = dd->ndim-2; d >= 0; d--)
847 dim = dd->dim[d];
848 bPBC = (dim < ddbox->npbcdim);
850 /* Use an rvec to store two reals */
851 extr_s[d][0] = comm->cell_f0[d+1];
852 extr_s[d][1] = comm->cell_f1[d+1];
853 extr_s[d][2] = comm->cell_f1[d+1];
855 pos = 0;
856 /* Store the extremes in the backward sending buffer,
857 * so the get updated separately from the forward communication.
859 for (d1 = d; d1 < dd->ndim-1; d1++)
861 /* We invert the order to be able to use the same loop for buf_e */
862 buf_s[pos].min0 = extr_s[d1][1];
863 buf_s[pos].max1 = extr_s[d1][0];
864 buf_s[pos].min1 = extr_s[d1][2];
865 buf_s[pos].mch0 = 0;
866 buf_s[pos].mch1 = 0;
867 /* Store the cell corner of the dimension we communicate along */
868 buf_s[pos].p1_0 = comm->cell_x0[dim];
869 buf_s[pos].p1_1 = 0;
870 pos++;
873 buf_s[pos] = (dd->ndim == 2) ? comm->zone_d1[0] : comm->zone_d2[0][0];
874 pos++;
876 if (dd->ndim == 3 && d == 0)
878 buf_s[pos] = comm->zone_d2[0][1];
879 pos++;
880 buf_s[pos] = comm->zone_d1[0];
881 pos++;
884 /* We only need to communicate the extremes
885 * in the forward direction
887 npulse = comm->cd[d].np;
888 if (bPBC)
890 /* Take the minimum to avoid double communication */
891 npulse_min = std::min(npulse, dd->nc[dim]-1-npulse);
893 else
895 /* Without PBC we should really not communicate over
896 * the boundaries, but implementing that complicates
897 * the communication setup and therefore we simply
898 * do all communication, but ignore some data.
900 npulse_min = npulse;
902 for (p = 0; p < npulse_min; p++)
904 /* Communicate the extremes forward */
905 bUse = (bPBC || dd->ci[dim] > 0);
907 dd_sendrecv_rvec(dd, d, dddirForward,
908 extr_s+d, dd->ndim-d-1,
909 extr_r+d, dd->ndim-d-1);
911 if (bUse)
913 for (d1 = d; d1 < dd->ndim-1; d1++)
915 extr_s[d1][0] = std::max(extr_s[d1][0], extr_r[d1][0]);
916 extr_s[d1][1] = std::min(extr_s[d1][1], extr_r[d1][1]);
917 extr_s[d1][2] = std::min(extr_s[d1][2], extr_r[d1][2]);
922 buf_size = pos;
923 for (p = 0; p < npulse; p++)
925 /* Communicate all the zone information backward */
926 bUse = (bPBC || dd->ci[dim] < dd->nc[dim] - 1);
928 dd_sendrecv_ddzone(dd, d, dddirBackward,
929 buf_s, buf_size,
930 buf_r, buf_size);
932 clear_rvec(dh);
933 if (p > 0)
935 for (d1 = d+1; d1 < dd->ndim; d1++)
937 /* Determine the decrease of maximum required
938 * communication height along d1 due to the distance along d,
939 * this avoids a lot of useless atom communication.
941 dist_d = comm->cell_x1[dim] - buf_r[0].p1_0;
943 if (ddbox->tric_dir[dim])
945 /* c is the off-diagonal coupling between the cell planes
946 * along directions d and d1.
948 c = ddbox->v[dim][dd->dim[d1]][dim];
950 else
952 c = 0;
954 det = (1 + c*c)*comm->cutoff*comm->cutoff - dist_d*dist_d;
955 if (det > 0)
957 dh[d1] = comm->cutoff - (c*dist_d + std::sqrt(det))/(1 + c*c);
959 else
961 /* A negative value signals out of range */
962 dh[d1] = -1;
967 /* Accumulate the extremes over all pulses */
968 for (i = 0; i < buf_size; i++)
970 if (p == 0)
972 buf_e[i] = buf_r[i];
974 else
976 if (bUse)
978 buf_e[i].min0 = std::min(buf_e[i].min0, buf_r[i].min0);
979 buf_e[i].max1 = std::max(buf_e[i].max1, buf_r[i].max1);
980 buf_e[i].min1 = std::min(buf_e[i].min1, buf_r[i].min1);
983 if (dd->ndim == 3 && d == 0 && i == buf_size - 1)
985 d1 = 1;
987 else
989 d1 = d + 1;
991 if (bUse && dh[d1] >= 0)
993 buf_e[i].mch0 = std::max(buf_e[i].mch0, buf_r[i].mch0-dh[d1]);
994 buf_e[i].mch1 = std::max(buf_e[i].mch1, buf_r[i].mch1-dh[d1]);
997 /* Copy the received buffer to the send buffer,
998 * to pass the data through with the next pulse.
1000 buf_s[i] = buf_r[i];
1002 if (((bPBC || dd->ci[dim]+npulse < dd->nc[dim]) && p == npulse-1) ||
1003 (!bPBC && dd->ci[dim]+1+p == dd->nc[dim]-1))
1005 /* Store the extremes */
1006 pos = 0;
1008 for (d1 = d; d1 < dd->ndim-1; d1++)
1010 extr_s[d1][1] = std::min(extr_s[d1][1], buf_e[pos].min0);
1011 extr_s[d1][0] = std::max(extr_s[d1][0], buf_e[pos].max1);
1012 extr_s[d1][2] = std::min(extr_s[d1][2], buf_e[pos].min1);
1013 pos++;
1016 if (d == 1 || (d == 0 && dd->ndim == 3))
1018 for (i = d; i < 2; i++)
1020 comm->zone_d2[1-d][i] = buf_e[pos];
1021 pos++;
1024 if (d == 0)
1026 comm->zone_d1[1] = buf_e[pos];
1027 pos++;
1033 if (dd->ndim >= 2)
1035 dim = dd->dim[1];
1036 for (i = 0; i < 2; i++)
1038 if (debug)
1040 print_ddzone(debug, 1, i, 0, &comm->zone_d1[i]);
1042 cell_ns_x0[dim] = std::min(cell_ns_x0[dim], comm->zone_d1[i].min0);
1043 cell_ns_x1[dim] = std::max(cell_ns_x1[dim], comm->zone_d1[i].max1);
1046 if (dd->ndim >= 3)
1048 dim = dd->dim[2];
1049 for (i = 0; i < 2; i++)
1051 for (j = 0; j < 2; j++)
1053 if (debug)
1055 print_ddzone(debug, 2, i, j, &comm->zone_d2[i][j]);
1057 cell_ns_x0[dim] = std::min(cell_ns_x0[dim], comm->zone_d2[i][j].min0);
1058 cell_ns_x1[dim] = std::max(cell_ns_x1[dim], comm->zone_d2[i][j].max1);
1062 for (d = 1; d < dd->ndim; d++)
1064 comm->cell_f_max0[d] = extr_s[d-1][0];
1065 comm->cell_f_min1[d] = extr_s[d-1][1];
1066 if (debug)
1068 fprintf(debug, "Cell fraction d %d, max0 %f, min1 %f\n",
1069 d, comm->cell_f_max0[d], comm->cell_f_min1[d]);
1074 static void dd_collect_cg(gmx_domdec_t *dd,
1075 const t_state *state_local)
1077 gmx_domdec_master_t *ma = nullptr;
1078 int buf2[2], *ibuf, i, ncg_home = 0, nat_home = 0;
1080 if (state_local->ddp_count == dd->comm->master_cg_ddp_count)
1082 /* The master has the correct distribution */
1083 return;
1086 const int *cg;
1088 if (state_local->ddp_count == dd->ddp_count)
1090 /* The local state and DD are in sync, use the DD indices */
1091 ncg_home = dd->ncg_home;
1092 cg = dd->index_gl;
1093 nat_home = dd->nat_home;
1095 else if (state_local->ddp_count_cg_gl == state_local->ddp_count)
1097 /* The DD is out of sync with the local state, but we have stored
1098 * the cg indices with the local state, so we can use those.
1100 t_block *cgs_gl;
1102 cgs_gl = &dd->comm->cgs_gl;
1104 ncg_home = state_local->cg_gl.size();
1105 cg = state_local->cg_gl.data();
1106 nat_home = 0;
1107 for (i = 0; i < ncg_home; i++)
1109 nat_home += cgs_gl->index[cg[i]+1] - cgs_gl->index[cg[i]];
1112 else
1114 gmx_incons("Attempted to collect a vector for a state for which the charge group distribution is unknown");
1117 buf2[0] = ncg_home;
1118 buf2[1] = nat_home;
1119 if (DDMASTER(dd))
1121 ma = dd->ma;
1122 ibuf = ma->ibuf;
1124 else
1126 ibuf = nullptr;
1128 /* Collect the charge group and atom counts on the master */
1129 dd_gather(dd, 2*sizeof(int), buf2, ibuf);
1131 if (DDMASTER(dd))
1133 ma->index[0] = 0;
1134 for (i = 0; i < dd->nnodes; i++)
1136 ma->ncg[i] = ma->ibuf[2*i];
1137 ma->nat[i] = ma->ibuf[2*i+1];
1138 ma->index[i+1] = ma->index[i] + ma->ncg[i];
1141 /* Make byte counts and indices */
1142 for (i = 0; i < dd->nnodes; i++)
1144 ma->ibuf[i] = ma->ncg[i]*sizeof(int);
1145 ma->ibuf[dd->nnodes+i] = ma->index[i]*sizeof(int);
1147 if (debug)
1149 fprintf(debug, "Initial charge group distribution: ");
1150 for (i = 0; i < dd->nnodes; i++)
1152 fprintf(debug, " %d", ma->ncg[i]);
1154 fprintf(debug, "\n");
1158 /* Collect the charge group indices on the master */
1159 dd_gatherv(dd,
1160 ncg_home*sizeof(int), cg,
1161 DDMASTER(dd) ? ma->ibuf : nullptr,
1162 DDMASTER(dd) ? ma->ibuf+dd->nnodes : nullptr,
1163 DDMASTER(dd) ? ma->cg : nullptr);
1165 dd->comm->master_cg_ddp_count = state_local->ddp_count;
1168 static void dd_collect_vec_sendrecv(gmx_domdec_t *dd,
1169 gmx::ArrayRef<const gmx::RVec> lv,
1170 gmx::ArrayRef<gmx::RVec> v)
1172 gmx_domdec_master_t *ma;
1173 int n, i, c, a, nalloc = 0;
1174 rvec *buf = nullptr;
1175 t_block *cgs_gl;
1177 ma = dd->ma;
1179 if (!DDMASTER(dd))
1181 #if GMX_MPI
1182 MPI_Send(const_cast<void *>(static_cast<const void *>(lv.data())), dd->nat_home*sizeof(rvec), MPI_BYTE,
1183 DDMASTERRANK(dd), dd->rank, dd->mpi_comm_all);
1184 #endif
1186 else
1188 /* Copy the master coordinates to the global array */
1189 cgs_gl = &dd->comm->cgs_gl;
1191 n = DDMASTERRANK(dd);
1192 a = 0;
1193 for (i = ma->index[n]; i < ma->index[n+1]; i++)
1195 for (c = cgs_gl->index[ma->cg[i]]; c < cgs_gl->index[ma->cg[i]+1]; c++)
1197 copy_rvec(lv[a++], v[c]);
1201 for (n = 0; n < dd->nnodes; n++)
1203 if (n != dd->rank)
1205 if (ma->nat[n] > nalloc)
1207 nalloc = over_alloc_dd(ma->nat[n]);
1208 srenew(buf, nalloc);
1210 #if GMX_MPI
1211 MPI_Recv(buf, ma->nat[n]*sizeof(rvec), MPI_BYTE, DDRANK(dd, n),
1212 n, dd->mpi_comm_all, MPI_STATUS_IGNORE);
1213 #endif
1214 a = 0;
1215 for (i = ma->index[n]; i < ma->index[n+1]; i++)
1217 for (c = cgs_gl->index[ma->cg[i]]; c < cgs_gl->index[ma->cg[i]+1]; c++)
1219 copy_rvec(buf[a++], v[c]);
1224 sfree(buf);
1228 static void get_commbuffer_counts(gmx_domdec_t *dd,
1229 int **counts, int **disps)
1231 gmx_domdec_master_t *ma;
1232 int n;
1234 ma = dd->ma;
1236 /* Make the rvec count and displacment arrays */
1237 *counts = ma->ibuf;
1238 *disps = ma->ibuf + dd->nnodes;
1239 for (n = 0; n < dd->nnodes; n++)
1241 (*counts)[n] = ma->nat[n]*sizeof(rvec);
1242 (*disps)[n] = (n == 0 ? 0 : (*disps)[n-1] + (*counts)[n-1]);
1246 static void dd_collect_vec_gatherv(gmx_domdec_t *dd,
1247 gmx::ArrayRef<const gmx::RVec> lv,
1248 gmx::ArrayRef<gmx::RVec> v)
1250 gmx_domdec_master_t *ma;
1251 int *rcounts = nullptr, *disps = nullptr;
1252 int n, i, c, a;
1253 rvec *buf = nullptr;
1254 t_block *cgs_gl;
1256 ma = dd->ma;
1258 if (DDMASTER(dd))
1260 get_commbuffer_counts(dd, &rcounts, &disps);
1262 buf = ma->vbuf;
1265 dd_gatherv(dd, dd->nat_home*sizeof(rvec), lv.data(), rcounts, disps, buf);
1267 if (DDMASTER(dd))
1269 cgs_gl = &dd->comm->cgs_gl;
1271 a = 0;
1272 for (n = 0; n < dd->nnodes; n++)
1274 for (i = ma->index[n]; i < ma->index[n+1]; i++)
1276 for (c = cgs_gl->index[ma->cg[i]]; c < cgs_gl->index[ma->cg[i]+1]; c++)
1278 copy_rvec(buf[a++], v[c]);
1285 void dd_collect_vec(gmx_domdec_t *dd,
1286 const t_state *state_local,
1287 gmx::ArrayRef<const gmx::RVec> lv,
1288 gmx::ArrayRef<gmx::RVec> v)
1290 dd_collect_cg(dd, state_local);
1292 if (dd->nnodes <= GMX_DD_NNODES_SENDRECV)
1294 dd_collect_vec_sendrecv(dd, lv, v);
1296 else
1298 dd_collect_vec_gatherv(dd, lv, v);
1303 void dd_collect_state(gmx_domdec_t *dd,
1304 const t_state *state_local, t_state *state)
1306 int nh = state_local->nhchainlength;
1308 if (DDMASTER(dd))
1310 GMX_RELEASE_ASSERT(state->nhchainlength == nh, "The global and local Nose-Hoover chain lengths should match");
1312 for (int i = 0; i < efptNR; i++)
1314 state->lambda[i] = state_local->lambda[i];
1316 state->fep_state = state_local->fep_state;
1317 state->veta = state_local->veta;
1318 state->vol0 = state_local->vol0;
1319 copy_mat(state_local->box, state->box);
1320 copy_mat(state_local->boxv, state->boxv);
1321 copy_mat(state_local->svir_prev, state->svir_prev);
1322 copy_mat(state_local->fvir_prev, state->fvir_prev);
1323 copy_mat(state_local->pres_prev, state->pres_prev);
1325 for (int i = 0; i < state_local->ngtc; i++)
1327 for (int j = 0; j < nh; j++)
1329 state->nosehoover_xi[i*nh+j] = state_local->nosehoover_xi[i*nh+j];
1330 state->nosehoover_vxi[i*nh+j] = state_local->nosehoover_vxi[i*nh+j];
1332 state->therm_integral[i] = state_local->therm_integral[i];
1334 for (int i = 0; i < state_local->nnhpres; i++)
1336 for (int j = 0; j < nh; j++)
1338 state->nhpres_xi[i*nh+j] = state_local->nhpres_xi[i*nh+j];
1339 state->nhpres_vxi[i*nh+j] = state_local->nhpres_vxi[i*nh+j];
1342 state->baros_integral = state_local->baros_integral;
1344 if (state_local->flags & (1 << estX))
1346 gmx::ArrayRef<gmx::RVec> globalXRef = state ? gmx::makeArrayRef(state->x) : gmx::EmptyArrayRef();
1347 dd_collect_vec(dd, state_local, state_local->x, globalXRef);
1349 if (state_local->flags & (1 << estV))
1351 gmx::ArrayRef<gmx::RVec> globalVRef = state ? gmx::makeArrayRef(state->v) : gmx::EmptyArrayRef();
1352 dd_collect_vec(dd, state_local, state_local->v, globalVRef);
1354 if (state_local->flags & (1 << estCGP))
1356 gmx::ArrayRef<gmx::RVec> globalCgpRef = state ? gmx::makeArrayRef(state->cg_p) : gmx::EmptyArrayRef();
1357 dd_collect_vec(dd, state_local, state_local->cg_p, globalCgpRef);
1361 static void dd_resize_state(t_state *state, PaddedRVecVector *f, int natoms)
1363 if (debug)
1365 fprintf(debug, "Resizing state: currently %d, required %d\n", state->natoms, natoms);
1368 state_change_natoms(state, natoms);
1370 if (f != nullptr)
1372 /* We need to allocate one element extra, since we might use
1373 * (unaligned) 4-wide SIMD loads to access rvec entries.
1375 f->resize(paddedRVecVectorSize(natoms));
1379 static void dd_check_alloc_ncg(t_forcerec *fr,
1380 t_state *state,
1381 PaddedRVecVector *f,
1382 int numChargeGroups)
1384 if (numChargeGroups > fr->cg_nalloc)
1386 if (debug)
1388 fprintf(debug, "Reallocating forcerec: currently %d, required %d, allocating %d\n", fr->cg_nalloc, numChargeGroups, over_alloc_dd(numChargeGroups));
1390 fr->cg_nalloc = over_alloc_dd(numChargeGroups);
1391 srenew(fr->cginfo, fr->cg_nalloc);
1392 if (fr->cutoff_scheme == ecutsGROUP)
1394 srenew(fr->cg_cm, fr->cg_nalloc);
1397 if (fr->cutoff_scheme == ecutsVERLET)
1399 /* We don't use charge groups, we use x in state to set up
1400 * the atom communication.
1402 dd_resize_state(state, f, numChargeGroups);
1406 static void dd_distribute_vec_sendrecv(gmx_domdec_t *dd, t_block *cgs,
1407 const rvec *v, rvec *lv)
1409 gmx_domdec_master_t *ma;
1410 int n, i, c, a, nalloc = 0;
1411 rvec *buf = nullptr;
1413 if (DDMASTER(dd))
1415 ma = dd->ma;
1417 for (n = 0; n < dd->nnodes; n++)
1419 if (n != dd->rank)
1421 if (ma->nat[n] > nalloc)
1423 nalloc = over_alloc_dd(ma->nat[n]);
1424 srenew(buf, nalloc);
1426 /* Use lv as a temporary buffer */
1427 a = 0;
1428 for (i = ma->index[n]; i < ma->index[n+1]; i++)
1430 for (c = cgs->index[ma->cg[i]]; c < cgs->index[ma->cg[i]+1]; c++)
1432 copy_rvec(v[c], buf[a++]);
1435 if (a != ma->nat[n])
1437 gmx_fatal(FARGS, "Internal error a (%d) != nat (%d)",
1438 a, ma->nat[n]);
1441 #if GMX_MPI
1442 MPI_Send(buf, ma->nat[n]*sizeof(rvec), MPI_BYTE,
1443 DDRANK(dd, n), n, dd->mpi_comm_all);
1444 #endif
1447 sfree(buf);
1448 n = DDMASTERRANK(dd);
1449 a = 0;
1450 for (i = ma->index[n]; i < ma->index[n+1]; i++)
1452 for (c = cgs->index[ma->cg[i]]; c < cgs->index[ma->cg[i]+1]; c++)
1454 copy_rvec(v[c], lv[a++]);
1458 else
1460 #if GMX_MPI
1461 MPI_Recv(lv, dd->nat_home*sizeof(rvec), MPI_BYTE, DDMASTERRANK(dd),
1462 MPI_ANY_TAG, dd->mpi_comm_all, MPI_STATUS_IGNORE);
1463 #endif
1467 static void dd_distribute_vec_scatterv(gmx_domdec_t *dd, t_block *cgs,
1468 const rvec *v, rvec *lv)
1470 gmx_domdec_master_t *ma;
1471 int *scounts = nullptr, *disps = nullptr;
1472 int n, i, c, a;
1473 rvec *buf = nullptr;
1475 if (DDMASTER(dd))
1477 ma = dd->ma;
1479 get_commbuffer_counts(dd, &scounts, &disps);
1481 buf = ma->vbuf;
1482 a = 0;
1483 for (n = 0; n < dd->nnodes; n++)
1485 for (i = ma->index[n]; i < ma->index[n+1]; i++)
1487 for (c = cgs->index[ma->cg[i]]; c < cgs->index[ma->cg[i]+1]; c++)
1489 copy_rvec(v[c], buf[a++]);
1495 dd_scatterv(dd, scounts, disps, buf, dd->nat_home*sizeof(rvec), lv);
1498 static void dd_distribute_vec(gmx_domdec_t *dd, t_block *cgs,
1499 const rvec *v, rvec *lv)
1501 if (dd->nnodes <= GMX_DD_NNODES_SENDRECV)
1503 dd_distribute_vec_sendrecv(dd, cgs, v, lv);
1505 else
1507 dd_distribute_vec_scatterv(dd, cgs, v, lv);
1511 static void dd_distribute_dfhist(gmx_domdec_t *dd, df_history_t *dfhist)
1513 if (dfhist == nullptr)
1515 return;
1518 dd_bcast(dd, sizeof(int), &dfhist->bEquil);
1519 dd_bcast(dd, sizeof(int), &dfhist->nlambda);
1520 dd_bcast(dd, sizeof(real), &dfhist->wl_delta);
1522 if (dfhist->nlambda > 0)
1524 int nlam = dfhist->nlambda;
1525 dd_bcast(dd, sizeof(int)*nlam, dfhist->n_at_lam);
1526 dd_bcast(dd, sizeof(real)*nlam, dfhist->wl_histo);
1527 dd_bcast(dd, sizeof(real)*nlam, dfhist->sum_weights);
1528 dd_bcast(dd, sizeof(real)*nlam, dfhist->sum_dg);
1529 dd_bcast(dd, sizeof(real)*nlam, dfhist->sum_minvar);
1530 dd_bcast(dd, sizeof(real)*nlam, dfhist->sum_variance);
1532 for (int i = 0; i < nlam; i++)
1534 dd_bcast(dd, sizeof(real)*nlam, dfhist->accum_p[i]);
1535 dd_bcast(dd, sizeof(real)*nlam, dfhist->accum_m[i]);
1536 dd_bcast(dd, sizeof(real)*nlam, dfhist->accum_p2[i]);
1537 dd_bcast(dd, sizeof(real)*nlam, dfhist->accum_m2[i]);
1538 dd_bcast(dd, sizeof(real)*nlam, dfhist->Tij[i]);
1539 dd_bcast(dd, sizeof(real)*nlam, dfhist->Tij_empirical[i]);
1544 static void dd_distribute_state(gmx_domdec_t *dd, t_block *cgs,
1545 t_state *state, t_state *state_local,
1546 PaddedRVecVector *f)
1548 int nh = state_local->nhchainlength;
1550 if (DDMASTER(dd))
1552 GMX_RELEASE_ASSERT(state->nhchainlength == nh, "The global and local Nose-Hoover chain lengths should match");
1554 for (int i = 0; i < efptNR; i++)
1556 state_local->lambda[i] = state->lambda[i];
1558 state_local->fep_state = state->fep_state;
1559 state_local->veta = state->veta;
1560 state_local->vol0 = state->vol0;
1561 copy_mat(state->box, state_local->box);
1562 copy_mat(state->box_rel, state_local->box_rel);
1563 copy_mat(state->boxv, state_local->boxv);
1564 copy_mat(state->svir_prev, state_local->svir_prev);
1565 copy_mat(state->fvir_prev, state_local->fvir_prev);
1566 if (state->dfhist != nullptr)
1568 copy_df_history(state_local->dfhist, state->dfhist);
1570 for (int i = 0; i < state_local->ngtc; i++)
1572 for (int j = 0; j < nh; j++)
1574 state_local->nosehoover_xi[i*nh+j] = state->nosehoover_xi[i*nh+j];
1575 state_local->nosehoover_vxi[i*nh+j] = state->nosehoover_vxi[i*nh+j];
1577 state_local->therm_integral[i] = state->therm_integral[i];
1579 for (int i = 0; i < state_local->nnhpres; i++)
1581 for (int j = 0; j < nh; j++)
1583 state_local->nhpres_xi[i*nh+j] = state->nhpres_xi[i*nh+j];
1584 state_local->nhpres_vxi[i*nh+j] = state->nhpres_vxi[i*nh+j];
1587 state_local->baros_integral = state->baros_integral;
1589 dd_bcast(dd, ((efptNR)*sizeof(real)), state_local->lambda.data());
1590 dd_bcast(dd, sizeof(int), &state_local->fep_state);
1591 dd_bcast(dd, sizeof(real), &state_local->veta);
1592 dd_bcast(dd, sizeof(real), &state_local->vol0);
1593 dd_bcast(dd, sizeof(state_local->box), state_local->box);
1594 dd_bcast(dd, sizeof(state_local->box_rel), state_local->box_rel);
1595 dd_bcast(dd, sizeof(state_local->boxv), state_local->boxv);
1596 dd_bcast(dd, sizeof(state_local->svir_prev), state_local->svir_prev);
1597 dd_bcast(dd, sizeof(state_local->fvir_prev), state_local->fvir_prev);
1598 dd_bcast(dd, ((state_local->ngtc*nh)*sizeof(double)), state_local->nosehoover_xi.data());
1599 dd_bcast(dd, ((state_local->ngtc*nh)*sizeof(double)), state_local->nosehoover_vxi.data());
1600 dd_bcast(dd, state_local->ngtc*sizeof(double), state_local->therm_integral.data());
1601 dd_bcast(dd, ((state_local->nnhpres*nh)*sizeof(double)), state_local->nhpres_xi.data());
1602 dd_bcast(dd, ((state_local->nnhpres*nh)*sizeof(double)), state_local->nhpres_vxi.data());
1604 /* communicate df_history -- required for restarting from checkpoint */
1605 dd_distribute_dfhist(dd, state_local->dfhist);
1607 dd_resize_state(state_local, f, dd->nat_home);
1609 if (state_local->flags & (1 << estX))
1611 const rvec *xGlobal = (DDMASTER(dd) ? as_rvec_array(state->x.data()) : nullptr);
1612 dd_distribute_vec(dd, cgs, xGlobal, as_rvec_array(state_local->x.data()));
1614 if (state_local->flags & (1 << estV))
1616 const rvec *vGlobal = (DDMASTER(dd) ? as_rvec_array(state->v.data()) : nullptr);
1617 dd_distribute_vec(dd, cgs, vGlobal, as_rvec_array(state_local->v.data()));
1619 if (state_local->flags & (1 << estCGP))
1621 const rvec *cgpGlobal = (DDMASTER(dd) ? as_rvec_array(state->cg_p.data()) : nullptr);
1622 dd_distribute_vec(dd, cgs, cgpGlobal, as_rvec_array(state_local->cg_p.data()));
1626 static char dim2char(int dim)
1628 char c = '?';
1630 switch (dim)
1632 case XX: c = 'X'; break;
1633 case YY: c = 'Y'; break;
1634 case ZZ: c = 'Z'; break;
1635 default: gmx_fatal(FARGS, "Unknown dim %d", dim);
1638 return c;
1641 static void write_dd_grid_pdb(const char *fn, gmx_int64_t step,
1642 gmx_domdec_t *dd, matrix box, gmx_ddbox_t *ddbox)
1644 rvec grid_s[2], *grid_r = nullptr, cx, r;
1645 char fname[STRLEN], buf[22];
1646 FILE *out;
1647 int a, i, d, z, y, x;
1648 matrix tric;
1649 real vol;
1651 copy_rvec(dd->comm->cell_x0, grid_s[0]);
1652 copy_rvec(dd->comm->cell_x1, grid_s[1]);
1654 if (DDMASTER(dd))
1656 snew(grid_r, 2*dd->nnodes);
1659 dd_gather(dd, 2*sizeof(rvec), grid_s, DDMASTER(dd) ? grid_r : nullptr);
1661 if (DDMASTER(dd))
1663 for (d = 0; d < DIM; d++)
1665 for (i = 0; i < DIM; i++)
1667 if (d == i)
1669 tric[d][i] = 1;
1671 else
1673 if (d < ddbox->npbcdim && dd->nc[d] > 1)
1675 tric[d][i] = box[i][d]/box[i][i];
1677 else
1679 tric[d][i] = 0;
1684 sprintf(fname, "%s_%s.pdb", fn, gmx_step_str(step, buf));
1685 out = gmx_fio_fopen(fname, "w");
1686 gmx_write_pdb_box(out, dd->bScrewPBC ? epbcSCREW : epbcXYZ, box);
1687 a = 1;
1688 for (i = 0; i < dd->nnodes; i++)
1690 vol = dd->nnodes/(box[XX][XX]*box[YY][YY]*box[ZZ][ZZ]);
1691 for (d = 0; d < DIM; d++)
1693 vol *= grid_r[i*2+1][d] - grid_r[i*2][d];
1695 for (z = 0; z < 2; z++)
1697 for (y = 0; y < 2; y++)
1699 for (x = 0; x < 2; x++)
1701 cx[XX] = grid_r[i*2+x][XX];
1702 cx[YY] = grid_r[i*2+y][YY];
1703 cx[ZZ] = grid_r[i*2+z][ZZ];
1704 mvmul(tric, cx, r);
1705 gmx_fprintf_pdb_atomline(out, epdbATOM, a++, "CA", ' ', "GLY", ' ', i+1, ' ',
1706 10*r[XX], 10*r[YY], 10*r[ZZ], 1.0, vol, "");
1710 for (d = 0; d < DIM; d++)
1712 for (x = 0; x < 4; x++)
1714 switch (d)
1716 case 0: y = 1 + i*8 + 2*x; break;
1717 case 1: y = 1 + i*8 + 2*x - (x % 2); break;
1718 case 2: y = 1 + i*8 + x; break;
1720 fprintf(out, "%6s%5d%5d\n", "CONECT", y, y+(1<<d));
1724 gmx_fio_fclose(out);
1725 sfree(grid_r);
1729 void write_dd_pdb(const char *fn, gmx_int64_t step, const char *title,
1730 const gmx_mtop_t *mtop, const t_commrec *cr,
1731 int natoms, const rvec x[], const matrix box)
1733 char fname[STRLEN], buf[22];
1734 FILE *out;
1735 int i, ii, resnr, c;
1736 const char *atomname, *resname;
1737 real b;
1738 gmx_domdec_t *dd;
1740 dd = cr->dd;
1741 if (natoms == -1)
1743 natoms = dd->comm->nat[ddnatVSITE];
1746 sprintf(fname, "%s_%s_n%d.pdb", fn, gmx_step_str(step, buf), cr->sim_nodeid);
1748 out = gmx_fio_fopen(fname, "w");
1750 fprintf(out, "TITLE %s\n", title);
1751 gmx_write_pdb_box(out, dd->bScrewPBC ? epbcSCREW : epbcXYZ, box);
1752 int molb = 0;
1753 for (i = 0; i < natoms; i++)
1755 ii = dd->gatindex[i];
1756 mtopGetAtomAndResidueName(mtop, ii, &molb, &atomname, &resnr, &resname, nullptr);
1757 if (i < dd->comm->nat[ddnatZONE])
1759 c = 0;
1760 while (i >= dd->cgindex[dd->comm->zones.cg_range[c+1]])
1762 c++;
1764 b = c;
1766 else if (i < dd->comm->nat[ddnatVSITE])
1768 b = dd->comm->zones.n;
1770 else
1772 b = dd->comm->zones.n + 1;
1774 gmx_fprintf_pdb_atomline(out, epdbATOM, ii+1, atomname, ' ', resname, ' ', resnr, ' ',
1775 10*x[i][XX], 10*x[i][YY], 10*x[i][ZZ], 1.0, b, "");
1777 fprintf(out, "TER\n");
1779 gmx_fio_fclose(out);
1782 real dd_cutoff_multibody(const gmx_domdec_t *dd)
1784 gmx_domdec_comm_t *comm;
1785 int di;
1786 real r;
1788 comm = dd->comm;
1790 r = -1;
1791 if (comm->bInterCGBondeds)
1793 if (comm->cutoff_mbody > 0)
1795 r = comm->cutoff_mbody;
1797 else
1799 /* cutoff_mbody=0 means we do not have DLB */
1800 r = comm->cellsize_min[dd->dim[0]];
1801 for (di = 1; di < dd->ndim; di++)
1803 r = std::min(r, comm->cellsize_min[dd->dim[di]]);
1805 if (comm->bBondComm)
1807 r = std::max(r, comm->cutoff_mbody);
1809 else
1811 r = std::min(r, comm->cutoff);
1816 return r;
1819 real dd_cutoff_twobody(const gmx_domdec_t *dd)
1821 real r_mb;
1823 r_mb = dd_cutoff_multibody(dd);
1825 return std::max(dd->comm->cutoff, r_mb);
1829 static void dd_cart_coord2pmecoord(const gmx_domdec_t *dd, const ivec coord,
1830 ivec coord_pme)
1832 int nc, ntot;
1834 nc = dd->nc[dd->comm->cartpmedim];
1835 ntot = dd->comm->ntot[dd->comm->cartpmedim];
1836 copy_ivec(coord, coord_pme);
1837 coord_pme[dd->comm->cartpmedim] =
1838 nc + (coord[dd->comm->cartpmedim]*(ntot - nc) + (ntot - nc)/2)/nc;
1841 static int ddindex2pmeindex(const gmx_domdec_t *dd, int ddindex)
1843 int npp, npme;
1845 npp = dd->nnodes;
1846 npme = dd->comm->npmenodes;
1848 /* Here we assign a PME node to communicate with this DD node
1849 * by assuming that the major index of both is x.
1850 * We add cr->npmenodes/2 to obtain an even distribution.
1852 return (ddindex*npme + npme/2)/npp;
1855 static int *dd_interleaved_pme_ranks(const gmx_domdec_t *dd)
1857 int *pme_rank;
1858 int n, i, p0, p1;
1860 snew(pme_rank, dd->comm->npmenodes);
1861 n = 0;
1862 for (i = 0; i < dd->nnodes; i++)
1864 p0 = ddindex2pmeindex(dd, i);
1865 p1 = ddindex2pmeindex(dd, i+1);
1866 if (i+1 == dd->nnodes || p1 > p0)
1868 if (debug)
1870 fprintf(debug, "pme_rank[%d] = %d\n", n, i+1+n);
1872 pme_rank[n] = i + 1 + n;
1873 n++;
1877 return pme_rank;
1880 static int gmx_ddcoord2pmeindex(const t_commrec *cr, int x, int y, int z)
1882 gmx_domdec_t *dd;
1883 ivec coords;
1884 int slab;
1886 dd = cr->dd;
1888 if (dd->comm->bCartesian) {
1889 gmx_ddindex2xyz(dd->nc,ddindex,coords);
1890 dd_coords2pmecoords(dd,coords,coords_pme);
1891 copy_ivec(dd->ntot,nc);
1892 nc[dd->cartpmedim] -= dd->nc[dd->cartpmedim];
1893 coords_pme[dd->cartpmedim] -= dd->nc[dd->cartpmedim];
1895 slab = (coords_pme[XX]*nc[YY] + coords_pme[YY])*nc[ZZ] + coords_pme[ZZ];
1896 } else {
1897 slab = (ddindex*cr->npmenodes + cr->npmenodes/2)/dd->nnodes;
1900 coords[XX] = x;
1901 coords[YY] = y;
1902 coords[ZZ] = z;
1903 slab = ddindex2pmeindex(dd, dd_index(dd->nc, coords));
1905 return slab;
1908 static int ddcoord2simnodeid(const t_commrec *cr, int x, int y, int z)
1910 gmx_domdec_comm_t *comm;
1911 ivec coords;
1912 int ddindex, nodeid = -1;
1914 comm = cr->dd->comm;
1916 coords[XX] = x;
1917 coords[YY] = y;
1918 coords[ZZ] = z;
1919 if (comm->bCartesianPP_PME)
1921 #if GMX_MPI
1922 MPI_Cart_rank(cr->mpi_comm_mysim, coords, &nodeid);
1923 #endif
1925 else
1927 ddindex = dd_index(cr->dd->nc, coords);
1928 if (comm->bCartesianPP)
1930 nodeid = comm->ddindex2simnodeid[ddindex];
1932 else
1934 if (comm->pmenodes)
1936 nodeid = ddindex + gmx_ddcoord2pmeindex(cr, x, y, z);
1938 else
1940 nodeid = ddindex;
1945 return nodeid;
1948 static int dd_simnode2pmenode(const gmx_domdec_t *dd,
1949 const t_commrec gmx_unused *cr,
1950 int sim_nodeid)
1952 int pmenode = -1;
1954 const gmx_domdec_comm_t *comm = dd->comm;
1956 /* This assumes a uniform x domain decomposition grid cell size */
1957 if (comm->bCartesianPP_PME)
1959 #if GMX_MPI
1960 ivec coord, coord_pme;
1961 MPI_Cart_coords(cr->mpi_comm_mysim, sim_nodeid, DIM, coord);
1962 if (coord[comm->cartpmedim] < dd->nc[comm->cartpmedim])
1964 /* This is a PP node */
1965 dd_cart_coord2pmecoord(dd, coord, coord_pme);
1966 MPI_Cart_rank(cr->mpi_comm_mysim, coord_pme, &pmenode);
1968 #endif
1970 else if (comm->bCartesianPP)
1972 if (sim_nodeid < dd->nnodes)
1974 pmenode = dd->nnodes + ddindex2pmeindex(dd, sim_nodeid);
1977 else
1979 /* This assumes DD cells with identical x coordinates
1980 * are numbered sequentially.
1982 if (dd->comm->pmenodes == nullptr)
1984 if (sim_nodeid < dd->nnodes)
1986 /* The DD index equals the nodeid */
1987 pmenode = dd->nnodes + ddindex2pmeindex(dd, sim_nodeid);
1990 else
1992 int i = 0;
1993 while (sim_nodeid > dd->comm->pmenodes[i])
1995 i++;
1997 if (sim_nodeid < dd->comm->pmenodes[i])
1999 pmenode = dd->comm->pmenodes[i];
2004 return pmenode;
2007 NumPmeDomains getNumPmeDomains(const gmx_domdec_t *dd)
2009 if (dd != nullptr)
2011 return { dd->comm->npmenodes_x, dd->comm->npmenodes_y };
2013 else
2015 return { 1, 1 };
2019 std::vector<int> get_pme_ddranks(const t_commrec *cr, int pmenodeid)
2021 gmx_domdec_t *dd;
2022 int x, y, z;
2023 ivec coord, coord_pme;
2025 dd = cr->dd;
2027 std::vector<int> ddranks;
2028 ddranks.reserve((dd->nnodes+cr->npmenodes-1)/cr->npmenodes);
2030 for (x = 0; x < dd->nc[XX]; x++)
2032 for (y = 0; y < dd->nc[YY]; y++)
2034 for (z = 0; z < dd->nc[ZZ]; z++)
2036 if (dd->comm->bCartesianPP_PME)
2038 coord[XX] = x;
2039 coord[YY] = y;
2040 coord[ZZ] = z;
2041 dd_cart_coord2pmecoord(dd, coord, coord_pme);
2042 if (dd->ci[XX] == coord_pme[XX] &&
2043 dd->ci[YY] == coord_pme[YY] &&
2044 dd->ci[ZZ] == coord_pme[ZZ])
2046 ddranks.push_back(ddcoord2simnodeid(cr, x, y, z));
2049 else
2051 /* The slab corresponds to the nodeid in the PME group */
2052 if (gmx_ddcoord2pmeindex(cr, x, y, z) == pmenodeid)
2054 ddranks.push_back(ddcoord2simnodeid(cr, x, y, z));
2060 return ddranks;
2063 static gmx_bool receive_vir_ener(const gmx_domdec_t *dd, const t_commrec *cr)
2065 gmx_bool bReceive = TRUE;
2067 if (cr->npmenodes < dd->nnodes)
2069 gmx_domdec_comm_t *comm = dd->comm;
2070 if (comm->bCartesianPP_PME)
2072 #if GMX_MPI
2073 int pmenode = dd_simnode2pmenode(dd, cr, cr->sim_nodeid);
2074 ivec coords;
2075 MPI_Cart_coords(cr->mpi_comm_mysim, cr->sim_nodeid, DIM, coords);
2076 coords[comm->cartpmedim]++;
2077 if (coords[comm->cartpmedim] < dd->nc[comm->cartpmedim])
2079 int rank;
2080 MPI_Cart_rank(cr->mpi_comm_mysim, coords, &rank);
2081 if (dd_simnode2pmenode(dd, cr, rank) == pmenode)
2083 /* This is not the last PP node for pmenode */
2084 bReceive = FALSE;
2087 #else
2088 GMX_RELEASE_ASSERT(false, "Without MPI we should not have Cartesian PP-PME with #PMEnodes < #DDnodes");
2089 #endif
2091 else
2093 int pmenode = dd_simnode2pmenode(dd, cr, cr->sim_nodeid);
2094 if (cr->sim_nodeid+1 < cr->nnodes &&
2095 dd_simnode2pmenode(dd, cr, cr->sim_nodeid+1) == pmenode)
2097 /* This is not the last PP node for pmenode */
2098 bReceive = FALSE;
2103 return bReceive;
2106 static void set_zones_ncg_home(gmx_domdec_t *dd)
2108 gmx_domdec_zones_t *zones;
2109 int i;
2111 zones = &dd->comm->zones;
2113 zones->cg_range[0] = 0;
2114 for (i = 1; i < zones->n+1; i++)
2116 zones->cg_range[i] = dd->ncg_home;
2118 /* zone_ncg1[0] should always be equal to ncg_home */
2119 dd->comm->zone_ncg1[0] = dd->ncg_home;
2122 static void rebuild_cgindex(gmx_domdec_t *dd,
2123 const int *gcgs_index, const t_state *state)
2125 int * gmx_restrict dd_cg_gl = dd->index_gl;
2126 int * gmx_restrict cgindex = dd->cgindex;
2127 int nat = 0;
2129 /* Copy back the global charge group indices from state
2130 * and rebuild the local charge group to atom index.
2132 cgindex[0] = nat;
2133 for (unsigned int i = 0; i < state->cg_gl.size(); i++)
2135 cgindex[i] = nat;
2136 int cg_gl = state->cg_gl[i];
2137 dd_cg_gl[i] = cg_gl;
2138 nat += gcgs_index[cg_gl+1] - gcgs_index[cg_gl];
2140 cgindex[state->cg_gl.size()] = nat;
2142 dd->ncg_home = state->cg_gl.size();
2143 dd->nat_home = nat;
2145 set_zones_ncg_home(dd);
2148 static int ddcginfo(const cginfo_mb_t *cginfo_mb, int cg)
2150 while (cg >= cginfo_mb->cg_end)
2152 cginfo_mb++;
2155 return cginfo_mb->cginfo[(cg - cginfo_mb->cg_start) % cginfo_mb->cg_mod];
2158 static void dd_set_cginfo(int *index_gl, int cg0, int cg1,
2159 t_forcerec *fr, char *bLocalCG)
2161 cginfo_mb_t *cginfo_mb;
2162 int *cginfo;
2163 int cg;
2165 if (fr != nullptr)
2167 cginfo_mb = fr->cginfo_mb;
2168 cginfo = fr->cginfo;
2170 for (cg = cg0; cg < cg1; cg++)
2172 cginfo[cg] = ddcginfo(cginfo_mb, index_gl[cg]);
2176 if (bLocalCG != nullptr)
2178 for (cg = cg0; cg < cg1; cg++)
2180 bLocalCG[index_gl[cg]] = TRUE;
2185 static void make_dd_indices(gmx_domdec_t *dd,
2186 const int *gcgs_index, int cg_start)
2188 int nzone, zone, zone1, cg0, cg1, cg1_p1, cg, cg_gl, a, a_gl;
2189 int *zone2cg, *zone_ncg1, *index_gl, *gatindex;
2190 gmx_bool bCGs;
2192 if (dd->nat_tot > dd->gatindex_nalloc)
2194 dd->gatindex_nalloc = over_alloc_dd(dd->nat_tot);
2195 srenew(dd->gatindex, dd->gatindex_nalloc);
2198 nzone = dd->comm->zones.n;
2199 zone2cg = dd->comm->zones.cg_range;
2200 zone_ncg1 = dd->comm->zone_ncg1;
2201 index_gl = dd->index_gl;
2202 gatindex = dd->gatindex;
2203 bCGs = dd->comm->bCGs;
2205 if (zone2cg[1] != dd->ncg_home)
2207 gmx_incons("dd->ncg_zone is not up to date");
2210 /* Make the local to global and global to local atom index */
2211 a = dd->cgindex[cg_start];
2212 for (zone = 0; zone < nzone; zone++)
2214 if (zone == 0)
2216 cg0 = cg_start;
2218 else
2220 cg0 = zone2cg[zone];
2222 cg1 = zone2cg[zone+1];
2223 cg1_p1 = cg0 + zone_ncg1[zone];
2225 for (cg = cg0; cg < cg1; cg++)
2227 zone1 = zone;
2228 if (cg >= cg1_p1)
2230 /* Signal that this cg is from more than one pulse away */
2231 zone1 += nzone;
2233 cg_gl = index_gl[cg];
2234 if (bCGs)
2236 for (a_gl = gcgs_index[cg_gl]; a_gl < gcgs_index[cg_gl+1]; a_gl++)
2238 gatindex[a] = a_gl;
2239 ga2la_set(dd->ga2la, a_gl, a, zone1);
2240 a++;
2243 else
2245 gatindex[a] = cg_gl;
2246 ga2la_set(dd->ga2la, cg_gl, a, zone1);
2247 a++;
2253 static int check_bLocalCG(gmx_domdec_t *dd, int ncg_sys, const char *bLocalCG,
2254 const char *where)
2256 int i, ngl, nerr;
2258 nerr = 0;
2259 if (bLocalCG == nullptr)
2261 return nerr;
2263 for (i = 0; i < dd->ncg_tot; i++)
2265 if (!bLocalCG[dd->index_gl[i]])
2267 fprintf(stderr,
2268 "DD rank %d, %s: cg %d, global cg %d is not marked in bLocalCG (ncg_home %d)\n", dd->rank, where, i+1, dd->index_gl[i]+1, dd->ncg_home);
2269 nerr++;
2272 ngl = 0;
2273 for (i = 0; i < ncg_sys; i++)
2275 if (bLocalCG[i])
2277 ngl++;
2280 if (ngl != dd->ncg_tot)
2282 fprintf(stderr, "DD rank %d, %s: In bLocalCG %d cgs are marked as local, whereas there are %d\n", dd->rank, where, ngl, dd->ncg_tot);
2283 nerr++;
2286 return nerr;
2289 static void check_index_consistency(gmx_domdec_t *dd,
2290 int natoms_sys, int ncg_sys,
2291 const char *where)
2293 int nerr, ngl, i, a, cell;
2294 int *have;
2296 nerr = 0;
2298 if (dd->comm->DD_debug > 1)
2300 snew(have, natoms_sys);
2301 for (a = 0; a < dd->nat_tot; a++)
2303 if (have[dd->gatindex[a]] > 0)
2305 fprintf(stderr, "DD rank %d: global atom %d occurs twice: index %d and %d\n", dd->rank, dd->gatindex[a]+1, have[dd->gatindex[a]], a+1);
2307 else
2309 have[dd->gatindex[a]] = a + 1;
2312 sfree(have);
2315 snew(have, dd->nat_tot);
2317 ngl = 0;
2318 for (i = 0; i < natoms_sys; i++)
2320 if (ga2la_get(dd->ga2la, i, &a, &cell))
2322 if (a >= dd->nat_tot)
2324 fprintf(stderr, "DD rank %d: global atom %d marked as local atom %d, which is larger than nat_tot (%d)\n", dd->rank, i+1, a+1, dd->nat_tot);
2325 nerr++;
2327 else
2329 have[a] = 1;
2330 if (dd->gatindex[a] != i)
2332 fprintf(stderr, "DD rank %d: global atom %d marked as local atom %d, which has global atom index %d\n", dd->rank, i+1, a+1, dd->gatindex[a]+1);
2333 nerr++;
2336 ngl++;
2339 if (ngl != dd->nat_tot)
2341 fprintf(stderr,
2342 "DD rank %d, %s: %d global atom indices, %d local atoms\n",
2343 dd->rank, where, ngl, dd->nat_tot);
2345 for (a = 0; a < dd->nat_tot; a++)
2347 if (have[a] == 0)
2349 fprintf(stderr,
2350 "DD rank %d, %s: local atom %d, global %d has no global index\n",
2351 dd->rank, where, a+1, dd->gatindex[a]+1);
2354 sfree(have);
2356 nerr += check_bLocalCG(dd, ncg_sys, dd->comm->bLocalCG, where);
2358 if (nerr > 0)
2360 gmx_fatal(FARGS, "DD rank %d, %s: %d atom/cg index inconsistencies",
2361 dd->rank, where, nerr);
2365 static void clear_dd_indices(gmx_domdec_t *dd, int cg_start, int a_start)
2367 int i;
2368 char *bLocalCG;
2370 if (a_start == 0)
2372 /* Clear the whole list without searching */
2373 ga2la_clear(dd->ga2la);
2375 else
2377 for (i = a_start; i < dd->nat_tot; i++)
2379 ga2la_del(dd->ga2la, dd->gatindex[i]);
2383 bLocalCG = dd->comm->bLocalCG;
2384 if (bLocalCG)
2386 for (i = cg_start; i < dd->ncg_tot; i++)
2388 bLocalCG[dd->index_gl[i]] = FALSE;
2392 dd_clear_local_vsite_indices(dd);
2394 if (dd->constraints)
2396 dd_clear_local_constraint_indices(dd);
2400 /* This function should be used for moving the domain boudaries during DLB,
2401 * for obtaining the minimum cell size. It checks the initially set limit
2402 * comm->cellsize_min, for bonded and initial non-bonded cut-offs,
2403 * and, possibly, a longer cut-off limit set for PME load balancing.
2405 static real cellsize_min_dlb(gmx_domdec_comm_t *comm, int dim_ind, int dim)
2407 real cellsize_min;
2409 cellsize_min = comm->cellsize_min[dim];
2411 if (!comm->bVacDLBNoLimit)
2413 /* The cut-off might have changed, e.g. by PME load balacning,
2414 * from the value used to set comm->cellsize_min, so check it.
2416 cellsize_min = std::max(cellsize_min, comm->cutoff/comm->cd[dim_ind].np_dlb);
2418 if (comm->bPMELoadBalDLBLimits)
2420 /* Check for the cut-off limit set by the PME load balancing */
2421 cellsize_min = std::max(cellsize_min, comm->PMELoadBal_max_cutoff/comm->cd[dim_ind].np_dlb);
2425 return cellsize_min;
2428 static real grid_jump_limit(gmx_domdec_comm_t *comm, real cutoff,
2429 int dim_ind)
2431 real grid_jump_limit;
2433 /* The distance between the boundaries of cells at distance
2434 * x+-1,y+-1 or y+-1,z+-1 is limited by the cut-off restrictions
2435 * and by the fact that cells should not be shifted by more than
2436 * half their size, such that cg's only shift by one cell
2437 * at redecomposition.
2439 grid_jump_limit = comm->cellsize_limit;
2440 if (!comm->bVacDLBNoLimit)
2442 if (comm->bPMELoadBalDLBLimits)
2444 cutoff = std::max(cutoff, comm->PMELoadBal_max_cutoff);
2446 grid_jump_limit = std::max(grid_jump_limit,
2447 cutoff/comm->cd[dim_ind].np);
2450 return grid_jump_limit;
2453 static gmx_bool check_grid_jump(gmx_int64_t step,
2454 gmx_domdec_t *dd,
2455 real cutoff,
2456 gmx_ddbox_t *ddbox,
2457 gmx_bool bFatal)
2459 gmx_domdec_comm_t *comm;
2460 int d, dim;
2461 real limit, bfac;
2462 gmx_bool bInvalid;
2464 bInvalid = FALSE;
2466 comm = dd->comm;
2468 for (d = 1; d < dd->ndim; d++)
2470 dim = dd->dim[d];
2471 limit = grid_jump_limit(comm, cutoff, d);
2472 bfac = ddbox->box_size[dim];
2473 if (ddbox->tric_dir[dim])
2475 bfac *= ddbox->skew_fac[dim];
2477 if ((comm->cell_f1[d] - comm->cell_f_max0[d])*bfac < limit ||
2478 (comm->cell_f0[d] - comm->cell_f_min1[d])*bfac > -limit)
2480 bInvalid = TRUE;
2482 if (bFatal)
2484 char buf[22];
2486 /* This error should never be triggered under normal
2487 * circumstances, but you never know ...
2489 gmx_fatal(FARGS, "step %s: The domain decomposition grid has shifted too much in the %c-direction around cell %d %d %d. This should not have happened. Running with fewer ranks might avoid this issue.",
2490 gmx_step_str(step, buf),
2491 dim2char(dim), dd->ci[XX], dd->ci[YY], dd->ci[ZZ]);
2496 return bInvalid;
2499 static int dd_load_count(gmx_domdec_comm_t *comm)
2501 return (comm->eFlop ? comm->flop_n : comm->cycl_n[ddCyclF]);
2504 static float dd_force_load(gmx_domdec_comm_t *comm)
2506 float load;
2508 if (comm->eFlop)
2510 load = comm->flop;
2511 if (comm->eFlop > 1)
2513 load *= 1.0 + (comm->eFlop - 1)*(0.1*rand()/RAND_MAX - 0.05);
2516 else
2518 load = comm->cycl[ddCyclF];
2519 if (comm->cycl_n[ddCyclF] > 1)
2521 /* Subtract the maximum of the last n cycle counts
2522 * to get rid of possible high counts due to other sources,
2523 * for instance system activity, that would otherwise
2524 * affect the dynamic load balancing.
2526 load -= comm->cycl_max[ddCyclF];
2529 #if GMX_MPI
2530 if (comm->cycl_n[ddCyclWaitGPU] && comm->nrank_gpu_shared > 1)
2532 float gpu_wait, gpu_wait_sum;
2534 gpu_wait = comm->cycl[ddCyclWaitGPU];
2535 if (comm->cycl_n[ddCyclF] > 1)
2537 /* We should remove the WaitGPU time of the same MD step
2538 * as the one with the maximum F time, since the F time
2539 * and the wait time are not independent.
2540 * Furthermore, the step for the max F time should be chosen
2541 * the same on all ranks that share the same GPU.
2542 * But to keep the code simple, we remove the average instead.
2543 * The main reason for artificially long times at some steps
2544 * is spurious CPU activity or MPI time, so we don't expect
2545 * that changes in the GPU wait time matter a lot here.
2547 gpu_wait *= (comm->cycl_n[ddCyclF] - 1)/(float)comm->cycl_n[ddCyclF];
2549 /* Sum the wait times over the ranks that share the same GPU */
2550 MPI_Allreduce(&gpu_wait, &gpu_wait_sum, 1, MPI_FLOAT, MPI_SUM,
2551 comm->mpi_comm_gpu_shared);
2552 /* Replace the wait time by the average over the ranks */
2553 load += -gpu_wait + gpu_wait_sum/comm->nrank_gpu_shared;
2555 #endif
2558 return load;
2561 static void set_slb_pme_dim_f(gmx_domdec_t *dd, int dim, real **dim_f)
2563 gmx_domdec_comm_t *comm;
2564 int i;
2566 comm = dd->comm;
2568 snew(*dim_f, dd->nc[dim]+1);
2569 (*dim_f)[0] = 0;
2570 for (i = 1; i < dd->nc[dim]; i++)
2572 if (comm->slb_frac[dim])
2574 (*dim_f)[i] = (*dim_f)[i-1] + comm->slb_frac[dim][i-1];
2576 else
2578 (*dim_f)[i] = (real)i/(real)dd->nc[dim];
2581 (*dim_f)[dd->nc[dim]] = 1;
2584 static void init_ddpme(gmx_domdec_t *dd, gmx_ddpme_t *ddpme, int dimind)
2586 int pmeindex, slab, nso, i;
2587 ivec xyz;
2589 if (dimind == 0 && dd->dim[0] == YY && dd->comm->npmenodes_x == 1)
2591 ddpme->dim = YY;
2593 else
2595 ddpme->dim = dimind;
2597 ddpme->dim_match = (ddpme->dim == dd->dim[dimind]);
2599 ddpme->nslab = (ddpme->dim == 0 ?
2600 dd->comm->npmenodes_x :
2601 dd->comm->npmenodes_y);
2603 if (ddpme->nslab <= 1)
2605 return;
2608 nso = dd->comm->npmenodes/ddpme->nslab;
2609 /* Determine for each PME slab the PP location range for dimension dim */
2610 snew(ddpme->pp_min, ddpme->nslab);
2611 snew(ddpme->pp_max, ddpme->nslab);
2612 for (slab = 0; slab < ddpme->nslab; slab++)
2614 ddpme->pp_min[slab] = dd->nc[dd->dim[dimind]] - 1;
2615 ddpme->pp_max[slab] = 0;
2617 for (i = 0; i < dd->nnodes; i++)
2619 ddindex2xyz(dd->nc, i, xyz);
2620 /* For y only use our y/z slab.
2621 * This assumes that the PME x grid size matches the DD grid size.
2623 if (dimind == 0 || xyz[XX] == dd->ci[XX])
2625 pmeindex = ddindex2pmeindex(dd, i);
2626 if (dimind == 0)
2628 slab = pmeindex/nso;
2630 else
2632 slab = pmeindex % ddpme->nslab;
2634 ddpme->pp_min[slab] = std::min(ddpme->pp_min[slab], xyz[dimind]);
2635 ddpme->pp_max[slab] = std::max(ddpme->pp_max[slab], xyz[dimind]);
2639 set_slb_pme_dim_f(dd, ddpme->dim, &ddpme->slb_dim_f);
2642 int dd_pme_maxshift_x(const gmx_domdec_t *dd)
2644 if (dd->comm->ddpme[0].dim == XX)
2646 return dd->comm->ddpme[0].maxshift;
2648 else
2650 return 0;
2654 int dd_pme_maxshift_y(const gmx_domdec_t *dd)
2656 if (dd->comm->ddpme[0].dim == YY)
2658 return dd->comm->ddpme[0].maxshift;
2660 else if (dd->comm->npmedecompdim >= 2 && dd->comm->ddpme[1].dim == YY)
2662 return dd->comm->ddpme[1].maxshift;
2664 else
2666 return 0;
2670 static void set_pme_maxshift(gmx_domdec_t *dd, gmx_ddpme_t *ddpme,
2671 gmx_bool bUniform, const gmx_ddbox_t *ddbox,
2672 const real *cell_f)
2674 gmx_domdec_comm_t *comm;
2675 int nc, ns, s;
2676 int *xmin, *xmax;
2677 real range, pme_boundary;
2678 int sh;
2680 comm = dd->comm;
2681 nc = dd->nc[ddpme->dim];
2682 ns = ddpme->nslab;
2684 if (!ddpme->dim_match)
2686 /* PP decomposition is not along dim: the worst situation */
2687 sh = ns/2;
2689 else if (ns <= 3 || (bUniform && ns == nc))
2691 /* The optimal situation */
2692 sh = 1;
2694 else
2696 /* We need to check for all pme nodes which nodes they
2697 * could possibly need to communicate with.
2699 xmin = ddpme->pp_min;
2700 xmax = ddpme->pp_max;
2701 /* Allow for atoms to be maximally 2/3 times the cut-off
2702 * out of their DD cell. This is a reasonable balance between
2703 * between performance and support for most charge-group/cut-off
2704 * combinations.
2706 range = 2.0/3.0*comm->cutoff/ddbox->box_size[ddpme->dim];
2707 /* Avoid extra communication when we are exactly at a boundary */
2708 range *= 0.999;
2710 sh = 1;
2711 for (s = 0; s < ns; s++)
2713 /* PME slab s spreads atoms between box frac. s/ns and (s+1)/ns */
2714 pme_boundary = (real)s/ns;
2715 while (sh+1 < ns &&
2716 ((s-(sh+1) >= 0 &&
2717 cell_f[xmax[s-(sh+1) ]+1] + range > pme_boundary) ||
2718 (s-(sh+1) < 0 &&
2719 cell_f[xmax[s-(sh+1)+ns]+1] - 1 + range > pme_boundary)))
2721 sh++;
2723 pme_boundary = (real)(s+1)/ns;
2724 while (sh+1 < ns &&
2725 ((s+(sh+1) < ns &&
2726 cell_f[xmin[s+(sh+1) ] ] - range < pme_boundary) ||
2727 (s+(sh+1) >= ns &&
2728 cell_f[xmin[s+(sh+1)-ns] ] + 1 - range < pme_boundary)))
2730 sh++;
2735 ddpme->maxshift = sh;
2737 if (debug)
2739 fprintf(debug, "PME slab communication range for dim %d is %d\n",
2740 ddpme->dim, ddpme->maxshift);
2744 static void check_box_size(gmx_domdec_t *dd, gmx_ddbox_t *ddbox)
2746 int d, dim;
2748 for (d = 0; d < dd->ndim; d++)
2750 dim = dd->dim[d];
2751 if (dim < ddbox->nboundeddim &&
2752 ddbox->box_size[dim]*ddbox->skew_fac[dim] <
2753 dd->nc[dim]*dd->comm->cellsize_limit*DD_CELL_MARGIN)
2755 gmx_fatal(FARGS, "The %c-size of the box (%f) times the triclinic skew factor (%f) is smaller than the number of DD cells (%d) times the smallest allowed cell size (%f)\n",
2756 dim2char(dim), ddbox->box_size[dim], ddbox->skew_fac[dim],
2757 dd->nc[dim], dd->comm->cellsize_limit);
2762 enum {
2763 setcellsizeslbLOCAL, setcellsizeslbMASTER, setcellsizeslbPULSE_ONLY
2766 /* Set the domain boundaries. Use for static (or no) load balancing,
2767 * and also for the starting state for dynamic load balancing.
2768 * setmode determine if and where the boundaries are stored, use enum above.
2769 * Returns the number communication pulses in npulse.
2771 static void set_dd_cell_sizes_slb(gmx_domdec_t *dd, const gmx_ddbox_t *ddbox,
2772 int setmode, ivec npulse)
2774 gmx_domdec_comm_t *comm;
2775 int d, j;
2776 rvec cellsize_min;
2777 real *cell_x, cell_dx, cellsize;
2779 comm = dd->comm;
2781 for (d = 0; d < DIM; d++)
2783 cellsize_min[d] = ddbox->box_size[d]*ddbox->skew_fac[d];
2784 npulse[d] = 1;
2785 if (dd->nc[d] == 1 || comm->slb_frac[d] == nullptr)
2787 /* Uniform grid */
2788 cell_dx = ddbox->box_size[d]/dd->nc[d];
2789 switch (setmode)
2791 case setcellsizeslbMASTER:
2792 for (j = 0; j < dd->nc[d]+1; j++)
2794 dd->ma->cell_x[d][j] = ddbox->box0[d] + j*cell_dx;
2796 break;
2797 case setcellsizeslbLOCAL:
2798 comm->cell_x0[d] = ddbox->box0[d] + (dd->ci[d] )*cell_dx;
2799 comm->cell_x1[d] = ddbox->box0[d] + (dd->ci[d]+1)*cell_dx;
2800 break;
2801 default:
2802 break;
2804 cellsize = cell_dx*ddbox->skew_fac[d];
2805 while (cellsize*npulse[d] < comm->cutoff)
2807 npulse[d]++;
2809 cellsize_min[d] = cellsize;
2811 else
2813 /* Statically load balanced grid */
2814 /* Also when we are not doing a master distribution we determine
2815 * all cell borders in a loop to obtain identical values
2816 * to the master distribution case and to determine npulse.
2818 if (setmode == setcellsizeslbMASTER)
2820 cell_x = dd->ma->cell_x[d];
2822 else
2824 snew(cell_x, dd->nc[d]+1);
2826 cell_x[0] = ddbox->box0[d];
2827 for (j = 0; j < dd->nc[d]; j++)
2829 cell_dx = ddbox->box_size[d]*comm->slb_frac[d][j];
2830 cell_x[j+1] = cell_x[j] + cell_dx;
2831 cellsize = cell_dx*ddbox->skew_fac[d];
2832 while (cellsize*npulse[d] < comm->cutoff &&
2833 npulse[d] < dd->nc[d]-1)
2835 npulse[d]++;
2837 cellsize_min[d] = std::min(cellsize_min[d], cellsize);
2839 if (setmode == setcellsizeslbLOCAL)
2841 comm->cell_x0[d] = cell_x[dd->ci[d]];
2842 comm->cell_x1[d] = cell_x[dd->ci[d]+1];
2844 if (setmode != setcellsizeslbMASTER)
2846 sfree(cell_x);
2849 /* The following limitation is to avoid that a cell would receive
2850 * some of its own home charge groups back over the periodic boundary.
2851 * Double charge groups cause trouble with the global indices.
2853 if (d < ddbox->npbcdim &&
2854 dd->nc[d] > 1 && npulse[d] >= dd->nc[d])
2856 char error_string[STRLEN];
2858 sprintf(error_string,
2859 "The box size in direction %c (%f) times the triclinic skew factor (%f) is too small for a cut-off of %f with %d domain decomposition cells, use 1 or more than %d %s or increase the box size in this direction",
2860 dim2char(d), ddbox->box_size[d], ddbox->skew_fac[d],
2861 comm->cutoff,
2862 dd->nc[d], dd->nc[d],
2863 dd->nnodes > dd->nc[d] ? "cells" : "ranks");
2865 if (setmode == setcellsizeslbLOCAL)
2867 gmx_fatal_collective(FARGS, dd->mpi_comm_all, DDMASTER(dd),
2868 error_string);
2870 else
2872 gmx_fatal(FARGS, error_string);
2877 if (!isDlbOn(comm))
2879 copy_rvec(cellsize_min, comm->cellsize_min);
2882 for (d = 0; d < comm->npmedecompdim; d++)
2884 set_pme_maxshift(dd, &comm->ddpme[d],
2885 comm->slb_frac[dd->dim[d]] == nullptr, ddbox,
2886 comm->ddpme[d].slb_dim_f);
2891 static void dd_cell_sizes_dlb_root_enforce_limits(gmx_domdec_t *dd,
2892 int d, int dim, domdec_root_t *root,
2893 const gmx_ddbox_t *ddbox,
2894 gmx_bool bUniform, gmx_int64_t step, real cellsize_limit_f, int range[])
2896 gmx_domdec_comm_t *comm;
2897 int ncd, i, j, nmin, nmin_old;
2898 gmx_bool bLimLo, bLimHi;
2899 real *cell_size;
2900 real fac, halfway, cellsize_limit_f_i, region_size;
2901 gmx_bool bPBC, bLastHi = FALSE;
2902 int nrange[] = {range[0], range[1]};
2904 region_size = root->cell_f[range[1]]-root->cell_f[range[0]];
2906 comm = dd->comm;
2908 ncd = dd->nc[dim];
2910 bPBC = (dim < ddbox->npbcdim);
2912 cell_size = root->buf_ncd;
2914 if (debug)
2916 fprintf(debug, "enforce_limits: %d %d\n", range[0], range[1]);
2919 /* First we need to check if the scaling does not make cells
2920 * smaller than the smallest allowed size.
2921 * We need to do this iteratively, since if a cell is too small,
2922 * it needs to be enlarged, which makes all the other cells smaller,
2923 * which could in turn make another cell smaller than allowed.
2925 for (i = range[0]; i < range[1]; i++)
2927 root->bCellMin[i] = FALSE;
2929 nmin = 0;
2932 nmin_old = nmin;
2933 /* We need the total for normalization */
2934 fac = 0;
2935 for (i = range[0]; i < range[1]; i++)
2937 if (root->bCellMin[i] == FALSE)
2939 fac += cell_size[i];
2942 fac = ( region_size - nmin*cellsize_limit_f)/fac; /* substracting cells already set to cellsize_limit_f */
2943 /* Determine the cell boundaries */
2944 for (i = range[0]; i < range[1]; i++)
2946 if (root->bCellMin[i] == FALSE)
2948 cell_size[i] *= fac;
2949 if (!bPBC && (i == 0 || i == dd->nc[dim] -1))
2951 cellsize_limit_f_i = 0;
2953 else
2955 cellsize_limit_f_i = cellsize_limit_f;
2957 if (cell_size[i] < cellsize_limit_f_i)
2959 root->bCellMin[i] = TRUE;
2960 cell_size[i] = cellsize_limit_f_i;
2961 nmin++;
2964 root->cell_f[i+1] = root->cell_f[i] + cell_size[i];
2967 while (nmin > nmin_old);
2969 i = range[1]-1;
2970 cell_size[i] = root->cell_f[i+1] - root->cell_f[i];
2971 /* For this check we should not use DD_CELL_MARGIN,
2972 * but a slightly smaller factor,
2973 * since rounding could get use below the limit.
2975 if (bPBC && cell_size[i] < cellsize_limit_f*DD_CELL_MARGIN2/DD_CELL_MARGIN)
2977 char buf[22];
2978 gmx_fatal(FARGS, "step %s: the dynamic load balancing could not balance dimension %c: box size %f, triclinic skew factor %f, #cells %d, minimum cell size %f\n",
2979 gmx_step_str(step, buf),
2980 dim2char(dim), ddbox->box_size[dim], ddbox->skew_fac[dim],
2981 ncd, comm->cellsize_min[dim]);
2984 root->bLimited = (nmin > 0) || (range[0] > 0) || (range[1] < ncd);
2986 if (!bUniform)
2988 /* Check if the boundary did not displace more than halfway
2989 * each of the cells it bounds, as this could cause problems,
2990 * especially when the differences between cell sizes are large.
2991 * If changes are applied, they will not make cells smaller
2992 * than the cut-off, as we check all the boundaries which
2993 * might be affected by a change and if the old state was ok,
2994 * the cells will at most be shrunk back to their old size.
2996 for (i = range[0]+1; i < range[1]; i++)
2998 halfway = 0.5*(root->old_cell_f[i] + root->old_cell_f[i-1]);
2999 if (root->cell_f[i] < halfway)
3001 root->cell_f[i] = halfway;
3002 /* Check if the change also causes shifts of the next boundaries */
3003 for (j = i+1; j < range[1]; j++)
3005 if (root->cell_f[j] < root->cell_f[j-1] + cellsize_limit_f)
3007 root->cell_f[j] = root->cell_f[j-1] + cellsize_limit_f;
3011 halfway = 0.5*(root->old_cell_f[i] + root->old_cell_f[i+1]);
3012 if (root->cell_f[i] > halfway)
3014 root->cell_f[i] = halfway;
3015 /* Check if the change also causes shifts of the next boundaries */
3016 for (j = i-1; j >= range[0]+1; j--)
3018 if (root->cell_f[j] > root->cell_f[j+1] - cellsize_limit_f)
3020 root->cell_f[j] = root->cell_f[j+1] - cellsize_limit_f;
3027 /* nrange is defined as [lower, upper) range for new call to enforce_limits */
3028 /* find highest violation of LimLo (a) and the following violation of LimHi (thus the lowest following) (b)
3029 * then call enforce_limits for (oldb,a), (a,b). In the next step: (b,nexta). oldb and nexta can be the boundaries.
3030 * for a and b nrange is used */
3031 if (d > 0)
3033 /* Take care of the staggering of the cell boundaries */
3034 if (bUniform)
3036 for (i = range[0]; i < range[1]; i++)
3038 root->cell_f_max0[i] = root->cell_f[i];
3039 root->cell_f_min1[i] = root->cell_f[i+1];
3042 else
3044 for (i = range[0]+1; i < range[1]; i++)
3046 bLimLo = (root->cell_f[i] < root->bound_min[i]);
3047 bLimHi = (root->cell_f[i] > root->bound_max[i]);
3048 if (bLimLo && bLimHi)
3050 /* Both limits violated, try the best we can */
3051 /* For this case we split the original range (range) in two parts and care about the other limitiations in the next iteration. */
3052 root->cell_f[i] = 0.5*(root->bound_min[i] + root->bound_max[i]);
3053 nrange[0] = range[0];
3054 nrange[1] = i;
3055 dd_cell_sizes_dlb_root_enforce_limits(dd, d, dim, root, ddbox, bUniform, step, cellsize_limit_f, nrange);
3057 nrange[0] = i;
3058 nrange[1] = range[1];
3059 dd_cell_sizes_dlb_root_enforce_limits(dd, d, dim, root, ddbox, bUniform, step, cellsize_limit_f, nrange);
3061 return;
3063 else if (bLimLo)
3065 /* root->cell_f[i] = root->bound_min[i]; */
3066 nrange[1] = i; /* only store violation location. There could be a LimLo violation following with an higher index */
3067 bLastHi = FALSE;
3069 else if (bLimHi && !bLastHi)
3071 bLastHi = TRUE;
3072 if (nrange[1] < range[1]) /* found a LimLo before */
3074 root->cell_f[nrange[1]] = root->bound_min[nrange[1]];
3075 dd_cell_sizes_dlb_root_enforce_limits(dd, d, dim, root, ddbox, bUniform, step, cellsize_limit_f, nrange);
3076 nrange[0] = nrange[1];
3078 root->cell_f[i] = root->bound_max[i];
3079 nrange[1] = i;
3080 dd_cell_sizes_dlb_root_enforce_limits(dd, d, dim, root, ddbox, bUniform, step, cellsize_limit_f, nrange);
3081 nrange[0] = i;
3082 nrange[1] = range[1];
3085 if (nrange[1] < range[1]) /* found last a LimLo */
3087 root->cell_f[nrange[1]] = root->bound_min[nrange[1]];
3088 dd_cell_sizes_dlb_root_enforce_limits(dd, d, dim, root, ddbox, bUniform, step, cellsize_limit_f, nrange);
3089 nrange[0] = nrange[1];
3090 nrange[1] = range[1];
3091 dd_cell_sizes_dlb_root_enforce_limits(dd, d, dim, root, ddbox, bUniform, step, cellsize_limit_f, nrange);
3093 else if (nrange[0] > range[0]) /* found at least one LimHi */
3095 dd_cell_sizes_dlb_root_enforce_limits(dd, d, dim, root, ddbox, bUniform, step, cellsize_limit_f, nrange);
3102 static void set_dd_cell_sizes_dlb_root(gmx_domdec_t *dd,
3103 int d, int dim, domdec_root_t *root,
3104 const gmx_ddbox_t *ddbox,
3105 gmx_bool bDynamicBox,
3106 gmx_bool bUniform, gmx_int64_t step)
3108 gmx_domdec_comm_t *comm;
3109 int ncd, d1, i, pos;
3110 real *cell_size;
3111 real load_aver, load_i, imbalance, change, change_max, sc;
3112 real cellsize_limit_f, dist_min_f, dist_min_f_hard, space;
3113 real change_limit;
3114 real relax = 0.5;
3115 gmx_bool bPBC;
3116 int range[] = { 0, 0 };
3118 comm = dd->comm;
3120 /* Convert the maximum change from the input percentage to a fraction */
3121 change_limit = comm->dlb_scale_lim*0.01;
3123 ncd = dd->nc[dim];
3125 bPBC = (dim < ddbox->npbcdim);
3127 cell_size = root->buf_ncd;
3129 /* Store the original boundaries */
3130 for (i = 0; i < ncd+1; i++)
3132 root->old_cell_f[i] = root->cell_f[i];
3134 if (bUniform)
3136 for (i = 0; i < ncd; i++)
3138 cell_size[i] = 1.0/ncd;
3141 else if (dd_load_count(comm) > 0)
3143 load_aver = comm->load[d].sum_m/ncd;
3144 change_max = 0;
3145 for (i = 0; i < ncd; i++)
3147 /* Determine the relative imbalance of cell i */
3148 load_i = comm->load[d].load[i*comm->load[d].nload+2];
3149 imbalance = (load_i - load_aver)/(load_aver > 0 ? load_aver : 1);
3150 /* Determine the change of the cell size using underrelaxation */
3151 change = -relax*imbalance;
3152 change_max = std::max(change_max, std::max(change, -change));
3154 /* Limit the amount of scaling.
3155 * We need to use the same rescaling for all cells in one row,
3156 * otherwise the load balancing might not converge.
3158 sc = relax;
3159 if (change_max > change_limit)
3161 sc *= change_limit/change_max;
3163 for (i = 0; i < ncd; i++)
3165 /* Determine the relative imbalance of cell i */
3166 load_i = comm->load[d].load[i*comm->load[d].nload+2];
3167 imbalance = (load_i - load_aver)/(load_aver > 0 ? load_aver : 1);
3168 /* Determine the change of the cell size using underrelaxation */
3169 change = -sc*imbalance;
3170 cell_size[i] = (root->cell_f[i+1]-root->cell_f[i])*(1 + change);
3174 cellsize_limit_f = cellsize_min_dlb(comm, d, dim)/ddbox->box_size[dim];
3175 cellsize_limit_f *= DD_CELL_MARGIN;
3176 dist_min_f_hard = grid_jump_limit(comm, comm->cutoff, d)/ddbox->box_size[dim];
3177 dist_min_f = dist_min_f_hard * DD_CELL_MARGIN;
3178 if (ddbox->tric_dir[dim])
3180 cellsize_limit_f /= ddbox->skew_fac[dim];
3181 dist_min_f /= ddbox->skew_fac[dim];
3183 if (bDynamicBox && d > 0)
3185 dist_min_f *= DD_PRES_SCALE_MARGIN;
3187 if (d > 0 && !bUniform)
3189 /* Make sure that the grid is not shifted too much */
3190 for (i = 1; i < ncd; i++)
3192 if (root->cell_f_min1[i] - root->cell_f_max0[i-1] < 2 * dist_min_f_hard)
3194 gmx_incons("Inconsistent DD boundary staggering limits!");
3196 root->bound_min[i] = root->cell_f_max0[i-1] + dist_min_f;
3197 space = root->cell_f[i] - (root->cell_f_max0[i-1] + dist_min_f);
3198 if (space > 0)
3200 root->bound_min[i] += 0.5*space;
3202 root->bound_max[i] = root->cell_f_min1[i] - dist_min_f;
3203 space = root->cell_f[i] - (root->cell_f_min1[i] - dist_min_f);
3204 if (space < 0)
3206 root->bound_max[i] += 0.5*space;
3208 if (debug)
3210 fprintf(debug,
3211 "dim %d boundary %d %.3f < %.3f < %.3f < %.3f < %.3f\n",
3212 d, i,
3213 root->cell_f_max0[i-1] + dist_min_f,
3214 root->bound_min[i], root->cell_f[i], root->bound_max[i],
3215 root->cell_f_min1[i] - dist_min_f);
3219 range[1] = ncd;
3220 root->cell_f[0] = 0;
3221 root->cell_f[ncd] = 1;
3222 dd_cell_sizes_dlb_root_enforce_limits(dd, d, dim, root, ddbox, bUniform, step, cellsize_limit_f, range);
3225 /* After the checks above, the cells should obey the cut-off
3226 * restrictions, but it does not hurt to check.
3228 for (i = 0; i < ncd; i++)
3230 if (debug)
3232 fprintf(debug, "Relative bounds dim %d cell %d: %f %f\n",
3233 dim, i, root->cell_f[i], root->cell_f[i+1]);
3236 if ((bPBC || (i != 0 && i != dd->nc[dim]-1)) &&
3237 root->cell_f[i+1] - root->cell_f[i] <
3238 cellsize_limit_f/DD_CELL_MARGIN)
3240 char buf[22];
3241 fprintf(stderr,
3242 "\nWARNING step %s: direction %c, cell %d too small: %f\n",
3243 gmx_step_str(step, buf), dim2char(dim), i,
3244 (root->cell_f[i+1] - root->cell_f[i])
3245 *ddbox->box_size[dim]*ddbox->skew_fac[dim]);
3249 pos = ncd + 1;
3250 /* Store the cell boundaries of the lower dimensions at the end */
3251 for (d1 = 0; d1 < d; d1++)
3253 root->cell_f[pos++] = comm->cell_f0[d1];
3254 root->cell_f[pos++] = comm->cell_f1[d1];
3257 if (d < comm->npmedecompdim)
3259 /* The master determines the maximum shift for
3260 * the coordinate communication between separate PME nodes.
3262 set_pme_maxshift(dd, &comm->ddpme[d], bUniform, ddbox, root->cell_f);
3264 root->cell_f[pos++] = comm->ddpme[0].maxshift;
3265 if (d >= 1)
3267 root->cell_f[pos++] = comm->ddpme[1].maxshift;
3271 static void relative_to_absolute_cell_bounds(gmx_domdec_t *dd,
3272 const gmx_ddbox_t *ddbox,
3273 int dimind)
3275 gmx_domdec_comm_t *comm;
3276 int dim;
3278 comm = dd->comm;
3280 /* Set the cell dimensions */
3281 dim = dd->dim[dimind];
3282 comm->cell_x0[dim] = comm->cell_f0[dimind]*ddbox->box_size[dim];
3283 comm->cell_x1[dim] = comm->cell_f1[dimind]*ddbox->box_size[dim];
3284 if (dim >= ddbox->nboundeddim)
3286 comm->cell_x0[dim] += ddbox->box0[dim];
3287 comm->cell_x1[dim] += ddbox->box0[dim];
3291 static void distribute_dd_cell_sizes_dlb(gmx_domdec_t *dd,
3292 int d, int dim, real *cell_f_row,
3293 const gmx_ddbox_t *ddbox)
3295 gmx_domdec_comm_t *comm;
3296 int d1, pos;
3298 comm = dd->comm;
3300 #if GMX_MPI
3301 /* Each node would only need to know two fractions,
3302 * but it is probably cheaper to broadcast the whole array.
3304 MPI_Bcast(cell_f_row, DD_CELL_F_SIZE(dd, d)*sizeof(real), MPI_BYTE,
3305 0, comm->mpi_comm_load[d]);
3306 #endif
3307 /* Copy the fractions for this dimension from the buffer */
3308 comm->cell_f0[d] = cell_f_row[dd->ci[dim] ];
3309 comm->cell_f1[d] = cell_f_row[dd->ci[dim]+1];
3310 /* The whole array was communicated, so set the buffer position */
3311 pos = dd->nc[dim] + 1;
3312 for (d1 = 0; d1 <= d; d1++)
3314 if (d1 < d)
3316 /* Copy the cell fractions of the lower dimensions */
3317 comm->cell_f0[d1] = cell_f_row[pos++];
3318 comm->cell_f1[d1] = cell_f_row[pos++];
3320 relative_to_absolute_cell_bounds(dd, ddbox, d1);
3322 /* Convert the communicated shift from float to int */
3323 comm->ddpme[0].maxshift = (int)(cell_f_row[pos++] + 0.5);
3324 if (d >= 1)
3326 comm->ddpme[1].maxshift = (int)(cell_f_row[pos++] + 0.5);
3330 static void set_dd_cell_sizes_dlb_change(gmx_domdec_t *dd,
3331 const gmx_ddbox_t *ddbox,
3332 gmx_bool bDynamicBox,
3333 gmx_bool bUniform, gmx_int64_t step)
3335 gmx_domdec_comm_t *comm;
3336 int d, dim, d1;
3337 gmx_bool bRowMember, bRowRoot;
3338 real *cell_f_row;
3340 comm = dd->comm;
3342 for (d = 0; d < dd->ndim; d++)
3344 dim = dd->dim[d];
3345 bRowMember = TRUE;
3346 bRowRoot = TRUE;
3347 for (d1 = d; d1 < dd->ndim; d1++)
3349 if (dd->ci[dd->dim[d1]] > 0)
3351 if (d1 != d)
3353 bRowMember = FALSE;
3355 bRowRoot = FALSE;
3358 if (bRowMember)
3360 if (bRowRoot)
3362 set_dd_cell_sizes_dlb_root(dd, d, dim, comm->root[d],
3363 ddbox, bDynamicBox, bUniform, step);
3364 cell_f_row = comm->root[d]->cell_f;
3366 else
3368 cell_f_row = comm->cell_f_row;
3370 distribute_dd_cell_sizes_dlb(dd, d, dim, cell_f_row, ddbox);
3375 static void set_dd_cell_sizes_dlb_nochange(gmx_domdec_t *dd,
3376 const gmx_ddbox_t *ddbox)
3378 int d;
3380 /* This function assumes the box is static and should therefore
3381 * not be called when the box has changed since the last
3382 * call to dd_partition_system.
3384 for (d = 0; d < dd->ndim; d++)
3386 relative_to_absolute_cell_bounds(dd, ddbox, d);
3392 static void set_dd_cell_sizes_dlb(gmx_domdec_t *dd,
3393 const gmx_ddbox_t *ddbox, gmx_bool bDynamicBox,
3394 gmx_bool bUniform, gmx_bool bDoDLB, gmx_int64_t step,
3395 gmx_wallcycle_t wcycle)
3397 gmx_domdec_comm_t *comm;
3398 int dim;
3400 comm = dd->comm;
3402 if (bDoDLB)
3404 wallcycle_start(wcycle, ewcDDCOMMBOUND);
3405 set_dd_cell_sizes_dlb_change(dd, ddbox, bDynamicBox, bUniform, step);
3406 wallcycle_stop(wcycle, ewcDDCOMMBOUND);
3408 else if (bDynamicBox)
3410 set_dd_cell_sizes_dlb_nochange(dd, ddbox);
3413 /* Set the dimensions for which no DD is used */
3414 for (dim = 0; dim < DIM; dim++)
3416 if (dd->nc[dim] == 1)
3418 comm->cell_x0[dim] = 0;
3419 comm->cell_x1[dim] = ddbox->box_size[dim];
3420 if (dim >= ddbox->nboundeddim)
3422 comm->cell_x0[dim] += ddbox->box0[dim];
3423 comm->cell_x1[dim] += ddbox->box0[dim];
3429 static void realloc_comm_ind(gmx_domdec_t *dd, ivec npulse)
3431 int d, np, i;
3432 gmx_domdec_comm_dim_t *cd;
3434 for (d = 0; d < dd->ndim; d++)
3436 cd = &dd->comm->cd[d];
3437 np = npulse[dd->dim[d]];
3438 if (np > cd->np_nalloc)
3440 if (debug)
3442 fprintf(debug, "(Re)allocing cd for %c to %d pulses\n",
3443 dim2char(dd->dim[d]), np);
3445 if (DDMASTER(dd) && cd->np_nalloc > 0)
3447 fprintf(stderr, "\nIncreasing the number of cell to communicate in dimension %c to %d for the first time\n", dim2char(dd->dim[d]), np);
3449 srenew(cd->ind, np);
3450 for (i = cd->np_nalloc; i < np; i++)
3452 cd->ind[i].index = nullptr;
3453 cd->ind[i].nalloc = 0;
3455 cd->np_nalloc = np;
3457 cd->np = np;
3462 static void set_dd_cell_sizes(gmx_domdec_t *dd,
3463 gmx_ddbox_t *ddbox, gmx_bool bDynamicBox,
3464 gmx_bool bUniform, gmx_bool bDoDLB, gmx_int64_t step,
3465 gmx_wallcycle_t wcycle)
3467 gmx_domdec_comm_t *comm;
3468 int d;
3469 ivec npulse;
3471 comm = dd->comm;
3473 /* Copy the old cell boundaries for the cg displacement check */
3474 copy_rvec(comm->cell_x0, comm->old_cell_x0);
3475 copy_rvec(comm->cell_x1, comm->old_cell_x1);
3477 if (isDlbOn(comm))
3479 if (DDMASTER(dd))
3481 check_box_size(dd, ddbox);
3483 set_dd_cell_sizes_dlb(dd, ddbox, bDynamicBox, bUniform, bDoDLB, step, wcycle);
3485 else
3487 set_dd_cell_sizes_slb(dd, ddbox, setcellsizeslbLOCAL, npulse);
3488 realloc_comm_ind(dd, npulse);
3491 if (debug)
3493 for (d = 0; d < DIM; d++)
3495 fprintf(debug, "cell_x[%d] %f - %f skew_fac %f\n",
3496 d, comm->cell_x0[d], comm->cell_x1[d], ddbox->skew_fac[d]);
3501 static void comm_dd_ns_cell_sizes(gmx_domdec_t *dd,
3502 gmx_ddbox_t *ddbox,
3503 rvec cell_ns_x0, rvec cell_ns_x1,
3504 gmx_int64_t step)
3506 gmx_domdec_comm_t *comm;
3507 int dim_ind, dim;
3509 comm = dd->comm;
3511 for (dim_ind = 0; dim_ind < dd->ndim; dim_ind++)
3513 dim = dd->dim[dim_ind];
3515 /* Without PBC we don't have restrictions on the outer cells */
3516 if (!(dim >= ddbox->npbcdim &&
3517 (dd->ci[dim] == 0 || dd->ci[dim] == dd->nc[dim] - 1)) &&
3518 isDlbOn(comm) &&
3519 (comm->cell_x1[dim] - comm->cell_x0[dim])*ddbox->skew_fac[dim] <
3520 comm->cellsize_min[dim])
3522 char buf[22];
3523 gmx_fatal(FARGS, "step %s: The %c-size (%f) times the triclinic skew factor (%f) is smaller than the smallest allowed cell size (%f) for domain decomposition grid cell %d %d %d",
3524 gmx_step_str(step, buf), dim2char(dim),
3525 comm->cell_x1[dim] - comm->cell_x0[dim],
3526 ddbox->skew_fac[dim],
3527 dd->comm->cellsize_min[dim],
3528 dd->ci[XX], dd->ci[YY], dd->ci[ZZ]);
3532 if ((isDlbOn(dd->comm) && dd->ndim > 1) || ddbox->nboundeddim < DIM)
3534 /* Communicate the boundaries and update cell_ns_x0/1 */
3535 dd_move_cellx(dd, ddbox, cell_ns_x0, cell_ns_x1);
3536 if (isDlbOn(dd->comm) && dd->ndim > 1)
3538 check_grid_jump(step, dd, dd->comm->cutoff, ddbox, TRUE);
3543 static void make_tric_corr_matrix(int npbcdim, const matrix box, matrix tcm)
3545 if (YY < npbcdim)
3547 tcm[YY][XX] = -box[YY][XX]/box[YY][YY];
3549 else
3551 tcm[YY][XX] = 0;
3553 if (ZZ < npbcdim)
3555 tcm[ZZ][XX] = -(box[ZZ][YY]*tcm[YY][XX] + box[ZZ][XX])/box[ZZ][ZZ];
3556 tcm[ZZ][YY] = -box[ZZ][YY]/box[ZZ][ZZ];
3558 else
3560 tcm[ZZ][XX] = 0;
3561 tcm[ZZ][YY] = 0;
3565 static void check_screw_box(const matrix box)
3567 /* Mathematical limitation */
3568 if (box[YY][XX] != 0 || box[ZZ][XX] != 0)
3570 gmx_fatal(FARGS, "With screw pbc the unit cell can not have non-zero off-diagonal x-components");
3573 /* Limitation due to the asymmetry of the eighth shell method */
3574 if (box[ZZ][YY] != 0)
3576 gmx_fatal(FARGS, "pbc=screw with non-zero box_zy is not supported");
3580 static void distribute_cg(FILE *fplog,
3581 const matrix box, ivec tric_dir, t_block *cgs, rvec pos[],
3582 gmx_domdec_t *dd)
3584 gmx_domdec_master_t *ma;
3585 int **tmp_ind = nullptr, *tmp_nalloc = nullptr;
3586 int i, icg, j, k, k0, k1, d;
3587 matrix tcm;
3588 rvec cg_cm;
3589 ivec ind;
3590 real nrcg, inv_ncg, pos_d;
3591 int *cgindex;
3592 gmx_bool bScrew;
3594 ma = dd->ma;
3596 snew(tmp_nalloc, dd->nnodes);
3597 snew(tmp_ind, dd->nnodes);
3598 for (i = 0; i < dd->nnodes; i++)
3600 tmp_nalloc[i] = over_alloc_large(cgs->nr/dd->nnodes+1);
3601 snew(tmp_ind[i], tmp_nalloc[i]);
3604 /* Clear the count */
3605 for (i = 0; i < dd->nnodes; i++)
3607 ma->ncg[i] = 0;
3608 ma->nat[i] = 0;
3611 make_tric_corr_matrix(dd->npbcdim, box, tcm);
3613 cgindex = cgs->index;
3615 /* Compute the center of geometry for all charge groups */
3616 for (icg = 0; icg < cgs->nr; icg++)
3618 k0 = cgindex[icg];
3619 k1 = cgindex[icg+1];
3620 nrcg = k1 - k0;
3621 if (nrcg == 1)
3623 copy_rvec(pos[k0], cg_cm);
3625 else
3627 inv_ncg = 1.0/nrcg;
3629 clear_rvec(cg_cm);
3630 for (k = k0; (k < k1); k++)
3632 rvec_inc(cg_cm, pos[k]);
3634 for (d = 0; (d < DIM); d++)
3636 cg_cm[d] *= inv_ncg;
3639 /* Put the charge group in the box and determine the cell index */
3640 for (d = DIM-1; d >= 0; d--)
3642 pos_d = cg_cm[d];
3643 if (d < dd->npbcdim)
3645 bScrew = (dd->bScrewPBC && d == XX);
3646 if (tric_dir[d] && dd->nc[d] > 1)
3648 /* Use triclinic coordintates for this dimension */
3649 for (j = d+1; j < DIM; j++)
3651 pos_d += cg_cm[j]*tcm[j][d];
3654 while (pos_d >= box[d][d])
3656 pos_d -= box[d][d];
3657 rvec_dec(cg_cm, box[d]);
3658 if (bScrew)
3660 cg_cm[YY] = box[YY][YY] - cg_cm[YY];
3661 cg_cm[ZZ] = box[ZZ][ZZ] - cg_cm[ZZ];
3663 for (k = k0; (k < k1); k++)
3665 rvec_dec(pos[k], box[d]);
3666 if (bScrew)
3668 pos[k][YY] = box[YY][YY] - pos[k][YY];
3669 pos[k][ZZ] = box[ZZ][ZZ] - pos[k][ZZ];
3673 while (pos_d < 0)
3675 pos_d += box[d][d];
3676 rvec_inc(cg_cm, box[d]);
3677 if (bScrew)
3679 cg_cm[YY] = box[YY][YY] - cg_cm[YY];
3680 cg_cm[ZZ] = box[ZZ][ZZ] - cg_cm[ZZ];
3682 for (k = k0; (k < k1); k++)
3684 rvec_inc(pos[k], box[d]);
3685 if (bScrew)
3687 pos[k][YY] = box[YY][YY] - pos[k][YY];
3688 pos[k][ZZ] = box[ZZ][ZZ] - pos[k][ZZ];
3693 /* This could be done more efficiently */
3694 ind[d] = 0;
3695 while (ind[d]+1 < dd->nc[d] && pos_d >= ma->cell_x[d][ind[d]+1])
3697 ind[d]++;
3700 i = dd_index(dd->nc, ind);
3701 if (ma->ncg[i] == tmp_nalloc[i])
3703 tmp_nalloc[i] = over_alloc_large(ma->ncg[i]+1);
3704 srenew(tmp_ind[i], tmp_nalloc[i]);
3706 tmp_ind[i][ma->ncg[i]] = icg;
3707 ma->ncg[i]++;
3708 ma->nat[i] += cgindex[icg+1] - cgindex[icg];
3711 k1 = 0;
3712 for (i = 0; i < dd->nnodes; i++)
3714 ma->index[i] = k1;
3715 for (k = 0; k < ma->ncg[i]; k++)
3717 ma->cg[k1++] = tmp_ind[i][k];
3720 ma->index[dd->nnodes] = k1;
3722 for (i = 0; i < dd->nnodes; i++)
3724 sfree(tmp_ind[i]);
3726 sfree(tmp_ind);
3727 sfree(tmp_nalloc);
3729 if (fplog)
3731 // Use double for the sums to avoid natoms^2 overflowing
3732 // (65537^2 > 2^32)
3733 int nat_sum, nat_min, nat_max;
3734 double nat2_sum;
3736 nat_sum = 0;
3737 nat2_sum = 0;
3738 nat_min = ma->nat[0];
3739 nat_max = ma->nat[0];
3740 for (i = 0; i < dd->nnodes; i++)
3742 nat_sum += ma->nat[i];
3743 // cast to double to avoid integer overflows when squaring
3744 nat2_sum += gmx::square(static_cast<double>(ma->nat[i]));
3745 nat_min = std::min(nat_min, ma->nat[i]);
3746 nat_max = std::max(nat_max, ma->nat[i]);
3748 nat_sum /= dd->nnodes;
3749 nat2_sum /= dd->nnodes;
3751 fprintf(fplog, "Atom distribution over %d domains: av %d stddev %d min %d max %d\n",
3752 dd->nnodes,
3753 nat_sum,
3754 static_cast<int>(std::sqrt(nat2_sum - gmx::square(static_cast<double>(nat_sum)) + 0.5)),
3755 nat_min, nat_max);
3759 static void get_cg_distribution(FILE *fplog, gmx_domdec_t *dd,
3760 t_block *cgs, const matrix box, gmx_ddbox_t *ddbox,
3761 rvec pos[])
3763 gmx_domdec_master_t *ma = nullptr;
3764 ivec npulse;
3765 int i, cg_gl;
3766 int *ibuf, buf2[2] = { 0, 0 };
3767 gmx_bool bMaster = DDMASTER(dd);
3769 if (bMaster)
3771 ma = dd->ma;
3773 if (dd->bScrewPBC)
3775 check_screw_box(box);
3778 set_dd_cell_sizes_slb(dd, ddbox, setcellsizeslbMASTER, npulse);
3780 distribute_cg(fplog, box, ddbox->tric_dir, cgs, pos, dd);
3781 for (i = 0; i < dd->nnodes; i++)
3783 ma->ibuf[2*i] = ma->ncg[i];
3784 ma->ibuf[2*i+1] = ma->nat[i];
3786 ibuf = ma->ibuf;
3788 else
3790 ibuf = nullptr;
3792 dd_scatter(dd, 2*sizeof(int), ibuf, buf2);
3794 dd->ncg_home = buf2[0];
3795 dd->nat_home = buf2[1];
3796 dd->ncg_tot = dd->ncg_home;
3797 dd->nat_tot = dd->nat_home;
3798 if (dd->ncg_home > dd->cg_nalloc || dd->cg_nalloc == 0)
3800 dd->cg_nalloc = over_alloc_dd(dd->ncg_home);
3801 srenew(dd->index_gl, dd->cg_nalloc);
3802 srenew(dd->cgindex, dd->cg_nalloc+1);
3804 if (bMaster)
3806 for (i = 0; i < dd->nnodes; i++)
3808 ma->ibuf[i] = ma->ncg[i]*sizeof(int);
3809 ma->ibuf[dd->nnodes+i] = ma->index[i]*sizeof(int);
3813 dd_scatterv(dd,
3814 bMaster ? ma->ibuf : nullptr,
3815 bMaster ? ma->ibuf+dd->nnodes : nullptr,
3816 bMaster ? ma->cg : nullptr,
3817 dd->ncg_home*sizeof(int), dd->index_gl);
3819 /* Determine the home charge group sizes */
3820 dd->cgindex[0] = 0;
3821 for (i = 0; i < dd->ncg_home; i++)
3823 cg_gl = dd->index_gl[i];
3824 dd->cgindex[i+1] =
3825 dd->cgindex[i] + cgs->index[cg_gl+1] - cgs->index[cg_gl];
3828 if (debug)
3830 fprintf(debug, "Home charge groups:\n");
3831 for (i = 0; i < dd->ncg_home; i++)
3833 fprintf(debug, " %d", dd->index_gl[i]);
3834 if (i % 10 == 9)
3836 fprintf(debug, "\n");
3839 fprintf(debug, "\n");
3843 static int compact_and_copy_vec_at(int ncg, int *move,
3844 int *cgindex,
3845 int nvec, int vec,
3846 rvec *src, gmx_domdec_comm_t *comm,
3847 gmx_bool bCompact)
3849 int m, icg, i, i0, i1, nrcg;
3850 int home_pos;
3851 int pos_vec[DIM*2];
3853 home_pos = 0;
3855 for (m = 0; m < DIM*2; m++)
3857 pos_vec[m] = 0;
3860 i0 = 0;
3861 for (icg = 0; icg < ncg; icg++)
3863 i1 = cgindex[icg+1];
3864 m = move[icg];
3865 if (m == -1)
3867 if (bCompact)
3869 /* Compact the home array in place */
3870 for (i = i0; i < i1; i++)
3872 copy_rvec(src[i], src[home_pos++]);
3876 else
3878 /* Copy to the communication buffer */
3879 nrcg = i1 - i0;
3880 pos_vec[m] += 1 + vec*nrcg;
3881 for (i = i0; i < i1; i++)
3883 copy_rvec(src[i], comm->cgcm_state[m][pos_vec[m]++]);
3885 pos_vec[m] += (nvec - vec - 1)*nrcg;
3887 if (!bCompact)
3889 home_pos += i1 - i0;
3891 i0 = i1;
3894 return home_pos;
3897 static int compact_and_copy_vec_cg(int ncg, int *move,
3898 int *cgindex,
3899 int nvec, rvec *src, gmx_domdec_comm_t *comm,
3900 gmx_bool bCompact)
3902 int m, icg, i0, i1, nrcg;
3903 int home_pos;
3904 int pos_vec[DIM*2];
3906 home_pos = 0;
3908 for (m = 0; m < DIM*2; m++)
3910 pos_vec[m] = 0;
3913 i0 = 0;
3914 for (icg = 0; icg < ncg; icg++)
3916 i1 = cgindex[icg+1];
3917 m = move[icg];
3918 if (m == -1)
3920 if (bCompact)
3922 /* Compact the home array in place */
3923 copy_rvec(src[icg], src[home_pos++]);
3926 else
3928 nrcg = i1 - i0;
3929 /* Copy to the communication buffer */
3930 copy_rvec(src[icg], comm->cgcm_state[m][pos_vec[m]]);
3931 pos_vec[m] += 1 + nrcg*nvec;
3933 i0 = i1;
3935 if (!bCompact)
3937 home_pos = ncg;
3940 return home_pos;
3943 static int compact_ind(int ncg, int *move,
3944 int *index_gl, int *cgindex,
3945 int *gatindex,
3946 gmx_ga2la_t *ga2la, char *bLocalCG,
3947 int *cginfo)
3949 int cg, nat, a0, a1, a, a_gl;
3950 int home_pos;
3952 home_pos = 0;
3953 nat = 0;
3954 for (cg = 0; cg < ncg; cg++)
3956 a0 = cgindex[cg];
3957 a1 = cgindex[cg+1];
3958 if (move[cg] == -1)
3960 /* Compact the home arrays in place.
3961 * Anything that can be done here avoids access to global arrays.
3963 cgindex[home_pos] = nat;
3964 for (a = a0; a < a1; a++)
3966 a_gl = gatindex[a];
3967 gatindex[nat] = a_gl;
3968 /* The cell number stays 0, so we don't need to set it */
3969 ga2la_change_la(ga2la, a_gl, nat);
3970 nat++;
3972 index_gl[home_pos] = index_gl[cg];
3973 cginfo[home_pos] = cginfo[cg];
3974 /* The charge group remains local, so bLocalCG does not change */
3975 home_pos++;
3977 else
3979 /* Clear the global indices */
3980 for (a = a0; a < a1; a++)
3982 ga2la_del(ga2la, gatindex[a]);
3984 if (bLocalCG)
3986 bLocalCG[index_gl[cg]] = FALSE;
3990 cgindex[home_pos] = nat;
3992 return home_pos;
3995 static void clear_and_mark_ind(int ncg, int *move,
3996 int *index_gl, int *cgindex, int *gatindex,
3997 gmx_ga2la_t *ga2la, char *bLocalCG,
3998 int *cell_index)
4000 int cg, a0, a1, a;
4002 for (cg = 0; cg < ncg; cg++)
4004 if (move[cg] >= 0)
4006 a0 = cgindex[cg];
4007 a1 = cgindex[cg+1];
4008 /* Clear the global indices */
4009 for (a = a0; a < a1; a++)
4011 ga2la_del(ga2la, gatindex[a]);
4013 if (bLocalCG)
4015 bLocalCG[index_gl[cg]] = FALSE;
4017 /* Signal that this cg has moved using the ns cell index.
4018 * Here we set it to -1. fill_grid will change it
4019 * from -1 to NSGRID_SIGNAL_MOVED_FAC*grid->ncells.
4021 cell_index[cg] = -1;
4026 static void print_cg_move(FILE *fplog,
4027 gmx_domdec_t *dd,
4028 gmx_int64_t step, int cg, int dim, int dir,
4029 gmx_bool bHaveCgcmOld, real limitd,
4030 rvec cm_old, rvec cm_new, real pos_d)
4032 gmx_domdec_comm_t *comm;
4033 char buf[22];
4035 comm = dd->comm;
4037 fprintf(fplog, "\nStep %s:\n", gmx_step_str(step, buf));
4038 if (limitd > 0)
4040 fprintf(fplog, "%s %d moved more than the distance allowed by the domain decomposition (%f) in direction %c\n",
4041 dd->comm->bCGs ? "The charge group starting at atom" : "Atom",
4042 ddglatnr(dd, dd->cgindex[cg]), limitd, dim2char(dim));
4044 else
4046 /* We don't have a limiting distance available: don't print it */
4047 fprintf(fplog, "%s %d moved more than the distance allowed by the domain decomposition in direction %c\n",
4048 dd->comm->bCGs ? "The charge group starting at atom" : "Atom",
4049 ddglatnr(dd, dd->cgindex[cg]), dim2char(dim));
4051 fprintf(fplog, "distance out of cell %f\n",
4052 dir == 1 ? pos_d - comm->cell_x1[dim] : pos_d - comm->cell_x0[dim]);
4053 if (bHaveCgcmOld)
4055 fprintf(fplog, "Old coordinates: %8.3f %8.3f %8.3f\n",
4056 cm_old[XX], cm_old[YY], cm_old[ZZ]);
4058 fprintf(fplog, "New coordinates: %8.3f %8.3f %8.3f\n",
4059 cm_new[XX], cm_new[YY], cm_new[ZZ]);
4060 fprintf(fplog, "Old cell boundaries in direction %c: %8.3f %8.3f\n",
4061 dim2char(dim),
4062 comm->old_cell_x0[dim], comm->old_cell_x1[dim]);
4063 fprintf(fplog, "New cell boundaries in direction %c: %8.3f %8.3f\n",
4064 dim2char(dim),
4065 comm->cell_x0[dim], comm->cell_x1[dim]);
4068 static void cg_move_error(FILE *fplog,
4069 gmx_domdec_t *dd,
4070 gmx_int64_t step, int cg, int dim, int dir,
4071 gmx_bool bHaveCgcmOld, real limitd,
4072 rvec cm_old, rvec cm_new, real pos_d)
4074 if (fplog)
4076 print_cg_move(fplog, dd, step, cg, dim, dir,
4077 bHaveCgcmOld, limitd, cm_old, cm_new, pos_d);
4079 print_cg_move(stderr, dd, step, cg, dim, dir,
4080 bHaveCgcmOld, limitd, cm_old, cm_new, pos_d);
4081 gmx_fatal(FARGS,
4082 "%s moved too far between two domain decomposition steps\n"
4083 "This usually means that your system is not well equilibrated",
4084 dd->comm->bCGs ? "A charge group" : "An atom");
4087 static void rotate_state_atom(t_state *state, int a)
4089 if (state->flags & (1 << estX))
4091 /* Rotate the complete state; for a rectangular box only */
4092 state->x[a][YY] = state->box[YY][YY] - state->x[a][YY];
4093 state->x[a][ZZ] = state->box[ZZ][ZZ] - state->x[a][ZZ];
4095 if (state->flags & (1 << estV))
4097 state->v[a][YY] = -state->v[a][YY];
4098 state->v[a][ZZ] = -state->v[a][ZZ];
4100 if (state->flags & (1 << estCGP))
4102 state->cg_p[a][YY] = -state->cg_p[a][YY];
4103 state->cg_p[a][ZZ] = -state->cg_p[a][ZZ];
4107 static int *get_moved(gmx_domdec_comm_t *comm, int natoms)
4109 if (natoms > comm->moved_nalloc)
4111 /* Contents should be preserved here */
4112 comm->moved_nalloc = over_alloc_dd(natoms);
4113 srenew(comm->moved, comm->moved_nalloc);
4116 return comm->moved;
4119 static void calc_cg_move(FILE *fplog, gmx_int64_t step,
4120 gmx_domdec_t *dd,
4121 t_state *state,
4122 ivec tric_dir, matrix tcm,
4123 rvec cell_x0, rvec cell_x1,
4124 rvec limitd, rvec limit0, rvec limit1,
4125 const int *cgindex,
4126 int cg_start, int cg_end,
4127 rvec *cg_cm,
4128 int *move)
4130 int npbcdim;
4131 int cg, k, k0, k1, d, dim, d2;
4132 int mc, nrcg;
4133 int flag;
4134 gmx_bool bScrew;
4135 ivec dev;
4136 real inv_ncg, pos_d;
4137 rvec cm_new;
4139 npbcdim = dd->npbcdim;
4141 for (cg = cg_start; cg < cg_end; cg++)
4143 k0 = cgindex[cg];
4144 k1 = cgindex[cg+1];
4145 nrcg = k1 - k0;
4146 if (nrcg == 1)
4148 copy_rvec(state->x[k0], cm_new);
4150 else
4152 inv_ncg = 1.0/nrcg;
4154 clear_rvec(cm_new);
4155 for (k = k0; (k < k1); k++)
4157 rvec_inc(cm_new, state->x[k]);
4159 for (d = 0; (d < DIM); d++)
4161 cm_new[d] = inv_ncg*cm_new[d];
4165 clear_ivec(dev);
4166 /* Do pbc and check DD cell boundary crossings */
4167 for (d = DIM-1; d >= 0; d--)
4169 if (dd->nc[d] > 1)
4171 bScrew = (dd->bScrewPBC && d == XX);
4172 /* Determine the location of this cg in lattice coordinates */
4173 pos_d = cm_new[d];
4174 if (tric_dir[d])
4176 for (d2 = d+1; d2 < DIM; d2++)
4178 pos_d += cm_new[d2]*tcm[d2][d];
4181 /* Put the charge group in the triclinic unit-cell */
4182 if (pos_d >= cell_x1[d])
4184 if (pos_d >= limit1[d])
4186 cg_move_error(fplog, dd, step, cg, d, 1,
4187 cg_cm != as_rvec_array(state->x.data()), limitd[d],
4188 cg_cm[cg], cm_new, pos_d);
4190 dev[d] = 1;
4191 if (dd->ci[d] == dd->nc[d] - 1)
4193 rvec_dec(cm_new, state->box[d]);
4194 if (bScrew)
4196 cm_new[YY] = state->box[YY][YY] - cm_new[YY];
4197 cm_new[ZZ] = state->box[ZZ][ZZ] - cm_new[ZZ];
4199 for (k = k0; (k < k1); k++)
4201 rvec_dec(state->x[k], state->box[d]);
4202 if (bScrew)
4204 rotate_state_atom(state, k);
4209 else if (pos_d < cell_x0[d])
4211 if (pos_d < limit0[d])
4213 cg_move_error(fplog, dd, step, cg, d, -1,
4214 cg_cm != as_rvec_array(state->x.data()), limitd[d],
4215 cg_cm[cg], cm_new, pos_d);
4217 dev[d] = -1;
4218 if (dd->ci[d] == 0)
4220 rvec_inc(cm_new, state->box[d]);
4221 if (bScrew)
4223 cm_new[YY] = state->box[YY][YY] - cm_new[YY];
4224 cm_new[ZZ] = state->box[ZZ][ZZ] - cm_new[ZZ];
4226 for (k = k0; (k < k1); k++)
4228 rvec_inc(state->x[k], state->box[d]);
4229 if (bScrew)
4231 rotate_state_atom(state, k);
4237 else if (d < npbcdim)
4239 /* Put the charge group in the rectangular unit-cell */
4240 while (cm_new[d] >= state->box[d][d])
4242 rvec_dec(cm_new, state->box[d]);
4243 for (k = k0; (k < k1); k++)
4245 rvec_dec(state->x[k], state->box[d]);
4248 while (cm_new[d] < 0)
4250 rvec_inc(cm_new, state->box[d]);
4251 for (k = k0; (k < k1); k++)
4253 rvec_inc(state->x[k], state->box[d]);
4259 copy_rvec(cm_new, cg_cm[cg]);
4261 /* Determine where this cg should go */
4262 flag = 0;
4263 mc = -1;
4264 for (d = 0; d < dd->ndim; d++)
4266 dim = dd->dim[d];
4267 if (dev[dim] == 1)
4269 flag |= DD_FLAG_FW(d);
4270 if (mc == -1)
4272 mc = d*2;
4275 else if (dev[dim] == -1)
4277 flag |= DD_FLAG_BW(d);
4278 if (mc == -1)
4280 if (dd->nc[dim] > 2)
4282 mc = d*2 + 1;
4284 else
4286 mc = d*2;
4291 /* Temporarily store the flag in move */
4292 move[cg] = mc + flag;
4296 static void dd_redistribute_cg(FILE *fplog, gmx_int64_t step,
4297 gmx_domdec_t *dd, ivec tric_dir,
4298 t_state *state, PaddedRVecVector *f,
4299 t_forcerec *fr,
4300 gmx_bool bCompact,
4301 t_nrnb *nrnb,
4302 int *ncg_stay_home,
4303 int *ncg_moved)
4305 int *move;
4306 int npbcdim;
4307 int ncg[DIM*2] = { 0 }, nat[DIM*2] = { 0 };
4308 int i, cg, k, d, dim, dim2, dir, d2, d3;
4309 int mc, cdd, nrcg, ncg_recv, nvs, nvr, nvec, vec;
4310 int sbuf[2], rbuf[2];
4311 int home_pos_cg, home_pos_at, buf_pos;
4312 int flag;
4313 real pos_d;
4314 matrix tcm;
4315 rvec *cg_cm = nullptr, cell_x0, cell_x1, limitd, limit0, limit1;
4316 int *cgindex;
4317 cginfo_mb_t *cginfo_mb;
4318 gmx_domdec_comm_t *comm;
4319 int *moved;
4320 int nthread, thread;
4322 if (dd->bScrewPBC)
4324 check_screw_box(state->box);
4327 comm = dd->comm;
4328 if (fr->cutoff_scheme == ecutsGROUP)
4330 cg_cm = fr->cg_cm;
4333 // Positions are always present, so there's nothing to flag
4334 bool bV = state->flags & (1<<estV);
4335 bool bCGP = state->flags & (1<<estCGP);
4337 if (dd->ncg_tot > comm->nalloc_int)
4339 comm->nalloc_int = over_alloc_dd(dd->ncg_tot);
4340 srenew(comm->buf_int, comm->nalloc_int);
4342 move = comm->buf_int;
4344 npbcdim = dd->npbcdim;
4346 for (d = 0; (d < DIM); d++)
4348 limitd[d] = dd->comm->cellsize_min[d];
4349 if (d >= npbcdim && dd->ci[d] == 0)
4351 cell_x0[d] = -GMX_FLOAT_MAX;
4353 else
4355 cell_x0[d] = comm->cell_x0[d];
4357 if (d >= npbcdim && dd->ci[d] == dd->nc[d] - 1)
4359 cell_x1[d] = GMX_FLOAT_MAX;
4361 else
4363 cell_x1[d] = comm->cell_x1[d];
4365 if (d < npbcdim)
4367 limit0[d] = comm->old_cell_x0[d] - limitd[d];
4368 limit1[d] = comm->old_cell_x1[d] + limitd[d];
4370 else
4372 /* We check after communication if a charge group moved
4373 * more than one cell. Set the pre-comm check limit to float_max.
4375 limit0[d] = -GMX_FLOAT_MAX;
4376 limit1[d] = GMX_FLOAT_MAX;
4380 make_tric_corr_matrix(npbcdim, state->box, tcm);
4382 cgindex = dd->cgindex;
4384 nthread = gmx_omp_nthreads_get(emntDomdec);
4386 /* Compute the center of geometry for all home charge groups
4387 * and put them in the box and determine where they should go.
4389 #pragma omp parallel for num_threads(nthread) schedule(static)
4390 for (thread = 0; thread < nthread; thread++)
4394 calc_cg_move(fplog, step, dd, state, tric_dir, tcm,
4395 cell_x0, cell_x1, limitd, limit0, limit1,
4396 cgindex,
4397 ( thread *dd->ncg_home)/nthread,
4398 ((thread+1)*dd->ncg_home)/nthread,
4399 fr->cutoff_scheme == ecutsGROUP ? cg_cm : as_rvec_array(state->x.data()),
4400 move);
4402 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
4405 for (cg = 0; cg < dd->ncg_home; cg++)
4407 if (move[cg] >= 0)
4409 mc = move[cg];
4410 flag = mc & ~DD_FLAG_NRCG;
4411 mc = mc & DD_FLAG_NRCG;
4412 move[cg] = mc;
4414 if (ncg[mc]+1 > comm->cggl_flag_nalloc[mc])
4416 comm->cggl_flag_nalloc[mc] = over_alloc_dd(ncg[mc]+1);
4417 srenew(comm->cggl_flag[mc], comm->cggl_flag_nalloc[mc]*DD_CGIBS);
4419 comm->cggl_flag[mc][ncg[mc]*DD_CGIBS ] = dd->index_gl[cg];
4420 /* We store the cg size in the lower 16 bits
4421 * and the place where the charge group should go
4422 * in the next 6 bits. This saves some communication volume.
4424 nrcg = cgindex[cg+1] - cgindex[cg];
4425 comm->cggl_flag[mc][ncg[mc]*DD_CGIBS+1] = nrcg | flag;
4426 ncg[mc] += 1;
4427 nat[mc] += nrcg;
4431 inc_nrnb(nrnb, eNR_CGCM, dd->nat_home);
4432 inc_nrnb(nrnb, eNR_RESETX, dd->ncg_home);
4434 *ncg_moved = 0;
4435 for (i = 0; i < dd->ndim*2; i++)
4437 *ncg_moved += ncg[i];
4440 nvec = 1;
4441 if (bV)
4443 nvec++;
4445 if (bCGP)
4447 nvec++;
4450 /* Make sure the communication buffers are large enough */
4451 for (mc = 0; mc < dd->ndim*2; mc++)
4453 nvr = ncg[mc] + nat[mc]*nvec;
4454 if (nvr > comm->cgcm_state_nalloc[mc])
4456 comm->cgcm_state_nalloc[mc] = over_alloc_dd(nvr);
4457 srenew(comm->cgcm_state[mc], comm->cgcm_state_nalloc[mc]);
4461 switch (fr->cutoff_scheme)
4463 case ecutsGROUP:
4464 /* Recalculating cg_cm might be cheaper than communicating,
4465 * but that could give rise to rounding issues.
4467 home_pos_cg =
4468 compact_and_copy_vec_cg(dd->ncg_home, move, cgindex,
4469 nvec, cg_cm, comm, bCompact);
4470 break;
4471 case ecutsVERLET:
4472 /* Without charge groups we send the moved atom coordinates
4473 * over twice. This is so the code below can be used without
4474 * many conditionals for both for with and without charge groups.
4476 home_pos_cg =
4477 compact_and_copy_vec_cg(dd->ncg_home, move, cgindex,
4478 nvec, as_rvec_array(state->x.data()), comm, FALSE);
4479 if (bCompact)
4481 home_pos_cg -= *ncg_moved;
4483 break;
4484 default:
4485 gmx_incons("unimplemented");
4486 home_pos_cg = 0;
4489 vec = 0;
4490 home_pos_at =
4491 compact_and_copy_vec_at(dd->ncg_home, move, cgindex,
4492 nvec, vec++, as_rvec_array(state->x.data()),
4493 comm, bCompact);
4494 if (bV)
4496 compact_and_copy_vec_at(dd->ncg_home, move, cgindex,
4497 nvec, vec++, as_rvec_array(state->v.data()),
4498 comm, bCompact);
4500 if (bCGP)
4502 compact_and_copy_vec_at(dd->ncg_home, move, cgindex,
4503 nvec, vec++, as_rvec_array(state->cg_p.data()),
4504 comm, bCompact);
4507 if (bCompact)
4509 compact_ind(dd->ncg_home, move,
4510 dd->index_gl, dd->cgindex, dd->gatindex,
4511 dd->ga2la, comm->bLocalCG,
4512 fr->cginfo);
4514 else
4516 if (fr->cutoff_scheme == ecutsVERLET)
4518 moved = get_moved(comm, dd->ncg_home);
4520 for (k = 0; k < dd->ncg_home; k++)
4522 moved[k] = 0;
4525 else
4527 moved = fr->ns->grid->cell_index;
4530 clear_and_mark_ind(dd->ncg_home, move,
4531 dd->index_gl, dd->cgindex, dd->gatindex,
4532 dd->ga2la, comm->bLocalCG,
4533 moved);
4536 cginfo_mb = fr->cginfo_mb;
4538 *ncg_stay_home = home_pos_cg;
4539 for (d = 0; d < dd->ndim; d++)
4541 dim = dd->dim[d];
4542 ncg_recv = 0;
4543 nvr = 0;
4544 for (dir = 0; dir < (dd->nc[dim] == 2 ? 1 : 2); dir++)
4546 cdd = d*2 + dir;
4547 /* Communicate the cg and atom counts */
4548 sbuf[0] = ncg[cdd];
4549 sbuf[1] = nat[cdd];
4550 if (debug)
4552 fprintf(debug, "Sending ddim %d dir %d: ncg %d nat %d\n",
4553 d, dir, sbuf[0], sbuf[1]);
4555 dd_sendrecv_int(dd, d, dir, sbuf, 2, rbuf, 2);
4557 if ((ncg_recv+rbuf[0])*DD_CGIBS > comm->nalloc_int)
4559 comm->nalloc_int = over_alloc_dd((ncg_recv+rbuf[0])*DD_CGIBS);
4560 srenew(comm->buf_int, comm->nalloc_int);
4563 /* Communicate the charge group indices, sizes and flags */
4564 dd_sendrecv_int(dd, d, dir,
4565 comm->cggl_flag[cdd], sbuf[0]*DD_CGIBS,
4566 comm->buf_int+ncg_recv*DD_CGIBS, rbuf[0]*DD_CGIBS);
4568 nvs = ncg[cdd] + nat[cdd]*nvec;
4569 i = rbuf[0] + rbuf[1] *nvec;
4570 vec_rvec_check_alloc(&comm->vbuf, nvr+i);
4572 /* Communicate cgcm and state */
4573 dd_sendrecv_rvec(dd, d, dir,
4574 comm->cgcm_state[cdd], nvs,
4575 comm->vbuf.v+nvr, i);
4576 ncg_recv += rbuf[0];
4577 nvr += i;
4580 dd_check_alloc_ncg(fr, state, f, home_pos_cg + ncg_recv);
4581 if (fr->cutoff_scheme == ecutsGROUP)
4583 /* Here we resize to more than necessary and shrink later */
4584 dd_resize_state(state, f, home_pos_at + ncg_recv*MAX_CGCGSIZE);
4587 /* Process the received charge groups */
4588 buf_pos = 0;
4589 for (cg = 0; cg < ncg_recv; cg++)
4591 flag = comm->buf_int[cg*DD_CGIBS+1];
4593 if (dim >= npbcdim && dd->nc[dim] > 2)
4595 /* No pbc in this dim and more than one domain boundary.
4596 * We do a separate check if a charge group didn't move too far.
4598 if (((flag & DD_FLAG_FW(d)) &&
4599 comm->vbuf.v[buf_pos][dim] > cell_x1[dim]) ||
4600 ((flag & DD_FLAG_BW(d)) &&
4601 comm->vbuf.v[buf_pos][dim] < cell_x0[dim]))
4603 cg_move_error(fplog, dd, step, cg, dim,
4604 (flag & DD_FLAG_FW(d)) ? 1 : 0,
4605 fr->cutoff_scheme == ecutsGROUP, 0,
4606 comm->vbuf.v[buf_pos],
4607 comm->vbuf.v[buf_pos],
4608 comm->vbuf.v[buf_pos][dim]);
4612 mc = -1;
4613 if (d < dd->ndim-1)
4615 /* Check which direction this cg should go */
4616 for (d2 = d+1; (d2 < dd->ndim && mc == -1); d2++)
4618 if (isDlbOn(dd->comm))
4620 /* The cell boundaries for dimension d2 are not equal
4621 * for each cell row of the lower dimension(s),
4622 * therefore we might need to redetermine where
4623 * this cg should go.
4625 dim2 = dd->dim[d2];
4626 /* If this cg crosses the box boundary in dimension d2
4627 * we can use the communicated flag, so we do not
4628 * have to worry about pbc.
4630 if (!((dd->ci[dim2] == dd->nc[dim2]-1 &&
4631 (flag & DD_FLAG_FW(d2))) ||
4632 (dd->ci[dim2] == 0 &&
4633 (flag & DD_FLAG_BW(d2)))))
4635 /* Clear the two flags for this dimension */
4636 flag &= ~(DD_FLAG_FW(d2) | DD_FLAG_BW(d2));
4637 /* Determine the location of this cg
4638 * in lattice coordinates
4640 pos_d = comm->vbuf.v[buf_pos][dim2];
4641 if (tric_dir[dim2])
4643 for (d3 = dim2+1; d3 < DIM; d3++)
4645 pos_d +=
4646 comm->vbuf.v[buf_pos][d3]*tcm[d3][dim2];
4649 /* Check of we are not at the box edge.
4650 * pbc is only handled in the first step above,
4651 * but this check could move over pbc while
4652 * the first step did not due to different rounding.
4654 if (pos_d >= cell_x1[dim2] &&
4655 dd->ci[dim2] != dd->nc[dim2]-1)
4657 flag |= DD_FLAG_FW(d2);
4659 else if (pos_d < cell_x0[dim2] &&
4660 dd->ci[dim2] != 0)
4662 flag |= DD_FLAG_BW(d2);
4664 comm->buf_int[cg*DD_CGIBS+1] = flag;
4667 /* Set to which neighboring cell this cg should go */
4668 if (flag & DD_FLAG_FW(d2))
4670 mc = d2*2;
4672 else if (flag & DD_FLAG_BW(d2))
4674 if (dd->nc[dd->dim[d2]] > 2)
4676 mc = d2*2+1;
4678 else
4680 mc = d2*2;
4686 nrcg = flag & DD_FLAG_NRCG;
4687 if (mc == -1)
4689 if (home_pos_cg+1 > dd->cg_nalloc)
4691 dd->cg_nalloc = over_alloc_dd(home_pos_cg+1);
4692 srenew(dd->index_gl, dd->cg_nalloc);
4693 srenew(dd->cgindex, dd->cg_nalloc+1);
4695 /* Set the global charge group index and size */
4696 dd->index_gl[home_pos_cg] = comm->buf_int[cg*DD_CGIBS];
4697 dd->cgindex[home_pos_cg+1] = dd->cgindex[home_pos_cg] + nrcg;
4698 /* Copy the state from the buffer */
4699 if (fr->cutoff_scheme == ecutsGROUP)
4701 cg_cm = fr->cg_cm;
4702 copy_rvec(comm->vbuf.v[buf_pos], cg_cm[home_pos_cg]);
4704 buf_pos++;
4706 /* Set the cginfo */
4707 fr->cginfo[home_pos_cg] = ddcginfo(cginfo_mb,
4708 dd->index_gl[home_pos_cg]);
4709 if (comm->bLocalCG)
4711 comm->bLocalCG[dd->index_gl[home_pos_cg]] = TRUE;
4714 for (i = 0; i < nrcg; i++)
4716 copy_rvec(comm->vbuf.v[buf_pos++],
4717 state->x[home_pos_at+i]);
4719 if (bV)
4721 for (i = 0; i < nrcg; i++)
4723 copy_rvec(comm->vbuf.v[buf_pos++],
4724 state->v[home_pos_at+i]);
4727 if (bCGP)
4729 for (i = 0; i < nrcg; i++)
4731 copy_rvec(comm->vbuf.v[buf_pos++],
4732 state->cg_p[home_pos_at+i]);
4735 home_pos_cg += 1;
4736 home_pos_at += nrcg;
4738 else
4740 /* Reallocate the buffers if necessary */
4741 if (ncg[mc]+1 > comm->cggl_flag_nalloc[mc])
4743 comm->cggl_flag_nalloc[mc] = over_alloc_dd(ncg[mc]+1);
4744 srenew(comm->cggl_flag[mc], comm->cggl_flag_nalloc[mc]*DD_CGIBS);
4746 nvr = ncg[mc] + nat[mc]*nvec;
4747 if (nvr + 1 + nrcg*nvec > comm->cgcm_state_nalloc[mc])
4749 comm->cgcm_state_nalloc[mc] = over_alloc_dd(nvr + 1 + nrcg*nvec);
4750 srenew(comm->cgcm_state[mc], comm->cgcm_state_nalloc[mc]);
4752 /* Copy from the receive to the send buffers */
4753 memcpy(comm->cggl_flag[mc] + ncg[mc]*DD_CGIBS,
4754 comm->buf_int + cg*DD_CGIBS,
4755 DD_CGIBS*sizeof(int));
4756 memcpy(comm->cgcm_state[mc][nvr],
4757 comm->vbuf.v[buf_pos],
4758 (1+nrcg*nvec)*sizeof(rvec));
4759 buf_pos += 1 + nrcg*nvec;
4760 ncg[mc] += 1;
4761 nat[mc] += nrcg;
4766 /* With sorting (!bCompact) the indices are now only partially up to date
4767 * and ncg_home and nat_home are not the real count, since there are
4768 * "holes" in the arrays for the charge groups that moved to neighbors.
4770 if (fr->cutoff_scheme == ecutsVERLET)
4772 moved = get_moved(comm, home_pos_cg);
4774 for (i = dd->ncg_home; i < home_pos_cg; i++)
4776 moved[i] = 0;
4779 dd->ncg_home = home_pos_cg;
4780 dd->nat_home = home_pos_at;
4782 if (fr->cutoff_scheme == ecutsGROUP && !bCompact)
4784 /* We overallocated before, we need to set the right size here */
4785 dd_resize_state(state, f, dd->nat_home);
4788 if (debug)
4790 fprintf(debug,
4791 "Finished repartitioning: cgs moved out %d, new home %d\n",
4792 *ncg_moved, dd->ncg_home-*ncg_moved);
4797 void dd_cycles_add(const gmx_domdec_t *dd, float cycles, int ddCycl)
4799 /* Note that the cycles value can be incorrect, either 0 or some
4800 * extremely large value, when our thread migrated to another core
4801 * with an unsynchronized cycle counter. If this happens less often
4802 * that once per nstlist steps, this will not cause issues, since
4803 * we later subtract the maximum value from the sum over nstlist steps.
4804 * A zero count will slightly lower the total, but that's a small effect.
4805 * Note that the main purpose of the subtraction of the maximum value
4806 * is to avoid throwing off the load balancing when stalls occur due
4807 * e.g. system activity or network congestion.
4809 dd->comm->cycl[ddCycl] += cycles;
4810 dd->comm->cycl_n[ddCycl]++;
4811 if (cycles > dd->comm->cycl_max[ddCycl])
4813 dd->comm->cycl_max[ddCycl] = cycles;
4817 static double force_flop_count(t_nrnb *nrnb)
4819 int i;
4820 double sum;
4821 const char *name;
4823 sum = 0;
4824 for (i = 0; i < eNR_NBKERNEL_FREE_ENERGY; i++)
4826 /* To get closer to the real timings, we half the count
4827 * for the normal loops and again half it for water loops.
4829 name = nrnb_str(i);
4830 if (strstr(name, "W3") != nullptr || strstr(name, "W4") != nullptr)
4832 sum += nrnb->n[i]*0.25*cost_nrnb(i);
4834 else
4836 sum += nrnb->n[i]*0.50*cost_nrnb(i);
4839 for (i = eNR_NBKERNEL_FREE_ENERGY; i <= eNR_NB14; i++)
4841 name = nrnb_str(i);
4842 if (strstr(name, "W3") != nullptr || strstr(name, "W4") != nullptr)
4844 sum += nrnb->n[i]*cost_nrnb(i);
4847 for (i = eNR_BONDS; i <= eNR_WALLS; i++)
4849 sum += nrnb->n[i]*cost_nrnb(i);
4852 return sum;
4855 void dd_force_flop_start(gmx_domdec_t *dd, t_nrnb *nrnb)
4857 if (dd->comm->eFlop)
4859 dd->comm->flop -= force_flop_count(nrnb);
4862 void dd_force_flop_stop(gmx_domdec_t *dd, t_nrnb *nrnb)
4864 if (dd->comm->eFlop)
4866 dd->comm->flop += force_flop_count(nrnb);
4867 dd->comm->flop_n++;
4871 static void clear_dd_cycle_counts(gmx_domdec_t *dd)
4873 int i;
4875 for (i = 0; i < ddCyclNr; i++)
4877 dd->comm->cycl[i] = 0;
4878 dd->comm->cycl_n[i] = 0;
4879 dd->comm->cycl_max[i] = 0;
4881 dd->comm->flop = 0;
4882 dd->comm->flop_n = 0;
4885 static void get_load_distribution(gmx_domdec_t *dd, gmx_wallcycle_t wcycle)
4887 gmx_domdec_comm_t *comm;
4888 domdec_load_t *load;
4889 domdec_root_t *root = nullptr;
4890 int d, dim, i, pos;
4891 float cell_frac = 0, sbuf[DD_NLOAD_MAX];
4892 gmx_bool bSepPME;
4894 if (debug)
4896 fprintf(debug, "get_load_distribution start\n");
4899 wallcycle_start(wcycle, ewcDDCOMMLOAD);
4901 comm = dd->comm;
4903 bSepPME = (dd->pme_nodeid >= 0);
4905 if (dd->ndim == 0 && bSepPME)
4907 /* Without decomposition, but with PME nodes, we need the load */
4908 comm->load[0].mdf = comm->cycl[ddCyclPPduringPME];
4909 comm->load[0].pme = comm->cycl[ddCyclPME];
4912 for (d = dd->ndim-1; d >= 0; d--)
4914 dim = dd->dim[d];
4915 /* Check if we participate in the communication in this dimension */
4916 if (d == dd->ndim-1 ||
4917 (dd->ci[dd->dim[d+1]] == 0 && dd->ci[dd->dim[dd->ndim-1]] == 0))
4919 load = &comm->load[d];
4920 if (isDlbOn(dd->comm))
4922 cell_frac = comm->cell_f1[d] - comm->cell_f0[d];
4924 pos = 0;
4925 if (d == dd->ndim-1)
4927 sbuf[pos++] = dd_force_load(comm);
4928 sbuf[pos++] = sbuf[0];
4929 if (isDlbOn(dd->comm))
4931 sbuf[pos++] = sbuf[0];
4932 sbuf[pos++] = cell_frac;
4933 if (d > 0)
4935 sbuf[pos++] = comm->cell_f_max0[d];
4936 sbuf[pos++] = comm->cell_f_min1[d];
4939 if (bSepPME)
4941 sbuf[pos++] = comm->cycl[ddCyclPPduringPME];
4942 sbuf[pos++] = comm->cycl[ddCyclPME];
4945 else
4947 sbuf[pos++] = comm->load[d+1].sum;
4948 sbuf[pos++] = comm->load[d+1].max;
4949 if (isDlbOn(dd->comm))
4951 sbuf[pos++] = comm->load[d+1].sum_m;
4952 sbuf[pos++] = comm->load[d+1].cvol_min*cell_frac;
4953 sbuf[pos++] = comm->load[d+1].flags;
4954 if (d > 0)
4956 sbuf[pos++] = comm->cell_f_max0[d];
4957 sbuf[pos++] = comm->cell_f_min1[d];
4960 if (bSepPME)
4962 sbuf[pos++] = comm->load[d+1].mdf;
4963 sbuf[pos++] = comm->load[d+1].pme;
4966 load->nload = pos;
4967 /* Communicate a row in DD direction d.
4968 * The communicators are setup such that the root always has rank 0.
4970 #if GMX_MPI
4971 MPI_Gather(sbuf, load->nload*sizeof(float), MPI_BYTE,
4972 load->load, load->nload*sizeof(float), MPI_BYTE,
4973 0, comm->mpi_comm_load[d]);
4974 #endif
4975 if (dd->ci[dim] == dd->master_ci[dim])
4977 /* We are the root, process this row */
4978 if (isDlbOn(comm))
4980 root = comm->root[d];
4982 load->sum = 0;
4983 load->max = 0;
4984 load->sum_m = 0;
4985 load->cvol_min = 1;
4986 load->flags = 0;
4987 load->mdf = 0;
4988 load->pme = 0;
4989 pos = 0;
4990 for (i = 0; i < dd->nc[dim]; i++)
4992 load->sum += load->load[pos++];
4993 load->max = std::max(load->max, load->load[pos]);
4994 pos++;
4995 if (isDlbOn(dd->comm))
4997 if (root->bLimited)
4999 /* This direction could not be load balanced properly,
5000 * therefore we need to use the maximum iso the average load.
5002 load->sum_m = std::max(load->sum_m, load->load[pos]);
5004 else
5006 load->sum_m += load->load[pos];
5008 pos++;
5009 load->cvol_min = std::min(load->cvol_min, load->load[pos]);
5010 pos++;
5011 if (d < dd->ndim-1)
5013 load->flags = (int)(load->load[pos++] + 0.5);
5015 if (d > 0)
5017 root->cell_f_max0[i] = load->load[pos++];
5018 root->cell_f_min1[i] = load->load[pos++];
5021 if (bSepPME)
5023 load->mdf = std::max(load->mdf, load->load[pos]);
5024 pos++;
5025 load->pme = std::max(load->pme, load->load[pos]);
5026 pos++;
5029 if (isDlbOn(comm) && root->bLimited)
5031 load->sum_m *= dd->nc[dim];
5032 load->flags |= (1<<d);
5038 if (DDMASTER(dd))
5040 comm->nload += dd_load_count(comm);
5041 comm->load_step += comm->cycl[ddCyclStep];
5042 comm->load_sum += comm->load[0].sum;
5043 comm->load_max += comm->load[0].max;
5044 if (isDlbOn(comm))
5046 for (d = 0; d < dd->ndim; d++)
5048 if (comm->load[0].flags & (1<<d))
5050 comm->load_lim[d]++;
5054 if (bSepPME)
5056 comm->load_mdf += comm->load[0].mdf;
5057 comm->load_pme += comm->load[0].pme;
5061 wallcycle_stop(wcycle, ewcDDCOMMLOAD);
5063 if (debug)
5065 fprintf(debug, "get_load_distribution finished\n");
5069 static float dd_force_load_fraction(gmx_domdec_t *dd)
5071 /* Return the relative performance loss on the total run time
5072 * due to the force calculation load imbalance.
5074 if (dd->comm->nload > 0 && dd->comm->load_step > 0)
5076 return dd->comm->load_sum/(dd->comm->load_step*dd->nnodes);
5078 else
5080 return 0;
5084 static float dd_force_imb_perf_loss(gmx_domdec_t *dd)
5086 /* Return the relative performance loss on the total run time
5087 * due to the force calculation load imbalance.
5089 if (dd->comm->nload > 0 && dd->comm->load_step > 0)
5091 return
5092 (dd->comm->load_max*dd->nnodes - dd->comm->load_sum)/
5093 (dd->comm->load_step*dd->nnodes);
5095 else
5097 return 0;
5101 static void print_dd_load_av(FILE *fplog, gmx_domdec_t *dd)
5103 gmx_domdec_comm_t *comm = dd->comm;
5105 /* Only the master rank prints loads and only if we measured loads */
5106 if (!DDMASTER(dd) || comm->nload == 0)
5108 return;
5111 char buf[STRLEN];
5112 int numPpRanks = dd->nnodes;
5113 int numPmeRanks = (dd->pme_nodeid >= 0) ? comm->npmenodes : 0;
5114 int numRanks = numPpRanks + numPmeRanks;
5115 float lossFraction = 0;
5117 /* Print the average load imbalance and performance loss */
5118 if (dd->nnodes > 1 && comm->load_sum > 0)
5120 float imbalance = comm->load_max*numPpRanks/comm->load_sum - 1;
5121 lossFraction = dd_force_imb_perf_loss(dd);
5123 std::string msg = "\n Dynamic load balancing report:\n";
5124 std::string dlbStateStr = "";
5126 switch (dd->comm->dlbState)
5128 case edlbsOffUser:
5129 dlbStateStr = "DLB was off during the run per user request.";
5130 break;
5131 case edlbsOffForever:
5132 /* Currectly this can happen due to performance loss observed, cell size
5133 * limitations or incompatibility with other settings observed during
5134 * determineInitialDlbState(). */
5135 dlbStateStr = "DLB got disabled because it was unsuitable to use.";
5136 break;
5137 case edlbsOffCanTurnOn:
5138 dlbStateStr = "DLB was off during the run due to low measured imbalance.";
5139 break;
5140 case edlbsOffTemporarilyLocked:
5141 dlbStateStr = "DLB was locked at the end of the run due to unfinished PP-PME balancing.";
5142 break;
5143 case edlbsOnCanTurnOff:
5144 dlbStateStr = "DLB was turned on during the run due to measured imbalance.";
5145 break;
5146 case edlbsOnUser:
5147 dlbStateStr = "DLB was permanently on during the run per user request.";
5148 break;
5149 default:
5150 GMX_ASSERT(false, "Undocumented DLB state");
5153 msg += " " + dlbStateStr + "\n";
5154 msg += gmx::formatString(" Average load imbalance: %.1f%%.\n", imbalance*100);
5155 msg += gmx::formatString(" The balanceable part of the MD step is %d%%, load imbalance is computed from this.\n",
5156 static_cast<int>(dd_force_load_fraction(dd)*100 + 0.5));
5157 msg += gmx::formatString(" Part of the total run time spent waiting due to load imbalance: %.1f%%.\n",
5158 lossFraction*100);
5159 fprintf(fplog, "%s", msg.c_str());
5160 fprintf(stderr, "%s", msg.c_str());
5163 /* Print during what percentage of steps the load balancing was limited */
5164 bool dlbWasLimited = false;
5165 if (isDlbOn(comm))
5167 sprintf(buf, " Steps where the load balancing was limited by -rdd, -rcon and/or -dds:");
5168 for (int d = 0; d < dd->ndim; d++)
5170 int limitPercentage = (200*comm->load_lim[d] + 1)/(2*comm->nload);
5171 sprintf(buf+strlen(buf), " %c %d %%",
5172 dim2char(dd->dim[d]), limitPercentage);
5173 if (limitPercentage >= 50)
5175 dlbWasLimited = true;
5178 sprintf(buf + strlen(buf), "\n");
5179 fprintf(fplog, "%s", buf);
5180 fprintf(stderr, "%s", buf);
5183 /* Print the performance loss due to separate PME - PP rank imbalance */
5184 float lossFractionPme = 0;
5185 if (numPmeRanks > 0 && comm->load_mdf > 0 && comm->load_step > 0)
5187 float pmeForceRatio = comm->load_pme/comm->load_mdf;
5188 lossFractionPme = (comm->load_pme - comm->load_mdf)/comm->load_step;
5189 if (lossFractionPme <= 0)
5191 lossFractionPme *= numPmeRanks/static_cast<float>(numRanks);
5193 else
5195 lossFractionPme *= numPpRanks/static_cast<float>(numRanks);
5197 sprintf(buf, " Average PME mesh/force load: %5.3f\n", pmeForceRatio);
5198 fprintf(fplog, "%s", buf);
5199 fprintf(stderr, "%s", buf);
5200 sprintf(buf, " Part of the total run time spent waiting due to PP/PME imbalance: %.1f %%\n", fabs(lossFractionPme)*100);
5201 fprintf(fplog, "%s", buf);
5202 fprintf(stderr, "%s", buf);
5204 fprintf(fplog, "\n");
5205 fprintf(stderr, "\n");
5207 if (lossFraction >= DD_PERF_LOSS_WARN)
5209 sprintf(buf,
5210 "NOTE: %.1f %% of the available CPU time was lost due to load imbalance\n"
5211 " in the domain decomposition.\n", lossFraction*100);
5212 if (!isDlbOn(comm))
5214 sprintf(buf+strlen(buf), " You might want to use dynamic load balancing (option -dlb.)\n");
5216 else if (dlbWasLimited)
5218 sprintf(buf+strlen(buf), " You might want to decrease the cell size limit (options -rdd, -rcon and/or -dds).\n");
5220 fprintf(fplog, "%s\n", buf);
5221 fprintf(stderr, "%s\n", buf);
5223 if (numPmeRanks > 0 && fabs(lossFractionPme) >= DD_PERF_LOSS_WARN)
5225 sprintf(buf,
5226 "NOTE: %.1f %% performance was lost because the PME ranks\n"
5227 " had %s work to do than the PP ranks.\n"
5228 " You might want to %s the number of PME ranks\n"
5229 " or %s the cut-off and the grid spacing.\n",
5230 fabs(lossFractionPme*100),
5231 (lossFractionPme < 0) ? "less" : "more",
5232 (lossFractionPme < 0) ? "decrease" : "increase",
5233 (lossFractionPme < 0) ? "decrease" : "increase");
5234 fprintf(fplog, "%s\n", buf);
5235 fprintf(stderr, "%s\n", buf);
5239 static float dd_vol_min(gmx_domdec_t *dd)
5241 return dd->comm->load[0].cvol_min*dd->nnodes;
5244 static gmx_bool dd_load_flags(gmx_domdec_t *dd)
5246 return dd->comm->load[0].flags;
5249 static float dd_f_imbal(gmx_domdec_t *dd)
5251 if (dd->comm->load[0].sum > 0)
5253 return dd->comm->load[0].max*dd->nnodes/dd->comm->load[0].sum - 1.0f;
5255 else
5257 /* Something is wrong in the cycle counting, report no load imbalance */
5258 return 0.0f;
5262 float dd_pme_f_ratio(gmx_domdec_t *dd)
5264 /* Should only be called on the DD master rank */
5265 assert(DDMASTER(dd));
5267 if (dd->comm->load[0].mdf > 0 && dd->comm->cycl_n[ddCyclPME] > 0)
5269 return dd->comm->load[0].pme/dd->comm->load[0].mdf;
5271 else
5273 return -1.0;
5277 static void dd_print_load(FILE *fplog, gmx_domdec_t *dd, gmx_int64_t step)
5279 int flags, d;
5280 char buf[22];
5282 flags = dd_load_flags(dd);
5283 if (flags)
5285 fprintf(fplog,
5286 "DD load balancing is limited by minimum cell size in dimension");
5287 for (d = 0; d < dd->ndim; d++)
5289 if (flags & (1<<d))
5291 fprintf(fplog, " %c", dim2char(dd->dim[d]));
5294 fprintf(fplog, "\n");
5296 fprintf(fplog, "DD step %s", gmx_step_str(step, buf));
5297 if (isDlbOn(dd->comm))
5299 fprintf(fplog, " vol min/aver %5.3f%c",
5300 dd_vol_min(dd), flags ? '!' : ' ');
5302 if (dd->nnodes > 1)
5304 fprintf(fplog, " load imb.: force %4.1f%%", dd_f_imbal(dd)*100);
5306 if (dd->comm->cycl_n[ddCyclPME])
5308 fprintf(fplog, " pme mesh/force %5.3f", dd_pme_f_ratio(dd));
5310 fprintf(fplog, "\n\n");
5313 static void dd_print_load_verbose(gmx_domdec_t *dd)
5315 if (isDlbOn(dd->comm))
5317 fprintf(stderr, "vol %4.2f%c ",
5318 dd_vol_min(dd), dd_load_flags(dd) ? '!' : ' ');
5320 if (dd->nnodes > 1)
5322 fprintf(stderr, "imb F %2d%% ", (int)(dd_f_imbal(dd)*100+0.5));
5324 if (dd->comm->cycl_n[ddCyclPME])
5326 fprintf(stderr, "pme/F %4.2f ", dd_pme_f_ratio(dd));
5330 #if GMX_MPI
5331 static void make_load_communicator(gmx_domdec_t *dd, int dim_ind, ivec loc)
5333 MPI_Comm c_row;
5334 int dim, i, rank;
5335 ivec loc_c;
5336 domdec_root_t *root;
5337 gmx_bool bPartOfGroup = FALSE;
5339 dim = dd->dim[dim_ind];
5340 copy_ivec(loc, loc_c);
5341 for (i = 0; i < dd->nc[dim]; i++)
5343 loc_c[dim] = i;
5344 rank = dd_index(dd->nc, loc_c);
5345 if (rank == dd->rank)
5347 /* This process is part of the group */
5348 bPartOfGroup = TRUE;
5351 MPI_Comm_split(dd->mpi_comm_all, bPartOfGroup ? 0 : MPI_UNDEFINED, dd->rank,
5352 &c_row);
5353 if (bPartOfGroup)
5355 dd->comm->mpi_comm_load[dim_ind] = c_row;
5356 if (!isDlbDisabled(dd->comm))
5358 if (dd->ci[dim] == dd->master_ci[dim])
5360 /* This is the root process of this row */
5361 snew(dd->comm->root[dim_ind], 1);
5362 root = dd->comm->root[dim_ind];
5363 snew(root->cell_f, DD_CELL_F_SIZE(dd, dim_ind));
5364 snew(root->old_cell_f, dd->nc[dim]+1);
5365 snew(root->bCellMin, dd->nc[dim]);
5366 if (dim_ind > 0)
5368 snew(root->cell_f_max0, dd->nc[dim]);
5369 snew(root->cell_f_min1, dd->nc[dim]);
5370 snew(root->bound_min, dd->nc[dim]);
5371 snew(root->bound_max, dd->nc[dim]);
5373 snew(root->buf_ncd, dd->nc[dim]);
5375 else
5377 /* This is not a root process, we only need to receive cell_f */
5378 snew(dd->comm->cell_f_row, DD_CELL_F_SIZE(dd, dim_ind));
5381 if (dd->ci[dim] == dd->master_ci[dim])
5383 snew(dd->comm->load[dim_ind].load, dd->nc[dim]*DD_NLOAD_MAX);
5387 #endif
5389 void dd_setup_dlb_resource_sharing(t_commrec *cr,
5390 int gpu_id)
5392 #if GMX_MPI
5393 int physicalnode_id_hash;
5394 gmx_domdec_t *dd;
5395 MPI_Comm mpi_comm_pp_physicalnode;
5397 if (!thisRankHasDuty(cr, DUTY_PP) || gpu_id < 0)
5399 /* Only ranks with short-ranged tasks (currently) use GPUs.
5400 * If we don't have GPUs assigned, there are no resources to share.
5402 return;
5405 physicalnode_id_hash = gmx_physicalnode_id_hash();
5407 dd = cr->dd;
5409 if (debug)
5411 fprintf(debug, "dd_setup_dd_dlb_gpu_sharing:\n");
5412 fprintf(debug, "DD PP rank %d physical node hash %d gpu_id %d\n",
5413 dd->rank, physicalnode_id_hash, gpu_id);
5415 /* Split the PP communicator over the physical nodes */
5416 /* TODO: See if we should store this (before), as it's also used for
5417 * for the nodecomm summation.
5419 // TODO PhysicalNodeCommunicator could be extended/used to handle
5420 // the need for per-node per-group communicators.
5421 MPI_Comm_split(dd->mpi_comm_all, physicalnode_id_hash, dd->rank,
5422 &mpi_comm_pp_physicalnode);
5423 MPI_Comm_split(mpi_comm_pp_physicalnode, gpu_id, dd->rank,
5424 &dd->comm->mpi_comm_gpu_shared);
5425 MPI_Comm_free(&mpi_comm_pp_physicalnode);
5426 MPI_Comm_size(dd->comm->mpi_comm_gpu_shared, &dd->comm->nrank_gpu_shared);
5428 if (debug)
5430 fprintf(debug, "nrank_gpu_shared %d\n", dd->comm->nrank_gpu_shared);
5433 /* Note that some ranks could share a GPU, while others don't */
5435 if (dd->comm->nrank_gpu_shared == 1)
5437 MPI_Comm_free(&dd->comm->mpi_comm_gpu_shared);
5439 #else
5440 GMX_UNUSED_VALUE(cr);
5441 GMX_UNUSED_VALUE(gpu_id);
5442 #endif
5445 static void make_load_communicators(gmx_domdec_t gmx_unused *dd)
5447 #if GMX_MPI
5448 int dim0, dim1, i, j;
5449 ivec loc;
5451 if (debug)
5453 fprintf(debug, "Making load communicators\n");
5456 snew(dd->comm->load, std::max(dd->ndim, 1));
5457 snew(dd->comm->mpi_comm_load, std::max(dd->ndim, 1));
5459 if (dd->ndim == 0)
5461 return;
5464 clear_ivec(loc);
5465 make_load_communicator(dd, 0, loc);
5466 if (dd->ndim > 1)
5468 dim0 = dd->dim[0];
5469 for (i = 0; i < dd->nc[dim0]; i++)
5471 loc[dim0] = i;
5472 make_load_communicator(dd, 1, loc);
5475 if (dd->ndim > 2)
5477 dim0 = dd->dim[0];
5478 for (i = 0; i < dd->nc[dim0]; i++)
5480 loc[dim0] = i;
5481 dim1 = dd->dim[1];
5482 for (j = 0; j < dd->nc[dim1]; j++)
5484 loc[dim1] = j;
5485 make_load_communicator(dd, 2, loc);
5490 if (debug)
5492 fprintf(debug, "Finished making load communicators\n");
5494 #endif
5497 /*! \brief Sets up the relation between neighboring domains and zones */
5498 static void setup_neighbor_relations(gmx_domdec_t *dd)
5500 int d, dim, i, j, m;
5501 ivec tmp, s;
5502 gmx_domdec_zones_t *zones;
5503 gmx_domdec_ns_ranges_t *izone;
5505 for (d = 0; d < dd->ndim; d++)
5507 dim = dd->dim[d];
5508 copy_ivec(dd->ci, tmp);
5509 tmp[dim] = (tmp[dim] + 1) % dd->nc[dim];
5510 dd->neighbor[d][0] = ddcoord2ddnodeid(dd, tmp);
5511 copy_ivec(dd->ci, tmp);
5512 tmp[dim] = (tmp[dim] - 1 + dd->nc[dim]) % dd->nc[dim];
5513 dd->neighbor[d][1] = ddcoord2ddnodeid(dd, tmp);
5514 if (debug)
5516 fprintf(debug, "DD rank %d neighbor ranks in dir %d are + %d - %d\n",
5517 dd->rank, dim,
5518 dd->neighbor[d][0],
5519 dd->neighbor[d][1]);
5523 int nzone = (1 << dd->ndim);
5524 int nizone = (1 << std::max(dd->ndim - 1, 0));
5525 assert(nizone >= 1 && nizone <= DD_MAXIZONE);
5527 zones = &dd->comm->zones;
5529 for (i = 0; i < nzone; i++)
5531 m = 0;
5532 clear_ivec(zones->shift[i]);
5533 for (d = 0; d < dd->ndim; d++)
5535 zones->shift[i][dd->dim[d]] = dd_zo[i][m++];
5539 zones->n = nzone;
5540 for (i = 0; i < nzone; i++)
5542 for (d = 0; d < DIM; d++)
5544 s[d] = dd->ci[d] - zones->shift[i][d];
5545 if (s[d] < 0)
5547 s[d] += dd->nc[d];
5549 else if (s[d] >= dd->nc[d])
5551 s[d] -= dd->nc[d];
5555 zones->nizone = nizone;
5556 for (i = 0; i < zones->nizone; i++)
5558 assert(ddNonbondedZonePairRanges[i][0] == i);
5560 izone = &zones->izone[i];
5561 /* dd_zp3 is for 3D decomposition, for fewer dimensions use only
5562 * j-zones up to nzone.
5564 izone->j0 = std::min(ddNonbondedZonePairRanges[i][1], nzone);
5565 izone->j1 = std::min(ddNonbondedZonePairRanges[i][2], nzone);
5566 for (dim = 0; dim < DIM; dim++)
5568 if (dd->nc[dim] == 1)
5570 /* All shifts should be allowed */
5571 izone->shift0[dim] = -1;
5572 izone->shift1[dim] = 1;
5574 else
5576 /* Determine the min/max j-zone shift wrt the i-zone */
5577 izone->shift0[dim] = 1;
5578 izone->shift1[dim] = -1;
5579 for (j = izone->j0; j < izone->j1; j++)
5581 int shift_diff = zones->shift[j][dim] - zones->shift[i][dim];
5582 if (shift_diff < izone->shift0[dim])
5584 izone->shift0[dim] = shift_diff;
5586 if (shift_diff > izone->shift1[dim])
5588 izone->shift1[dim] = shift_diff;
5595 if (!isDlbDisabled(dd->comm))
5597 snew(dd->comm->root, dd->ndim);
5600 if (dd->comm->bRecordLoad)
5602 make_load_communicators(dd);
5606 static void make_pp_communicator(FILE *fplog,
5607 gmx_domdec_t *dd,
5608 t_commrec gmx_unused *cr,
5609 int gmx_unused reorder)
5611 #if GMX_MPI
5612 gmx_domdec_comm_t *comm;
5613 int rank, *buf;
5614 ivec periods;
5615 MPI_Comm comm_cart;
5617 comm = dd->comm;
5619 if (comm->bCartesianPP)
5621 /* Set up cartesian communication for the particle-particle part */
5622 if (fplog)
5624 fprintf(fplog, "Will use a Cartesian communicator: %d x %d x %d\n",
5625 dd->nc[XX], dd->nc[YY], dd->nc[ZZ]);
5628 for (int i = 0; i < DIM; i++)
5630 periods[i] = TRUE;
5632 MPI_Cart_create(cr->mpi_comm_mygroup, DIM, dd->nc, periods, reorder,
5633 &comm_cart);
5634 /* We overwrite the old communicator with the new cartesian one */
5635 cr->mpi_comm_mygroup = comm_cart;
5638 dd->mpi_comm_all = cr->mpi_comm_mygroup;
5639 MPI_Comm_rank(dd->mpi_comm_all, &dd->rank);
5641 if (comm->bCartesianPP_PME)
5643 /* Since we want to use the original cartesian setup for sim,
5644 * and not the one after split, we need to make an index.
5646 snew(comm->ddindex2ddnodeid, dd->nnodes);
5647 comm->ddindex2ddnodeid[dd_index(dd->nc, dd->ci)] = dd->rank;
5648 gmx_sumi(dd->nnodes, comm->ddindex2ddnodeid, cr);
5649 /* Get the rank of the DD master,
5650 * above we made sure that the master node is a PP node.
5652 if (MASTER(cr))
5654 rank = dd->rank;
5656 else
5658 rank = 0;
5660 MPI_Allreduce(&rank, &dd->masterrank, 1, MPI_INT, MPI_SUM, dd->mpi_comm_all);
5662 else if (comm->bCartesianPP)
5664 if (cr->npmenodes == 0)
5666 /* The PP communicator is also
5667 * the communicator for this simulation
5669 cr->mpi_comm_mysim = cr->mpi_comm_mygroup;
5671 cr->nodeid = dd->rank;
5673 MPI_Cart_coords(dd->mpi_comm_all, dd->rank, DIM, dd->ci);
5675 /* We need to make an index to go from the coordinates
5676 * to the nodeid of this simulation.
5678 snew(comm->ddindex2simnodeid, dd->nnodes);
5679 snew(buf, dd->nnodes);
5680 if (thisRankHasDuty(cr, DUTY_PP))
5682 buf[dd_index(dd->nc, dd->ci)] = cr->sim_nodeid;
5684 /* Communicate the ddindex to simulation nodeid index */
5685 MPI_Allreduce(buf, comm->ddindex2simnodeid, dd->nnodes, MPI_INT, MPI_SUM,
5686 cr->mpi_comm_mysim);
5687 sfree(buf);
5689 /* Determine the master coordinates and rank.
5690 * The DD master should be the same node as the master of this sim.
5692 for (int i = 0; i < dd->nnodes; i++)
5694 if (comm->ddindex2simnodeid[i] == 0)
5696 ddindex2xyz(dd->nc, i, dd->master_ci);
5697 MPI_Cart_rank(dd->mpi_comm_all, dd->master_ci, &dd->masterrank);
5700 if (debug)
5702 fprintf(debug, "The master rank is %d\n", dd->masterrank);
5705 else
5707 /* No Cartesian communicators */
5708 /* We use the rank in dd->comm->all as DD index */
5709 ddindex2xyz(dd->nc, dd->rank, dd->ci);
5710 /* The simulation master nodeid is 0, so the DD master rank is also 0 */
5711 dd->masterrank = 0;
5712 clear_ivec(dd->master_ci);
5714 #endif
5716 if (fplog)
5718 fprintf(fplog,
5719 "Domain decomposition rank %d, coordinates %d %d %d\n\n",
5720 dd->rank, dd->ci[XX], dd->ci[YY], dd->ci[ZZ]);
5722 if (debug)
5724 fprintf(debug,
5725 "Domain decomposition rank %d, coordinates %d %d %d\n\n",
5726 dd->rank, dd->ci[XX], dd->ci[YY], dd->ci[ZZ]);
5730 static void receive_ddindex2simnodeid(gmx_domdec_t *dd,
5731 t_commrec *cr)
5733 #if GMX_MPI
5734 gmx_domdec_comm_t *comm = dd->comm;
5736 if (!comm->bCartesianPP_PME && comm->bCartesianPP)
5738 int *buf;
5739 snew(comm->ddindex2simnodeid, dd->nnodes);
5740 snew(buf, dd->nnodes);
5741 if (thisRankHasDuty(cr, DUTY_PP))
5743 buf[dd_index(dd->nc, dd->ci)] = cr->sim_nodeid;
5745 /* Communicate the ddindex to simulation nodeid index */
5746 MPI_Allreduce(buf, comm->ddindex2simnodeid, dd->nnodes, MPI_INT, MPI_SUM,
5747 cr->mpi_comm_mysim);
5748 sfree(buf);
5750 #else
5751 GMX_UNUSED_VALUE(dd);
5752 GMX_UNUSED_VALUE(cr);
5753 #endif
5756 static gmx_domdec_master_t *init_gmx_domdec_master_t(gmx_domdec_t *dd,
5757 int ncg, int natoms)
5759 gmx_domdec_master_t *ma;
5760 int i;
5762 snew(ma, 1);
5764 snew(ma->ncg, dd->nnodes);
5765 snew(ma->index, dd->nnodes+1);
5766 snew(ma->cg, ncg);
5767 snew(ma->nat, dd->nnodes);
5768 snew(ma->ibuf, dd->nnodes*2);
5769 snew(ma->cell_x, DIM);
5770 for (i = 0; i < DIM; i++)
5772 snew(ma->cell_x[i], dd->nc[i]+1);
5775 if (dd->nnodes <= GMX_DD_NNODES_SENDRECV)
5777 ma->vbuf = nullptr;
5779 else
5781 snew(ma->vbuf, natoms);
5784 return ma;
5787 static void split_communicator(FILE *fplog, t_commrec *cr, gmx_domdec_t *dd,
5788 DdRankOrder gmx_unused rankOrder,
5789 int gmx_unused reorder)
5791 gmx_domdec_comm_t *comm;
5792 int i;
5793 gmx_bool bDiv[DIM];
5794 #if GMX_MPI
5795 MPI_Comm comm_cart;
5796 #endif
5798 comm = dd->comm;
5800 if (comm->bCartesianPP)
5802 for (i = 1; i < DIM; i++)
5804 bDiv[i] = ((cr->npmenodes*dd->nc[i]) % (dd->nnodes) == 0);
5806 if (bDiv[YY] || bDiv[ZZ])
5808 comm->bCartesianPP_PME = TRUE;
5809 /* If we have 2D PME decomposition, which is always in x+y,
5810 * we stack the PME only nodes in z.
5811 * Otherwise we choose the direction that provides the thinnest slab
5812 * of PME only nodes as this will have the least effect
5813 * on the PP communication.
5814 * But for the PME communication the opposite might be better.
5816 if (bDiv[ZZ] && (comm->npmenodes_y > 1 ||
5817 !bDiv[YY] ||
5818 dd->nc[YY] > dd->nc[ZZ]))
5820 comm->cartpmedim = ZZ;
5822 else
5824 comm->cartpmedim = YY;
5826 comm->ntot[comm->cartpmedim]
5827 += (cr->npmenodes*dd->nc[comm->cartpmedim])/dd->nnodes;
5829 else if (fplog)
5831 fprintf(fplog, "Number of PME-only ranks (%d) is not a multiple of nx*ny (%d*%d) or nx*nz (%d*%d)\n", cr->npmenodes, dd->nc[XX], dd->nc[YY], dd->nc[XX], dd->nc[ZZ]);
5832 fprintf(fplog,
5833 "Will not use a Cartesian communicator for PP <-> PME\n\n");
5837 if (comm->bCartesianPP_PME)
5839 #if GMX_MPI
5840 int rank;
5841 ivec periods;
5843 if (fplog)
5845 fprintf(fplog, "Will use a Cartesian communicator for PP <-> PME: %d x %d x %d\n", comm->ntot[XX], comm->ntot[YY], comm->ntot[ZZ]);
5848 for (i = 0; i < DIM; i++)
5850 periods[i] = TRUE;
5852 MPI_Cart_create(cr->mpi_comm_mysim, DIM, comm->ntot, periods, reorder,
5853 &comm_cart);
5854 MPI_Comm_rank(comm_cart, &rank);
5855 if (MASTER(cr) && rank != 0)
5857 gmx_fatal(FARGS, "MPI rank 0 was renumbered by MPI_Cart_create, we do not allow this");
5860 /* With this assigment we loose the link to the original communicator
5861 * which will usually be MPI_COMM_WORLD, unless have multisim.
5863 cr->mpi_comm_mysim = comm_cart;
5864 cr->sim_nodeid = rank;
5866 MPI_Cart_coords(cr->mpi_comm_mysim, cr->sim_nodeid, DIM, dd->ci);
5868 if (fplog)
5870 fprintf(fplog, "Cartesian rank %d, coordinates %d %d %d\n\n",
5871 cr->sim_nodeid, dd->ci[XX], dd->ci[YY], dd->ci[ZZ]);
5874 if (dd->ci[comm->cartpmedim] < dd->nc[comm->cartpmedim])
5876 cr->duty = DUTY_PP;
5878 if (cr->npmenodes == 0 ||
5879 dd->ci[comm->cartpmedim] >= dd->nc[comm->cartpmedim])
5881 cr->duty = DUTY_PME;
5884 /* Split the sim communicator into PP and PME only nodes */
5885 MPI_Comm_split(cr->mpi_comm_mysim,
5886 getThisRankDuties(cr),
5887 dd_index(comm->ntot, dd->ci),
5888 &cr->mpi_comm_mygroup);
5889 #endif
5891 else
5893 switch (rankOrder)
5895 case DdRankOrder::pp_pme:
5896 if (fplog)
5898 fprintf(fplog, "Order of the ranks: PP first, PME last\n");
5900 break;
5901 case DdRankOrder::interleave:
5902 /* Interleave the PP-only and PME-only ranks */
5903 if (fplog)
5905 fprintf(fplog, "Interleaving PP and PME ranks\n");
5907 comm->pmenodes = dd_interleaved_pme_ranks(dd);
5908 break;
5909 case DdRankOrder::cartesian:
5910 break;
5911 default:
5912 gmx_fatal(FARGS, "Invalid ddRankOrder=%d", static_cast<int>(rankOrder));
5915 if (dd_simnode2pmenode(dd, cr, cr->sim_nodeid) == -1)
5917 cr->duty = DUTY_PME;
5919 else
5921 cr->duty = DUTY_PP;
5923 #if GMX_MPI
5924 /* Split the sim communicator into PP and PME only nodes */
5925 MPI_Comm_split(cr->mpi_comm_mysim,
5926 getThisRankDuties(cr),
5927 cr->nodeid,
5928 &cr->mpi_comm_mygroup);
5929 MPI_Comm_rank(cr->mpi_comm_mygroup, &cr->nodeid);
5930 #endif
5933 if (fplog)
5935 fprintf(fplog, "This rank does only %s work.\n\n",
5936 thisRankHasDuty(cr, DUTY_PP) ? "particle-particle" : "PME-mesh");
5940 /*! \brief Generates the MPI communicators for domain decomposition */
5941 static void make_dd_communicators(FILE *fplog, t_commrec *cr,
5942 gmx_domdec_t *dd, DdRankOrder ddRankOrder)
5944 gmx_domdec_comm_t *comm;
5945 int CartReorder;
5947 comm = dd->comm;
5949 copy_ivec(dd->nc, comm->ntot);
5951 comm->bCartesianPP = (ddRankOrder == DdRankOrder::cartesian);
5952 comm->bCartesianPP_PME = FALSE;
5954 /* Reorder the nodes by default. This might change the MPI ranks.
5955 * Real reordering is only supported on very few architectures,
5956 * Blue Gene is one of them.
5958 CartReorder = (getenv("GMX_NO_CART_REORDER") == nullptr);
5960 if (cr->npmenodes > 0)
5962 /* Split the communicator into a PP and PME part */
5963 split_communicator(fplog, cr, dd, ddRankOrder, CartReorder);
5964 if (comm->bCartesianPP_PME)
5966 /* We (possibly) reordered the nodes in split_communicator,
5967 * so it is no longer required in make_pp_communicator.
5969 CartReorder = FALSE;
5972 else
5974 /* All nodes do PP and PME */
5975 #if GMX_MPI
5976 /* We do not require separate communicators */
5977 cr->mpi_comm_mygroup = cr->mpi_comm_mysim;
5978 #endif
5981 if (thisRankHasDuty(cr, DUTY_PP))
5983 /* Copy or make a new PP communicator */
5984 make_pp_communicator(fplog, dd, cr, CartReorder);
5986 else
5988 receive_ddindex2simnodeid(dd, cr);
5991 if (!thisRankHasDuty(cr, DUTY_PME))
5993 /* Set up the commnuication to our PME node */
5994 dd->pme_nodeid = dd_simnode2pmenode(dd, cr, cr->sim_nodeid);
5995 dd->pme_receive_vir_ener = receive_vir_ener(dd, cr);
5996 if (debug)
5998 fprintf(debug, "My pme_nodeid %d receive ener %d\n",
5999 dd->pme_nodeid, dd->pme_receive_vir_ener);
6002 else
6004 dd->pme_nodeid = -1;
6007 if (DDMASTER(dd))
6009 dd->ma = init_gmx_domdec_master_t(dd,
6010 comm->cgs_gl.nr,
6011 comm->cgs_gl.index[comm->cgs_gl.nr]);
6015 static real *get_slb_frac(FILE *fplog, const char *dir, int nc, const char *size_string)
6017 real *slb_frac, tot;
6018 int i, n;
6019 double dbl;
6021 slb_frac = nullptr;
6022 if (nc > 1 && size_string != nullptr)
6024 if (fplog)
6026 fprintf(fplog, "Using static load balancing for the %s direction\n",
6027 dir);
6029 snew(slb_frac, nc);
6030 tot = 0;
6031 for (i = 0; i < nc; i++)
6033 dbl = 0;
6034 sscanf(size_string, "%20lf%n", &dbl, &n);
6035 if (dbl == 0)
6037 gmx_fatal(FARGS, "Incorrect or not enough DD cell size entries for direction %s: '%s'", dir, size_string);
6039 slb_frac[i] = dbl;
6040 size_string += n;
6041 tot += slb_frac[i];
6043 /* Normalize */
6044 if (fplog)
6046 fprintf(fplog, "Relative cell sizes:");
6048 for (i = 0; i < nc; i++)
6050 slb_frac[i] /= tot;
6051 if (fplog)
6053 fprintf(fplog, " %5.3f", slb_frac[i]);
6056 if (fplog)
6058 fprintf(fplog, "\n");
6062 return slb_frac;
6065 static int multi_body_bondeds_count(const gmx_mtop_t *mtop)
6067 int n, nmol, ftype;
6068 gmx_mtop_ilistloop_t iloop;
6069 const t_ilist *il;
6071 n = 0;
6072 iloop = gmx_mtop_ilistloop_init(mtop);
6073 while (gmx_mtop_ilistloop_next(iloop, &il, &nmol))
6075 for (ftype = 0; ftype < F_NRE; ftype++)
6077 if ((interaction_function[ftype].flags & IF_BOND) &&
6078 NRAL(ftype) > 2)
6080 n += nmol*il[ftype].nr/(1 + NRAL(ftype));
6085 return n;
6088 static int dd_getenv(FILE *fplog, const char *env_var, int def)
6090 char *val;
6091 int nst;
6093 nst = def;
6094 val = getenv(env_var);
6095 if (val)
6097 if (sscanf(val, "%20d", &nst) <= 0)
6099 nst = 1;
6101 if (fplog)
6103 fprintf(fplog, "Found env.var. %s = %s, using value %d\n",
6104 env_var, val, nst);
6108 return nst;
6111 static void dd_warning(const t_commrec *cr, FILE *fplog, const char *warn_string)
6113 if (MASTER(cr))
6115 fprintf(stderr, "\n%s\n", warn_string);
6117 if (fplog)
6119 fprintf(fplog, "\n%s\n", warn_string);
6123 static void check_dd_restrictions(t_commrec *cr, const gmx_domdec_t *dd,
6124 const t_inputrec *ir, FILE *fplog)
6126 if (ir->ePBC == epbcSCREW &&
6127 (dd->nc[XX] == 1 || dd->nc[YY] > 1 || dd->nc[ZZ] > 1))
6129 gmx_fatal(FARGS, "With pbc=%s can only do domain decomposition in the x-direction", epbc_names[ir->ePBC]);
6132 if (ir->ns_type == ensSIMPLE)
6134 gmx_fatal(FARGS, "Domain decomposition does not support simple neighbor searching, use grid searching or run with one MPI rank");
6137 if (ir->nstlist == 0)
6139 gmx_fatal(FARGS, "Domain decomposition does not work with nstlist=0");
6142 if (ir->comm_mode == ecmANGULAR && ir->ePBC != epbcNONE)
6144 dd_warning(cr, fplog, "comm-mode angular will give incorrect results when the comm group partially crosses a periodic boundary");
6148 static real average_cellsize_min(gmx_domdec_t *dd, gmx_ddbox_t *ddbox)
6150 int di, d;
6151 real r;
6153 r = ddbox->box_size[XX];
6154 for (di = 0; di < dd->ndim; di++)
6156 d = dd->dim[di];
6157 /* Check using the initial average cell size */
6158 r = std::min(r, ddbox->box_size[d]*ddbox->skew_fac[d]/dd->nc[d]);
6161 return r;
6164 /*! \brief Depending on the DLB initial value return the DLB switched off state or issue an error.
6166 static int forceDlbOffOrBail(int cmdlineDlbState,
6167 const std::string &reasonStr,
6168 t_commrec *cr,
6169 FILE *fplog)
6171 std::string dlbNotSupportedErr = "Dynamic load balancing requested, but ";
6172 std::string dlbDisableNote = "NOTE: disabling dynamic load balancing as ";
6174 if (cmdlineDlbState == edlbsOnUser)
6176 gmx_fatal(FARGS, (dlbNotSupportedErr + reasonStr).c_str());
6178 else if (cmdlineDlbState == edlbsOffCanTurnOn)
6180 dd_warning(cr, fplog, (dlbDisableNote + reasonStr + "\n").c_str());
6182 return edlbsOffForever;
6185 /*! \brief Return the dynamic load balancer's initial state based on initial conditions and user inputs.
6187 * This function parses the parameters of "-dlb" command line option setting
6188 * corresponding state values. Then it checks the consistency of the determined
6189 * state with other run parameters and settings. As a result, the initial state
6190 * may be altered or an error may be thrown if incompatibility of options is detected.
6192 * \param [in] fplog Pointer to mdrun log file.
6193 * \param [in] cr Pointer to MPI communication object.
6194 * \param [in] dlbOption Enum value for the DLB option.
6195 * \param [in] bRecordLoad True if the load balancer is recording load information.
6196 * \param [in] mdrunOptions Options for mdrun.
6197 * \param [in] ir Pointer mdrun to input parameters.
6198 * \returns DLB initial/startup state.
6200 static int determineInitialDlbState(FILE *fplog, t_commrec *cr,
6201 DlbOption dlbOption, gmx_bool bRecordLoad,
6202 const MdrunOptions &mdrunOptions,
6203 const t_inputrec *ir)
6205 int dlbState = edlbsOffCanTurnOn;
6207 switch (dlbOption)
6209 case DlbOption::turnOnWhenUseful: dlbState = edlbsOffCanTurnOn; break;
6210 case DlbOption::no: dlbState = edlbsOffUser; break;
6211 case DlbOption::yes: dlbState = edlbsOnUser; break;
6212 default: gmx_incons("Invalid dlbOption enum value");
6215 /* Reruns don't support DLB: bail or override auto mode */
6216 if (mdrunOptions.rerun)
6218 std::string reasonStr = "it is not supported in reruns.";
6219 return forceDlbOffOrBail(dlbState, reasonStr, cr, fplog);
6222 /* Unsupported integrators */
6223 if (!EI_DYNAMICS(ir->eI))
6225 auto reasonStr = gmx::formatString("it is only supported with dynamics, not with integrator '%s'.", EI(ir->eI));
6226 return forceDlbOffOrBail(dlbState, reasonStr, cr, fplog);
6229 /* Without cycle counters we can't time work to balance on */
6230 if (!bRecordLoad)
6232 std::string reasonStr = "cycle counters unsupported or not enabled in the operating system kernel.";
6233 return forceDlbOffOrBail(dlbState, reasonStr, cr, fplog);
6236 if (mdrunOptions.reproducible)
6238 std::string reasonStr = "you started a reproducible run.";
6239 switch (dlbState)
6241 case edlbsOffUser:
6242 break;
6243 case edlbsOffForever:
6244 GMX_RELEASE_ASSERT(false, "edlbsOffForever is not a valid initial state");
6245 break;
6246 case edlbsOffCanTurnOn:
6247 return forceDlbOffOrBail(dlbState, reasonStr, cr, fplog);
6248 break;
6249 case edlbsOnCanTurnOff:
6250 GMX_RELEASE_ASSERT(false, "edlbsOffCanTurnOff is not a valid initial state");
6251 break;
6252 case edlbsOnUser:
6253 return forceDlbOffOrBail(dlbState, reasonStr + " In load balanced runs binary reproducibility cannot be ensured.", cr, fplog);
6254 break;
6255 default:
6256 gmx_fatal(FARGS, "Death horror: undefined case (%d) for load balancing choice", dlbState);
6257 break;
6261 return dlbState;
6264 static void set_dd_dim(FILE *fplog, gmx_domdec_t *dd)
6266 int dim;
6268 dd->ndim = 0;
6269 if (getenv("GMX_DD_ORDER_ZYX") != nullptr)
6271 /* Decomposition order z,y,x */
6272 if (fplog)
6274 fprintf(fplog, "Using domain decomposition order z, y, x\n");
6276 for (dim = DIM-1; dim >= 0; dim--)
6278 if (dd->nc[dim] > 1)
6280 dd->dim[dd->ndim++] = dim;
6284 else
6286 /* Decomposition order x,y,z */
6287 for (dim = 0; dim < DIM; dim++)
6289 if (dd->nc[dim] > 1)
6291 dd->dim[dd->ndim++] = dim;
6297 static gmx_domdec_comm_t *init_dd_comm()
6299 gmx_domdec_comm_t *comm;
6300 int i;
6302 snew(comm, 1);
6303 snew(comm->cggl_flag, DIM*2);
6304 snew(comm->cgcm_state, DIM*2);
6305 for (i = 0; i < DIM*2; i++)
6307 comm->cggl_flag_nalloc[i] = 0;
6308 comm->cgcm_state_nalloc[i] = 0;
6311 comm->nalloc_int = 0;
6312 comm->buf_int = nullptr;
6314 vec_rvec_init(&comm->vbuf);
6316 comm->n_load_have = 0;
6317 comm->n_load_collect = 0;
6319 for (i = 0; i < ddnatNR-ddnatZONE; i++)
6321 comm->sum_nat[i] = 0;
6323 comm->ndecomp = 0;
6324 comm->nload = 0;
6325 comm->load_step = 0;
6326 comm->load_sum = 0;
6327 comm->load_max = 0;
6328 clear_ivec(comm->load_lim);
6329 comm->load_mdf = 0;
6330 comm->load_pme = 0;
6332 /* This should be replaced by a unique pointer */
6333 comm->balanceRegion = ddBalanceRegionAllocate();
6335 return comm;
6338 /*! \brief Set the cell size and interaction limits, as well as the DD grid */
6339 static void set_dd_limits_and_grid(FILE *fplog, t_commrec *cr, gmx_domdec_t *dd,
6340 const DomdecOptions &options,
6341 const MdrunOptions &mdrunOptions,
6342 const gmx_mtop_t *mtop,
6343 const t_inputrec *ir,
6344 const matrix box, const rvec *xGlobal,
6345 gmx_ddbox_t *ddbox)
6347 real r_bonded = -1;
6348 real r_bonded_limit = -1;
6349 const real tenPercentMargin = 1.1;
6350 gmx_domdec_comm_t *comm = dd->comm;
6352 snew(comm->cggl_flag, DIM*2);
6353 snew(comm->cgcm_state, DIM*2);
6355 dd->npbcdim = ePBC2npbcdim(ir->ePBC);
6356 dd->bScrewPBC = (ir->ePBC == epbcSCREW);
6358 dd->pme_recv_f_alloc = 0;
6359 dd->pme_recv_f_buf = nullptr;
6361 /* Initialize to GPU share count to 0, might change later */
6362 comm->nrank_gpu_shared = 0;
6364 comm->dlbState = determineInitialDlbState(fplog, cr, options.dlbOption, comm->bRecordLoad, mdrunOptions, ir);
6365 dd_dlb_set_should_check_whether_to_turn_dlb_on(dd, TRUE);
6366 /* To consider turning DLB on after 2*nstlist steps we need to check
6367 * at partitioning count 3. Thus we need to increase the first count by 2.
6369 comm->ddPartioningCountFirstDlbOff += 2;
6371 if (fplog)
6373 fprintf(fplog, "Dynamic load balancing: %s\n",
6374 edlbs_names[comm->dlbState]);
6376 comm->bPMELoadBalDLBLimits = FALSE;
6378 /* Allocate the charge group/atom sorting struct */
6379 snew(comm->sort, 1);
6381 comm->bCGs = (ncg_mtop(mtop) < mtop->natoms);
6383 comm->bInterCGBondeds = ((ncg_mtop(mtop) > gmx_mtop_num_molecules(*mtop)) ||
6384 mtop->bIntermolecularInteractions);
6385 if (comm->bInterCGBondeds)
6387 comm->bInterCGMultiBody = (multi_body_bondeds_count(mtop) > 0);
6389 else
6391 comm->bInterCGMultiBody = FALSE;
6394 dd->bInterCGcons = inter_charge_group_constraints(mtop);
6395 dd->bInterCGsettles = inter_charge_group_settles(mtop);
6397 if (ir->rlist == 0)
6399 /* Set the cut-off to some very large value,
6400 * so we don't need if statements everywhere in the code.
6401 * We use sqrt, since the cut-off is squared in some places.
6403 comm->cutoff = GMX_CUTOFF_INF;
6405 else
6407 comm->cutoff = ir->rlist;
6409 comm->cutoff_mbody = 0;
6411 comm->cellsize_limit = 0;
6412 comm->bBondComm = FALSE;
6414 /* Atoms should be able to move by up to half the list buffer size (if > 0)
6415 * within nstlist steps. Since boundaries are allowed to displace by half
6416 * a cell size, DD cells should be at least the size of the list buffer.
6418 comm->cellsize_limit = std::max(comm->cellsize_limit,
6419 ir->rlist - std::max(ir->rvdw, ir->rcoulomb));
6421 if (comm->bInterCGBondeds)
6423 if (options.minimumCommunicationRange > 0)
6425 comm->cutoff_mbody = options.minimumCommunicationRange;
6426 if (options.useBondedCommunication)
6428 comm->bBondComm = (comm->cutoff_mbody > comm->cutoff);
6430 else
6432 comm->cutoff = std::max(comm->cutoff, comm->cutoff_mbody);
6434 r_bonded_limit = comm->cutoff_mbody;
6436 else if (ir->bPeriodicMols)
6438 /* Can not easily determine the required cut-off */
6439 dd_warning(cr, fplog, "NOTE: Periodic molecules are present in this system. Because of this, the domain decomposition algorithm cannot easily determine the minimum cell size that it requires for treating bonded interactions. Instead, domain decomposition will assume that half the non-bonded cut-off will be a suitable lower bound.\n");
6440 comm->cutoff_mbody = comm->cutoff/2;
6441 r_bonded_limit = comm->cutoff_mbody;
6443 else
6445 real r_2b, r_mb;
6447 if (MASTER(cr))
6449 dd_bonded_cg_distance(fplog, mtop, ir, xGlobal, box,
6450 options.checkBondedInteractions,
6451 &r_2b, &r_mb);
6453 gmx_bcast(sizeof(r_2b), &r_2b, cr);
6454 gmx_bcast(sizeof(r_mb), &r_mb, cr);
6456 /* We use an initial margin of 10% for the minimum cell size,
6457 * except when we are just below the non-bonded cut-off.
6459 if (options.useBondedCommunication)
6461 if (std::max(r_2b, r_mb) > comm->cutoff)
6463 r_bonded = std::max(r_2b, r_mb);
6464 r_bonded_limit = tenPercentMargin*r_bonded;
6465 comm->bBondComm = TRUE;
6467 else
6469 r_bonded = r_mb;
6470 r_bonded_limit = std::min(tenPercentMargin*r_bonded, comm->cutoff);
6472 /* We determine cutoff_mbody later */
6474 else
6476 /* No special bonded communication,
6477 * simply increase the DD cut-off.
6479 r_bonded_limit = tenPercentMargin*std::max(r_2b, r_mb);
6480 comm->cutoff_mbody = r_bonded_limit;
6481 comm->cutoff = std::max(comm->cutoff, comm->cutoff_mbody);
6484 if (fplog)
6486 fprintf(fplog,
6487 "Minimum cell size due to bonded interactions: %.3f nm\n",
6488 r_bonded_limit);
6490 comm->cellsize_limit = std::max(comm->cellsize_limit, r_bonded_limit);
6493 real rconstr = 0;
6494 if (dd->bInterCGcons && options.constraintCommunicationRange <= 0)
6496 /* There is a cell size limit due to the constraints (P-LINCS) */
6497 rconstr = constr_r_max(fplog, mtop, ir);
6498 if (fplog)
6500 fprintf(fplog,
6501 "Estimated maximum distance required for P-LINCS: %.3f nm\n",
6502 rconstr);
6503 if (rconstr > comm->cellsize_limit)
6505 fprintf(fplog, "This distance will limit the DD cell size, you can override this with -rcon\n");
6509 else if (options.constraintCommunicationRange > 0 && fplog)
6511 /* Here we do not check for dd->bInterCGcons,
6512 * because one can also set a cell size limit for virtual sites only
6513 * and at this point we don't know yet if there are intercg v-sites.
6515 fprintf(fplog,
6516 "User supplied maximum distance required for P-LINCS: %.3f nm\n",
6517 options.constraintCommunicationRange);
6518 rconstr = options.constraintCommunicationRange;
6520 comm->cellsize_limit = std::max(comm->cellsize_limit, rconstr);
6522 comm->cgs_gl = gmx_mtop_global_cgs(mtop);
6524 if (options.numCells[XX] > 0)
6526 copy_ivec(options.numCells, dd->nc);
6527 set_dd_dim(fplog, dd);
6528 set_ddbox_cr(cr, &dd->nc, ir, box, &comm->cgs_gl, xGlobal, ddbox);
6530 if (options.numPmeRanks >= 0)
6532 cr->npmenodes = options.numPmeRanks;
6534 else
6536 /* When the DD grid is set explicitly and -npme is set to auto,
6537 * don't use PME ranks. We check later if the DD grid is
6538 * compatible with the total number of ranks.
6540 cr->npmenodes = 0;
6543 real acs = average_cellsize_min(dd, ddbox);
6544 if (acs < comm->cellsize_limit)
6546 if (fplog)
6548 fprintf(fplog, "ERROR: The initial cell size (%f) is smaller than the cell size limit (%f)\n", acs, comm->cellsize_limit);
6550 gmx_fatal_collective(FARGS, cr->mpi_comm_mysim, MASTER(cr),
6551 "The initial cell size (%f) is smaller than the cell size limit (%f), change options -dd, -rdd or -rcon, see the log file for details",
6552 acs, comm->cellsize_limit);
6555 else
6557 set_ddbox_cr(cr, nullptr, ir, box, &comm->cgs_gl, xGlobal, ddbox);
6559 /* We need to choose the optimal DD grid and possibly PME nodes */
6560 real limit =
6561 dd_choose_grid(fplog, cr, dd, ir, mtop, box, ddbox,
6562 options.numPmeRanks,
6563 !isDlbDisabled(comm),
6564 options.dlbScaling,
6565 comm->cellsize_limit, comm->cutoff,
6566 comm->bInterCGBondeds);
6568 if (dd->nc[XX] == 0)
6570 char buf[STRLEN];
6571 gmx_bool bC = (dd->bInterCGcons && rconstr > r_bonded_limit);
6572 sprintf(buf, "Change the number of ranks or mdrun option %s%s%s",
6573 !bC ? "-rdd" : "-rcon",
6574 comm->dlbState != edlbsOffUser ? " or -dds" : "",
6575 bC ? " or your LINCS settings" : "");
6577 gmx_fatal_collective(FARGS, cr->mpi_comm_mysim, MASTER(cr),
6578 "There is no domain decomposition for %d ranks that is compatible with the given box and a minimum cell size of %g nm\n"
6579 "%s\n"
6580 "Look in the log file for details on the domain decomposition",
6581 cr->nnodes-cr->npmenodes, limit, buf);
6583 set_dd_dim(fplog, dd);
6586 if (fplog)
6588 fprintf(fplog,
6589 "Domain decomposition grid %d x %d x %d, separate PME ranks %d\n",
6590 dd->nc[XX], dd->nc[YY], dd->nc[ZZ], cr->npmenodes);
6593 dd->nnodes = dd->nc[XX]*dd->nc[YY]*dd->nc[ZZ];
6594 if (cr->nnodes - dd->nnodes != cr->npmenodes)
6596 gmx_fatal_collective(FARGS, cr->mpi_comm_mysim, MASTER(cr),
6597 "The size of the domain decomposition grid (%d) does not match the number of ranks (%d). The total number of ranks is %d",
6598 dd->nnodes, cr->nnodes - cr->npmenodes, cr->nnodes);
6600 if (cr->npmenodes > dd->nnodes)
6602 gmx_fatal_collective(FARGS, cr->mpi_comm_mysim, MASTER(cr),
6603 "The number of separate PME ranks (%d) is larger than the number of PP ranks (%d), this is not supported.", cr->npmenodes, dd->nnodes);
6605 if (cr->npmenodes > 0)
6607 comm->npmenodes = cr->npmenodes;
6609 else
6611 comm->npmenodes = dd->nnodes;
6614 if (EEL_PME(ir->coulombtype) || EVDW_PME(ir->vdwtype))
6616 /* The following choices should match those
6617 * in comm_cost_est in domdec_setup.c.
6618 * Note that here the checks have to take into account
6619 * that the decomposition might occur in a different order than xyz
6620 * (for instance through the env.var. GMX_DD_ORDER_ZYX),
6621 * in which case they will not match those in comm_cost_est,
6622 * but since that is mainly for testing purposes that's fine.
6624 if (dd->ndim >= 2 && dd->dim[0] == XX && dd->dim[1] == YY &&
6625 comm->npmenodes > dd->nc[XX] && comm->npmenodes % dd->nc[XX] == 0 &&
6626 getenv("GMX_PMEONEDD") == nullptr)
6628 comm->npmedecompdim = 2;
6629 comm->npmenodes_x = dd->nc[XX];
6630 comm->npmenodes_y = comm->npmenodes/comm->npmenodes_x;
6632 else
6634 /* In case nc is 1 in both x and y we could still choose to
6635 * decompose pme in y instead of x, but we use x for simplicity.
6637 comm->npmedecompdim = 1;
6638 if (dd->dim[0] == YY)
6640 comm->npmenodes_x = 1;
6641 comm->npmenodes_y = comm->npmenodes;
6643 else
6645 comm->npmenodes_x = comm->npmenodes;
6646 comm->npmenodes_y = 1;
6649 if (fplog)
6651 fprintf(fplog, "PME domain decomposition: %d x %d x %d\n",
6652 comm->npmenodes_x, comm->npmenodes_y, 1);
6655 else
6657 comm->npmedecompdim = 0;
6658 comm->npmenodes_x = 0;
6659 comm->npmenodes_y = 0;
6662 snew(comm->slb_frac, DIM);
6663 if (isDlbDisabled(comm))
6665 comm->slb_frac[XX] = get_slb_frac(fplog, "x", dd->nc[XX], options.cellSizeX);
6666 comm->slb_frac[YY] = get_slb_frac(fplog, "y", dd->nc[YY], options.cellSizeY);
6667 comm->slb_frac[ZZ] = get_slb_frac(fplog, "z", dd->nc[ZZ], options.cellSizeZ);
6670 if (comm->bInterCGBondeds && comm->cutoff_mbody == 0)
6672 if (comm->bBondComm || !isDlbDisabled(comm))
6674 /* Set the bonded communication distance to halfway
6675 * the minimum and the maximum,
6676 * since the extra communication cost is nearly zero.
6678 real acs = average_cellsize_min(dd, ddbox);
6679 comm->cutoff_mbody = 0.5*(r_bonded + acs);
6680 if (!isDlbDisabled(comm))
6682 /* Check if this does not limit the scaling */
6683 comm->cutoff_mbody = std::min(comm->cutoff_mbody,
6684 options.dlbScaling*acs);
6686 if (!comm->bBondComm)
6688 /* Without bBondComm do not go beyond the n.b. cut-off */
6689 comm->cutoff_mbody = std::min(comm->cutoff_mbody, comm->cutoff);
6690 if (comm->cellsize_limit >= comm->cutoff)
6692 /* We don't loose a lot of efficieny
6693 * when increasing it to the n.b. cut-off.
6694 * It can even be slightly faster, because we need
6695 * less checks for the communication setup.
6697 comm->cutoff_mbody = comm->cutoff;
6700 /* Check if we did not end up below our original limit */
6701 comm->cutoff_mbody = std::max(comm->cutoff_mbody, r_bonded_limit);
6703 if (comm->cutoff_mbody > comm->cellsize_limit)
6705 comm->cellsize_limit = comm->cutoff_mbody;
6708 /* Without DLB and cutoff_mbody<cutoff, cutoff_mbody is dynamic */
6711 if (debug)
6713 fprintf(debug, "Bonded atom communication beyond the cut-off: %d\n"
6714 "cellsize limit %f\n",
6715 comm->bBondComm, comm->cellsize_limit);
6718 if (MASTER(cr))
6720 check_dd_restrictions(cr, dd, ir, fplog);
6724 static void set_dlb_limits(gmx_domdec_t *dd)
6727 int d;
6729 for (d = 0; d < dd->ndim; d++)
6731 dd->comm->cd[d].np = dd->comm->cd[d].np_dlb;
6732 dd->comm->cellsize_min[dd->dim[d]] =
6733 dd->comm->cellsize_min_dlb[dd->dim[d]];
6738 static void turn_on_dlb(FILE *fplog, const t_commrec *cr, gmx_int64_t step)
6740 gmx_domdec_t *dd;
6741 gmx_domdec_comm_t *comm;
6742 real cellsize_min;
6743 int d, nc, i;
6745 dd = cr->dd;
6746 comm = dd->comm;
6748 cellsize_min = comm->cellsize_min[dd->dim[0]];
6749 for (d = 1; d < dd->ndim; d++)
6751 cellsize_min = std::min(cellsize_min, comm->cellsize_min[dd->dim[d]]);
6754 /* Turn off DLB if we're too close to the cell size limit. */
6755 if (cellsize_min < comm->cellsize_limit*1.05)
6757 auto str = gmx::formatString("step %" GMX_PRId64 " Measured %.1f %% performance loss due to load imbalance, "
6758 "but the minimum cell size is smaller than 1.05 times the cell size limit."
6759 "Will no longer try dynamic load balancing.\n", step, dd_force_imb_perf_loss(dd)*100);
6760 dd_warning(cr, fplog, str.c_str());
6762 comm->dlbState = edlbsOffForever;
6763 return;
6766 char buf[STRLEN];
6767 sprintf(buf, "step %" GMX_PRId64 " Turning on dynamic load balancing, because the performance loss due to load imbalance is %.1f %%.\n", step, dd_force_imb_perf_loss(dd)*100);
6768 dd_warning(cr, fplog, buf);
6769 comm->dlbState = edlbsOnCanTurnOff;
6771 /* Store the non-DLB performance, so we can check if DLB actually
6772 * improves performance.
6774 GMX_RELEASE_ASSERT(comm->cycl_n[ddCyclStep] > 0, "When we turned on DLB, we should have measured cycles");
6775 comm->cyclesPerStepBeforeDLB = comm->cycl[ddCyclStep]/comm->cycl_n[ddCyclStep];
6777 set_dlb_limits(dd);
6779 /* We can set the required cell size info here,
6780 * so we do not need to communicate this.
6781 * The grid is completely uniform.
6783 for (d = 0; d < dd->ndim; d++)
6785 if (comm->root[d])
6787 comm->load[d].sum_m = comm->load[d].sum;
6789 nc = dd->nc[dd->dim[d]];
6790 for (i = 0; i < nc; i++)
6792 comm->root[d]->cell_f[i] = i/(real)nc;
6793 if (d > 0)
6795 comm->root[d]->cell_f_max0[i] = i /(real)nc;
6796 comm->root[d]->cell_f_min1[i] = (i+1)/(real)nc;
6799 comm->root[d]->cell_f[nc] = 1.0;
6804 static void turn_off_dlb(FILE *fplog, const t_commrec *cr, gmx_int64_t step)
6806 gmx_domdec_t *dd = cr->dd;
6808 char buf[STRLEN];
6809 sprintf(buf, "step %" GMX_PRId64 " Turning off dynamic load balancing, because it is degrading performance.\n", step);
6810 dd_warning(cr, fplog, buf);
6811 dd->comm->dlbState = edlbsOffCanTurnOn;
6812 dd->comm->haveTurnedOffDlb = true;
6813 dd->comm->ddPartioningCountFirstDlbOff = dd->ddp_count;
6816 static void turn_off_dlb_forever(FILE *fplog, const t_commrec *cr, gmx_int64_t step)
6818 GMX_RELEASE_ASSERT(cr->dd->comm->dlbState == edlbsOffCanTurnOn, "Can only turn off DLB forever when it was in the can-turn-on state");
6819 char buf[STRLEN];
6820 sprintf(buf, "step %" GMX_PRId64 " Will no longer try dynamic load balancing, as it degraded performance.\n", step);
6821 dd_warning(cr, fplog, buf);
6822 cr->dd->comm->dlbState = edlbsOffForever;
6825 static char *init_bLocalCG(const gmx_mtop_t *mtop)
6827 int ncg, cg;
6828 char *bLocalCG;
6830 ncg = ncg_mtop(mtop);
6831 snew(bLocalCG, ncg);
6832 for (cg = 0; cg < ncg; cg++)
6834 bLocalCG[cg] = FALSE;
6837 return bLocalCG;
6840 void dd_init_bondeds(FILE *fplog,
6841 gmx_domdec_t *dd,
6842 const gmx_mtop_t *mtop,
6843 const gmx_vsite_t *vsite,
6844 const t_inputrec *ir,
6845 gmx_bool bBCheck, cginfo_mb_t *cginfo_mb)
6847 gmx_domdec_comm_t *comm;
6849 dd_make_reverse_top(fplog, dd, mtop, vsite, ir, bBCheck);
6851 comm = dd->comm;
6853 if (comm->bBondComm)
6855 /* Communicate atoms beyond the cut-off for bonded interactions */
6856 comm = dd->comm;
6858 comm->cglink = make_charge_group_links(mtop, dd, cginfo_mb);
6860 comm->bLocalCG = init_bLocalCG(mtop);
6862 else
6864 /* Only communicate atoms based on cut-off */
6865 comm->cglink = nullptr;
6866 comm->bLocalCG = nullptr;
6870 static void print_dd_settings(FILE *fplog, gmx_domdec_t *dd,
6871 const gmx_mtop_t *mtop, const t_inputrec *ir,
6872 gmx_bool bDynLoadBal, real dlb_scale,
6873 const gmx_ddbox_t *ddbox)
6875 gmx_domdec_comm_t *comm;
6876 int d;
6877 ivec np;
6878 real limit, shrink;
6879 char buf[64];
6881 if (fplog == nullptr)
6883 return;
6886 comm = dd->comm;
6888 if (bDynLoadBal)
6890 fprintf(fplog, "The maximum number of communication pulses is:");
6891 for (d = 0; d < dd->ndim; d++)
6893 fprintf(fplog, " %c %d", dim2char(dd->dim[d]), comm->cd[d].np_dlb);
6895 fprintf(fplog, "\n");
6896 fprintf(fplog, "The minimum size for domain decomposition cells is %.3f nm\n", comm->cellsize_limit);
6897 fprintf(fplog, "The requested allowed shrink of DD cells (option -dds) is: %.2f\n", dlb_scale);
6898 fprintf(fplog, "The allowed shrink of domain decomposition cells is:");
6899 for (d = 0; d < DIM; d++)
6901 if (dd->nc[d] > 1)
6903 if (d >= ddbox->npbcdim && dd->nc[d] == 2)
6905 shrink = 0;
6907 else
6909 shrink =
6910 comm->cellsize_min_dlb[d]/
6911 (ddbox->box_size[d]*ddbox->skew_fac[d]/dd->nc[d]);
6913 fprintf(fplog, " %c %.2f", dim2char(d), shrink);
6916 fprintf(fplog, "\n");
6918 else
6920 set_dd_cell_sizes_slb(dd, ddbox, setcellsizeslbPULSE_ONLY, np);
6921 fprintf(fplog, "The initial number of communication pulses is:");
6922 for (d = 0; d < dd->ndim; d++)
6924 fprintf(fplog, " %c %d", dim2char(dd->dim[d]), np[dd->dim[d]]);
6926 fprintf(fplog, "\n");
6927 fprintf(fplog, "The initial domain decomposition cell size is:");
6928 for (d = 0; d < DIM; d++)
6930 if (dd->nc[d] > 1)
6932 fprintf(fplog, " %c %.2f nm",
6933 dim2char(d), dd->comm->cellsize_min[d]);
6936 fprintf(fplog, "\n\n");
6939 gmx_bool bInterCGVsites = count_intercg_vsites(mtop);
6941 if (comm->bInterCGBondeds ||
6942 bInterCGVsites ||
6943 dd->bInterCGcons || dd->bInterCGsettles)
6945 fprintf(fplog, "The maximum allowed distance for charge groups involved in interactions is:\n");
6946 fprintf(fplog, "%40s %-7s %6.3f nm\n",
6947 "non-bonded interactions", "", comm->cutoff);
6949 if (bDynLoadBal)
6951 limit = dd->comm->cellsize_limit;
6953 else
6955 if (dynamic_dd_box(ddbox, ir))
6957 fprintf(fplog, "(the following are initial values, they could change due to box deformation)\n");
6959 limit = dd->comm->cellsize_min[XX];
6960 for (d = 1; d < DIM; d++)
6962 limit = std::min(limit, dd->comm->cellsize_min[d]);
6966 if (comm->bInterCGBondeds)
6968 fprintf(fplog, "%40s %-7s %6.3f nm\n",
6969 "two-body bonded interactions", "(-rdd)",
6970 std::max(comm->cutoff, comm->cutoff_mbody));
6971 fprintf(fplog, "%40s %-7s %6.3f nm\n",
6972 "multi-body bonded interactions", "(-rdd)",
6973 (comm->bBondComm || isDlbOn(dd->comm)) ? comm->cutoff_mbody : std::min(comm->cutoff, limit));
6975 if (bInterCGVsites)
6977 fprintf(fplog, "%40s %-7s %6.3f nm\n",
6978 "virtual site constructions", "(-rcon)", limit);
6980 if (dd->bInterCGcons || dd->bInterCGsettles)
6982 sprintf(buf, "atoms separated by up to %d constraints",
6983 1+ir->nProjOrder);
6984 fprintf(fplog, "%40s %-7s %6.3f nm\n",
6985 buf, "(-rcon)", limit);
6987 fprintf(fplog, "\n");
6990 fflush(fplog);
6993 static void set_cell_limits_dlb(gmx_domdec_t *dd,
6994 real dlb_scale,
6995 const t_inputrec *ir,
6996 const gmx_ddbox_t *ddbox)
6998 gmx_domdec_comm_t *comm;
6999 int d, dim, npulse, npulse_d_max, npulse_d;
7000 gmx_bool bNoCutOff;
7002 comm = dd->comm;
7004 bNoCutOff = (ir->rvdw == 0 || ir->rcoulomb == 0);
7006 /* Determine the maximum number of comm. pulses in one dimension */
7008 comm->cellsize_limit = std::max(comm->cellsize_limit, comm->cutoff_mbody);
7010 /* Determine the maximum required number of grid pulses */
7011 if (comm->cellsize_limit >= comm->cutoff)
7013 /* Only a single pulse is required */
7014 npulse = 1;
7016 else if (!bNoCutOff && comm->cellsize_limit > 0)
7018 /* We round down slightly here to avoid overhead due to the latency
7019 * of extra communication calls when the cut-off
7020 * would be only slightly longer than the cell size.
7021 * Later cellsize_limit is redetermined,
7022 * so we can not miss interactions due to this rounding.
7024 npulse = (int)(0.96 + comm->cutoff/comm->cellsize_limit);
7026 else
7028 /* There is no cell size limit */
7029 npulse = std::max(dd->nc[XX]-1, std::max(dd->nc[YY]-1, dd->nc[ZZ]-1));
7032 if (!bNoCutOff && npulse > 1)
7034 /* See if we can do with less pulses, based on dlb_scale */
7035 npulse_d_max = 0;
7036 for (d = 0; d < dd->ndim; d++)
7038 dim = dd->dim[d];
7039 npulse_d = (int)(1 + dd->nc[dim]*comm->cutoff
7040 /(ddbox->box_size[dim]*ddbox->skew_fac[dim]*dlb_scale));
7041 npulse_d_max = std::max(npulse_d_max, npulse_d);
7043 npulse = std::min(npulse, npulse_d_max);
7046 /* This env var can override npulse */
7047 d = dd_getenv(debug, "GMX_DD_NPULSE", 0);
7048 if (d > 0)
7050 npulse = d;
7053 comm->maxpulse = 1;
7054 comm->bVacDLBNoLimit = (ir->ePBC == epbcNONE);
7055 for (d = 0; d < dd->ndim; d++)
7057 comm->cd[d].np_dlb = std::min(npulse, dd->nc[dd->dim[d]]-1);
7058 comm->cd[d].np_nalloc = comm->cd[d].np_dlb;
7059 snew(comm->cd[d].ind, comm->cd[d].np_nalloc);
7060 comm->maxpulse = std::max(comm->maxpulse, comm->cd[d].np_dlb);
7061 if (comm->cd[d].np_dlb < dd->nc[dd->dim[d]]-1)
7063 comm->bVacDLBNoLimit = FALSE;
7067 /* cellsize_limit is set for LINCS in init_domain_decomposition */
7068 if (!comm->bVacDLBNoLimit)
7070 comm->cellsize_limit = std::max(comm->cellsize_limit,
7071 comm->cutoff/comm->maxpulse);
7073 comm->cellsize_limit = std::max(comm->cellsize_limit, comm->cutoff_mbody);
7074 /* Set the minimum cell size for each DD dimension */
7075 for (d = 0; d < dd->ndim; d++)
7077 if (comm->bVacDLBNoLimit ||
7078 comm->cd[d].np_dlb*comm->cellsize_limit >= comm->cutoff)
7080 comm->cellsize_min_dlb[dd->dim[d]] = comm->cellsize_limit;
7082 else
7084 comm->cellsize_min_dlb[dd->dim[d]] =
7085 comm->cutoff/comm->cd[d].np_dlb;
7088 if (comm->cutoff_mbody <= 0)
7090 comm->cutoff_mbody = std::min(comm->cutoff, comm->cellsize_limit);
7092 if (isDlbOn(comm))
7094 set_dlb_limits(dd);
7098 gmx_bool dd_bonded_molpbc(const gmx_domdec_t *dd, int ePBC)
7100 /* If each molecule is a single charge group
7101 * or we use domain decomposition for each periodic dimension,
7102 * we do not need to take pbc into account for the bonded interactions.
7104 return (ePBC != epbcNONE && dd->comm->bInterCGBondeds &&
7105 !(dd->nc[XX] > 1 &&
7106 dd->nc[YY] > 1 &&
7107 (dd->nc[ZZ] > 1 || ePBC == epbcXY)));
7110 /*! \brief Sets grid size limits and PP-PME setup, prints settings to log */
7111 static void set_ddgrid_parameters(FILE *fplog, gmx_domdec_t *dd, real dlb_scale,
7112 const gmx_mtop_t *mtop, const t_inputrec *ir,
7113 const gmx_ddbox_t *ddbox)
7115 gmx_domdec_comm_t *comm;
7116 int natoms_tot;
7117 real vol_frac;
7119 comm = dd->comm;
7121 if (EEL_PME(ir->coulombtype) || EVDW_PME(ir->vdwtype))
7123 init_ddpme(dd, &comm->ddpme[0], 0);
7124 if (comm->npmedecompdim >= 2)
7126 init_ddpme(dd, &comm->ddpme[1], 1);
7129 else
7131 comm->npmenodes = 0;
7132 if (dd->pme_nodeid >= 0)
7134 gmx_fatal_collective(FARGS, dd->mpi_comm_all, DDMASTER(dd),
7135 "Can not have separate PME ranks without PME electrostatics");
7139 if (debug)
7141 fprintf(debug, "The DD cut-off is %f\n", comm->cutoff);
7143 if (!isDlbDisabled(comm))
7145 set_cell_limits_dlb(dd, dlb_scale, ir, ddbox);
7148 print_dd_settings(fplog, dd, mtop, ir, isDlbOn(comm), dlb_scale, ddbox);
7149 if (comm->dlbState == edlbsOffCanTurnOn)
7151 if (fplog)
7153 fprintf(fplog, "When dynamic load balancing gets turned on, these settings will change to:\n");
7155 print_dd_settings(fplog, dd, mtop, ir, TRUE, dlb_scale, ddbox);
7158 if (ir->ePBC == epbcNONE)
7160 vol_frac = 1 - 1/(double)dd->nnodes;
7162 else
7164 vol_frac =
7165 (1 + comm_box_frac(dd->nc, comm->cutoff, ddbox))/(double)dd->nnodes;
7167 if (debug)
7169 fprintf(debug, "Volume fraction for all DD zones: %f\n", vol_frac);
7171 natoms_tot = comm->cgs_gl.index[comm->cgs_gl.nr];
7173 dd->ga2la = ga2la_init(natoms_tot, static_cast<int>(vol_frac*natoms_tot));
7176 /*! \brief Set some important DD parameters that can be modified by env.vars */
7177 static void set_dd_envvar_options(FILE *fplog, gmx_domdec_t *dd, int rank_mysim)
7179 gmx_domdec_comm_t *comm = dd->comm;
7181 dd->bSendRecv2 = dd_getenv(fplog, "GMX_DD_USE_SENDRECV2", 0);
7182 comm->dlb_scale_lim = dd_getenv(fplog, "GMX_DLB_MAX_BOX_SCALING", 10);
7183 comm->eFlop = dd_getenv(fplog, "GMX_DLB_BASED_ON_FLOPS", 0);
7184 int recload = dd_getenv(fplog, "GMX_DD_RECORD_LOAD", 1);
7185 comm->nstDDDump = dd_getenv(fplog, "GMX_DD_NST_DUMP", 0);
7186 comm->nstDDDumpGrid = dd_getenv(fplog, "GMX_DD_NST_DUMP_GRID", 0);
7187 comm->DD_debug = dd_getenv(fplog, "GMX_DD_DEBUG", 0);
7189 if (dd->bSendRecv2 && fplog)
7191 fprintf(fplog, "Will use two sequential MPI_Sendrecv calls instead of two simultaneous non-blocking MPI_Irecv and MPI_Isend pairs for constraint and vsite communication\n");
7194 if (comm->eFlop)
7196 if (fplog)
7198 fprintf(fplog, "Will load balance based on FLOP count\n");
7200 if (comm->eFlop > 1)
7202 srand(1 + rank_mysim);
7204 comm->bRecordLoad = TRUE;
7206 else
7208 comm->bRecordLoad = (wallcycle_have_counter() && recload > 0);
7212 DomdecOptions::DomdecOptions() :
7213 checkBondedInteractions(TRUE),
7214 useBondedCommunication(TRUE),
7215 numPmeRanks(-1),
7216 rankOrder(DdRankOrder::pp_pme),
7217 minimumCommunicationRange(0),
7218 constraintCommunicationRange(0),
7219 dlbOption(DlbOption::turnOnWhenUseful),
7220 dlbScaling(0.8),
7221 cellSizeX(nullptr),
7222 cellSizeY(nullptr),
7223 cellSizeZ(nullptr)
7225 clear_ivec(numCells);
7228 gmx_domdec_t *init_domain_decomposition(FILE *fplog, t_commrec *cr,
7229 const DomdecOptions &options,
7230 const MdrunOptions &mdrunOptions,
7231 const gmx_mtop_t *mtop,
7232 const t_inputrec *ir,
7233 const matrix box,
7234 const rvec *xGlobal)
7236 gmx_domdec_t *dd;
7238 if (fplog)
7240 fprintf(fplog,
7241 "\nInitializing Domain Decomposition on %d ranks\n", cr->nnodes);
7244 snew(dd, 1);
7246 dd->comm = init_dd_comm();
7248 set_dd_envvar_options(fplog, dd, cr->nodeid);
7250 gmx_ddbox_t ddbox = {0};
7251 set_dd_limits_and_grid(fplog, cr, dd, options, mdrunOptions,
7252 mtop, ir,
7253 box, xGlobal,
7254 &ddbox);
7256 make_dd_communicators(fplog, cr, dd, options.rankOrder);
7258 if (thisRankHasDuty(cr, DUTY_PP))
7260 set_ddgrid_parameters(fplog, dd, options.dlbScaling, mtop, ir, &ddbox);
7262 setup_neighbor_relations(dd);
7265 /* Set overallocation to avoid frequent reallocation of arrays */
7266 set_over_alloc_dd(TRUE);
7268 /* Initialize DD paritioning counters */
7269 dd->comm->partition_step = INT_MIN;
7270 dd->ddp_count = 0;
7272 /* We currently don't know the number of threads yet, we set this later */
7273 dd->comm->nth = 0;
7275 clear_dd_cycle_counts(dd);
7277 return dd;
7280 static gmx_bool test_dd_cutoff(t_commrec *cr,
7281 t_state *state, const t_inputrec *ir,
7282 real cutoff_req)
7284 gmx_domdec_t *dd;
7285 gmx_ddbox_t ddbox;
7286 int d, dim, np;
7287 real inv_cell_size;
7288 int LocallyLimited;
7290 dd = cr->dd;
7292 set_ddbox(dd, FALSE, ir, state->box,
7293 TRUE, &dd->comm->cgs_gl, as_rvec_array(state->x.data()), &ddbox);
7295 LocallyLimited = 0;
7297 for (d = 0; d < dd->ndim; d++)
7299 dim = dd->dim[d];
7301 inv_cell_size = DD_CELL_MARGIN*dd->nc[dim]/ddbox.box_size[dim];
7302 if (dynamic_dd_box(&ddbox, ir))
7304 inv_cell_size *= DD_PRES_SCALE_MARGIN;
7307 np = 1 + (int)(cutoff_req*inv_cell_size*ddbox.skew_fac[dim]);
7309 if (!isDlbDisabled(dd->comm) && (dim < ddbox.npbcdim) && (dd->comm->cd[d].np_dlb > 0))
7311 if (np > dd->comm->cd[d].np_dlb)
7313 return FALSE;
7316 /* If a current local cell size is smaller than the requested
7317 * cut-off, we could still fix it, but this gets very complicated.
7318 * Without fixing here, we might actually need more checks.
7320 if ((dd->comm->cell_x1[dim] - dd->comm->cell_x0[dim])*ddbox.skew_fac[dim]*dd->comm->cd[d].np_dlb < cutoff_req)
7322 LocallyLimited = 1;
7327 if (!isDlbDisabled(dd->comm))
7329 /* If DLB is not active yet, we don't need to check the grid jumps.
7330 * Actually we shouldn't, because then the grid jump data is not set.
7332 if (isDlbOn(dd->comm) &&
7333 check_grid_jump(0, dd, cutoff_req, &ddbox, FALSE))
7335 LocallyLimited = 1;
7338 gmx_sumi(1, &LocallyLimited, cr);
7340 if (LocallyLimited > 0)
7342 return FALSE;
7346 return TRUE;
7349 gmx_bool change_dd_cutoff(t_commrec *cr, t_state *state, const t_inputrec *ir,
7350 real cutoff_req)
7352 gmx_bool bCutoffAllowed;
7354 bCutoffAllowed = test_dd_cutoff(cr, state, ir, cutoff_req);
7356 if (bCutoffAllowed)
7358 cr->dd->comm->cutoff = cutoff_req;
7361 return bCutoffAllowed;
7364 void set_dd_dlb_max_cutoff(t_commrec *cr, real cutoff)
7366 gmx_domdec_comm_t *comm;
7368 comm = cr->dd->comm;
7370 /* Turn on the DLB limiting (might have been on already) */
7371 comm->bPMELoadBalDLBLimits = TRUE;
7373 /* Change the cut-off limit */
7374 comm->PMELoadBal_max_cutoff = cutoff;
7376 if (debug)
7378 fprintf(debug, "PME load balancing set a limit to the DLB staggering such that a %f cut-off will continue to fit\n",
7379 comm->PMELoadBal_max_cutoff);
7383 /* Sets whether we should later check the load imbalance data, so that
7384 * we can trigger dynamic load balancing if enough imbalance has
7385 * arisen.
7387 * Used after PME load balancing unlocks DLB, so that the check
7388 * whether DLB will be useful can happen immediately.
7390 static void dd_dlb_set_should_check_whether_to_turn_dlb_on(gmx_domdec_t *dd, gmx_bool bValue)
7392 if (dd->comm->dlbState == edlbsOffCanTurnOn)
7394 dd->comm->bCheckWhetherToTurnDlbOn = bValue;
7396 if (bValue == TRUE)
7398 /* Store the DD partitioning count, so we can ignore cycle counts
7399 * over the next nstlist steps, which are often slower.
7401 dd->comm->ddPartioningCountFirstDlbOff = dd->ddp_count;
7406 /* Returns if we should check whether there has been enough load
7407 * imbalance to trigger dynamic load balancing.
7409 static gmx_bool dd_dlb_get_should_check_whether_to_turn_dlb_on(gmx_domdec_t *dd)
7411 if (dd->comm->dlbState != edlbsOffCanTurnOn)
7413 return FALSE;
7416 if (dd->ddp_count <= dd->comm->ddPartioningCountFirstDlbOff)
7418 /* We ignore the first nstlist steps at the start of the run
7419 * or after PME load balancing or after turning DLB off, since
7420 * these often have extra allocation or cache miss overhead.
7422 return FALSE;
7425 if (dd->comm->cycl_n[ddCyclStep] == 0)
7427 /* We can have zero timed steps when dd_partition_system is called
7428 * more than once at the same step, e.g. with replica exchange.
7429 * Turning on DLB would trigger an assertion failure later, but is
7430 * also useless right after exchanging replicas.
7432 return FALSE;
7435 /* We should check whether we should use DLB directly after
7436 * unlocking DLB. */
7437 if (dd->comm->bCheckWhetherToTurnDlbOn)
7439 /* This flag was set when the PME load-balancing routines
7440 unlocked DLB, and should now be cleared. */
7441 dd_dlb_set_should_check_whether_to_turn_dlb_on(dd, FALSE);
7442 return TRUE;
7444 /* We check whether we should use DLB every c_checkTurnDlbOnInterval
7445 * partitionings (we do not do this every partioning, so that we
7446 * avoid excessive communication). */
7447 if (dd->comm->n_load_have % c_checkTurnDlbOnInterval == c_checkTurnDlbOnInterval - 1)
7449 return TRUE;
7452 return FALSE;
7455 gmx_bool dd_dlb_is_on(const gmx_domdec_t *dd)
7457 return isDlbOn(dd->comm);
7460 gmx_bool dd_dlb_is_locked(const gmx_domdec_t *dd)
7462 return (dd->comm->dlbState == edlbsOffTemporarilyLocked);
7465 void dd_dlb_lock(gmx_domdec_t *dd)
7467 /* We can only lock the DLB when it is set to auto, otherwise don't do anything */
7468 if (dd->comm->dlbState == edlbsOffCanTurnOn)
7470 dd->comm->dlbState = edlbsOffTemporarilyLocked;
7474 void dd_dlb_unlock(gmx_domdec_t *dd)
7476 /* We can only lock the DLB when it is set to auto, otherwise don't do anything */
7477 if (dd->comm->dlbState == edlbsOffTemporarilyLocked)
7479 dd->comm->dlbState = edlbsOffCanTurnOn;
7480 dd_dlb_set_should_check_whether_to_turn_dlb_on(dd, TRUE);
7484 static void merge_cg_buffers(int ncell,
7485 gmx_domdec_comm_dim_t *cd, int pulse,
7486 int *ncg_cell,
7487 int *index_gl, int *recv_i,
7488 rvec *cg_cm, rvec *recv_vr,
7489 int *cgindex,
7490 cginfo_mb_t *cginfo_mb, int *cginfo)
7492 gmx_domdec_ind_t *ind, *ind_p;
7493 int p, cell, c, cg, cg0, cg1, cg_gl, nat;
7494 int shift, shift_at;
7496 ind = &cd->ind[pulse];
7498 /* First correct the already stored data */
7499 shift = ind->nrecv[ncell];
7500 for (cell = ncell-1; cell >= 0; cell--)
7502 shift -= ind->nrecv[cell];
7503 if (shift > 0)
7505 /* Move the cg's present from previous grid pulses */
7506 cg0 = ncg_cell[ncell+cell];
7507 cg1 = ncg_cell[ncell+cell+1];
7508 cgindex[cg1+shift] = cgindex[cg1];
7509 for (cg = cg1-1; cg >= cg0; cg--)
7511 index_gl[cg+shift] = index_gl[cg];
7512 copy_rvec(cg_cm[cg], cg_cm[cg+shift]);
7513 cgindex[cg+shift] = cgindex[cg];
7514 cginfo[cg+shift] = cginfo[cg];
7516 /* Correct the already stored send indices for the shift */
7517 for (p = 1; p <= pulse; p++)
7519 ind_p = &cd->ind[p];
7520 cg0 = 0;
7521 for (c = 0; c < cell; c++)
7523 cg0 += ind_p->nsend[c];
7525 cg1 = cg0 + ind_p->nsend[cell];
7526 for (cg = cg0; cg < cg1; cg++)
7528 ind_p->index[cg] += shift;
7534 /* Merge in the communicated buffers */
7535 shift = 0;
7536 shift_at = 0;
7537 cg0 = 0;
7538 for (cell = 0; cell < ncell; cell++)
7540 cg1 = ncg_cell[ncell+cell+1] + shift;
7541 if (shift_at > 0)
7543 /* Correct the old cg indices */
7544 for (cg = ncg_cell[ncell+cell]; cg < cg1; cg++)
7546 cgindex[cg+1] += shift_at;
7549 for (cg = 0; cg < ind->nrecv[cell]; cg++)
7551 /* Copy this charge group from the buffer */
7552 index_gl[cg1] = recv_i[cg0];
7553 copy_rvec(recv_vr[cg0], cg_cm[cg1]);
7554 /* Add it to the cgindex */
7555 cg_gl = index_gl[cg1];
7556 cginfo[cg1] = ddcginfo(cginfo_mb, cg_gl);
7557 nat = GET_CGINFO_NATOMS(cginfo[cg1]);
7558 cgindex[cg1+1] = cgindex[cg1] + nat;
7559 cg0++;
7560 cg1++;
7561 shift_at += nat;
7563 shift += ind->nrecv[cell];
7564 ncg_cell[ncell+cell+1] = cg1;
7568 static void make_cell2at_index(gmx_domdec_comm_dim_t *cd,
7569 int nzone, int cg0, const int *cgindex)
7571 int cg, zone, p;
7573 /* Store the atom block boundaries for easy copying of communication buffers
7575 cg = cg0;
7576 for (zone = 0; zone < nzone; zone++)
7578 for (p = 0; p < cd->np; p++)
7580 cd->ind[p].cell2at0[zone] = cgindex[cg];
7581 cg += cd->ind[p].nrecv[zone];
7582 cd->ind[p].cell2at1[zone] = cgindex[cg];
7587 static gmx_bool missing_link(t_blocka *link, int cg_gl, char *bLocalCG)
7589 int i;
7590 gmx_bool bMiss;
7592 bMiss = FALSE;
7593 for (i = link->index[cg_gl]; i < link->index[cg_gl+1]; i++)
7595 if (!bLocalCG[link->a[i]])
7597 bMiss = TRUE;
7601 return bMiss;
7604 /* Domain corners for communication, a maximum of 4 i-zones see a j domain */
7605 typedef struct {
7606 real c[DIM][4]; /* the corners for the non-bonded communication */
7607 real cr0; /* corner for rounding */
7608 real cr1[4]; /* corners for rounding */
7609 real bc[DIM]; /* corners for bounded communication */
7610 real bcr1; /* corner for rounding for bonded communication */
7611 } dd_corners_t;
7613 /* Determine the corners of the domain(s) we are communicating with */
7614 static void
7615 set_dd_corners(const gmx_domdec_t *dd,
7616 int dim0, int dim1, int dim2,
7617 gmx_bool bDistMB,
7618 dd_corners_t *c)
7620 const gmx_domdec_comm_t *comm;
7621 const gmx_domdec_zones_t *zones;
7622 int i, j;
7624 comm = dd->comm;
7626 zones = &comm->zones;
7628 /* Keep the compiler happy */
7629 c->cr0 = 0;
7630 c->bcr1 = 0;
7632 /* The first dimension is equal for all cells */
7633 c->c[0][0] = comm->cell_x0[dim0];
7634 if (bDistMB)
7636 c->bc[0] = c->c[0][0];
7638 if (dd->ndim >= 2)
7640 dim1 = dd->dim[1];
7641 /* This cell row is only seen from the first row */
7642 c->c[1][0] = comm->cell_x0[dim1];
7643 /* All rows can see this row */
7644 c->c[1][1] = comm->cell_x0[dim1];
7645 if (isDlbOn(dd->comm))
7647 c->c[1][1] = std::max(comm->cell_x0[dim1], comm->zone_d1[1].mch0);
7648 if (bDistMB)
7650 /* For the multi-body distance we need the maximum */
7651 c->bc[1] = std::max(comm->cell_x0[dim1], comm->zone_d1[1].p1_0);
7654 /* Set the upper-right corner for rounding */
7655 c->cr0 = comm->cell_x1[dim0];
7657 if (dd->ndim >= 3)
7659 dim2 = dd->dim[2];
7660 for (j = 0; j < 4; j++)
7662 c->c[2][j] = comm->cell_x0[dim2];
7664 if (isDlbOn(dd->comm))
7666 /* Use the maximum of the i-cells that see a j-cell */
7667 for (i = 0; i < zones->nizone; i++)
7669 for (j = zones->izone[i].j0; j < zones->izone[i].j1; j++)
7671 if (j >= 4)
7673 c->c[2][j-4] =
7674 std::max(c->c[2][j-4],
7675 comm->zone_d2[zones->shift[i][dim0]][zones->shift[i][dim1]].mch0);
7679 if (bDistMB)
7681 /* For the multi-body distance we need the maximum */
7682 c->bc[2] = comm->cell_x0[dim2];
7683 for (i = 0; i < 2; i++)
7685 for (j = 0; j < 2; j++)
7687 c->bc[2] = std::max(c->bc[2], comm->zone_d2[i][j].p1_0);
7693 /* Set the upper-right corner for rounding */
7694 /* Cell (0,0,0) and cell (1,0,0) can see cell 4 (0,1,1)
7695 * Only cell (0,0,0) can see cell 7 (1,1,1)
7697 c->cr1[0] = comm->cell_x1[dim1];
7698 c->cr1[3] = comm->cell_x1[dim1];
7699 if (isDlbOn(dd->comm))
7701 c->cr1[0] = std::max(comm->cell_x1[dim1], comm->zone_d1[1].mch1);
7702 if (bDistMB)
7704 /* For the multi-body distance we need the maximum */
7705 c->bcr1 = std::max(comm->cell_x1[dim1], comm->zone_d1[1].p1_1);
7712 /* Determine which cg's we need to send in this pulse from this zone */
7713 static void
7714 get_zone_pulse_cgs(gmx_domdec_t *dd,
7715 int zonei, int zone,
7716 int cg0, int cg1,
7717 const int *index_gl,
7718 const int *cgindex,
7719 int dim, int dim_ind,
7720 int dim0, int dim1, int dim2,
7721 real r_comm2, real r_bcomm2,
7722 matrix box,
7723 ivec tric_dist,
7724 rvec *normal,
7725 real skew_fac2_d, real skew_fac_01,
7726 rvec *v_d, rvec *v_0, rvec *v_1,
7727 const dd_corners_t *c,
7728 rvec sf2_round,
7729 gmx_bool bDistBonded,
7730 gmx_bool bBondComm,
7731 gmx_bool bDist2B,
7732 gmx_bool bDistMB,
7733 rvec *cg_cm,
7734 int *cginfo,
7735 gmx_domdec_ind_t *ind,
7736 int **ibuf, int *ibuf_nalloc,
7737 vec_rvec_t *vbuf,
7738 int *nsend_ptr,
7739 int *nat_ptr,
7740 int *nsend_z_ptr)
7742 gmx_domdec_comm_t *comm;
7743 gmx_bool bScrew;
7744 gmx_bool bDistMB_pulse;
7745 int cg, i;
7746 real r2, rb2, r, tric_sh;
7747 rvec rn, rb;
7748 int dimd;
7749 int nsend_z, nsend, nat;
7751 comm = dd->comm;
7753 bScrew = (dd->bScrewPBC && dim == XX);
7755 bDistMB_pulse = (bDistMB && bDistBonded);
7757 nsend_z = 0;
7758 nsend = *nsend_ptr;
7759 nat = *nat_ptr;
7761 for (cg = cg0; cg < cg1; cg++)
7763 r2 = 0;
7764 rb2 = 0;
7765 if (tric_dist[dim_ind] == 0)
7767 /* Rectangular direction, easy */
7768 r = cg_cm[cg][dim] - c->c[dim_ind][zone];
7769 if (r > 0)
7771 r2 += r*r;
7773 if (bDistMB_pulse)
7775 r = cg_cm[cg][dim] - c->bc[dim_ind];
7776 if (r > 0)
7778 rb2 += r*r;
7781 /* Rounding gives at most a 16% reduction
7782 * in communicated atoms
7784 if (dim_ind >= 1 && (zonei == 1 || zonei == 2))
7786 r = cg_cm[cg][dim0] - c->cr0;
7787 /* This is the first dimension, so always r >= 0 */
7788 r2 += r*r;
7789 if (bDistMB_pulse)
7791 rb2 += r*r;
7794 if (dim_ind == 2 && (zonei == 2 || zonei == 3))
7796 r = cg_cm[cg][dim1] - c->cr1[zone];
7797 if (r > 0)
7799 r2 += r*r;
7801 if (bDistMB_pulse)
7803 r = cg_cm[cg][dim1] - c->bcr1;
7804 if (r > 0)
7806 rb2 += r*r;
7811 else
7813 /* Triclinic direction, more complicated */
7814 clear_rvec(rn);
7815 clear_rvec(rb);
7816 /* Rounding, conservative as the skew_fac multiplication
7817 * will slightly underestimate the distance.
7819 if (dim_ind >= 1 && (zonei == 1 || zonei == 2))
7821 rn[dim0] = cg_cm[cg][dim0] - c->cr0;
7822 for (i = dim0+1; i < DIM; i++)
7824 rn[dim0] -= cg_cm[cg][i]*v_0[i][dim0];
7826 r2 = rn[dim0]*rn[dim0]*sf2_round[dim0];
7827 if (bDistMB_pulse)
7829 rb[dim0] = rn[dim0];
7830 rb2 = r2;
7832 /* Take care that the cell planes along dim0 might not
7833 * be orthogonal to those along dim1 and dim2.
7835 for (i = 1; i <= dim_ind; i++)
7837 dimd = dd->dim[i];
7838 if (normal[dim0][dimd] > 0)
7840 rn[dimd] -= rn[dim0]*normal[dim0][dimd];
7841 if (bDistMB_pulse)
7843 rb[dimd] -= rb[dim0]*normal[dim0][dimd];
7848 if (dim_ind == 2 && (zonei == 2 || zonei == 3))
7850 rn[dim1] += cg_cm[cg][dim1] - c->cr1[zone];
7851 tric_sh = 0;
7852 for (i = dim1+1; i < DIM; i++)
7854 tric_sh -= cg_cm[cg][i]*v_1[i][dim1];
7856 rn[dim1] += tric_sh;
7857 if (rn[dim1] > 0)
7859 r2 += rn[dim1]*rn[dim1]*sf2_round[dim1];
7860 /* Take care of coupling of the distances
7861 * to the planes along dim0 and dim1 through dim2.
7863 r2 -= rn[dim0]*rn[dim1]*skew_fac_01;
7864 /* Take care that the cell planes along dim1
7865 * might not be orthogonal to that along dim2.
7867 if (normal[dim1][dim2] > 0)
7869 rn[dim2] -= rn[dim1]*normal[dim1][dim2];
7872 if (bDistMB_pulse)
7874 rb[dim1] +=
7875 cg_cm[cg][dim1] - c->bcr1 + tric_sh;
7876 if (rb[dim1] > 0)
7878 rb2 += rb[dim1]*rb[dim1]*sf2_round[dim1];
7879 /* Take care of coupling of the distances
7880 * to the planes along dim0 and dim1 through dim2.
7882 rb2 -= rb[dim0]*rb[dim1]*skew_fac_01;
7883 /* Take care that the cell planes along dim1
7884 * might not be orthogonal to that along dim2.
7886 if (normal[dim1][dim2] > 0)
7888 rb[dim2] -= rb[dim1]*normal[dim1][dim2];
7893 /* The distance along the communication direction */
7894 rn[dim] += cg_cm[cg][dim] - c->c[dim_ind][zone];
7895 tric_sh = 0;
7896 for (i = dim+1; i < DIM; i++)
7898 tric_sh -= cg_cm[cg][i]*v_d[i][dim];
7900 rn[dim] += tric_sh;
7901 if (rn[dim] > 0)
7903 r2 += rn[dim]*rn[dim]*skew_fac2_d;
7904 /* Take care of coupling of the distances
7905 * to the planes along dim0 and dim1 through dim2.
7907 if (dim_ind == 1 && zonei == 1)
7909 r2 -= rn[dim0]*rn[dim]*skew_fac_01;
7912 if (bDistMB_pulse)
7914 clear_rvec(rb);
7915 rb[dim] += cg_cm[cg][dim] - c->bc[dim_ind] + tric_sh;
7916 if (rb[dim] > 0)
7918 rb2 += rb[dim]*rb[dim]*skew_fac2_d;
7919 /* Take care of coupling of the distances
7920 * to the planes along dim0 and dim1 through dim2.
7922 if (dim_ind == 1 && zonei == 1)
7924 rb2 -= rb[dim0]*rb[dim]*skew_fac_01;
7930 if (r2 < r_comm2 ||
7931 (bDistBonded &&
7932 ((bDistMB && rb2 < r_bcomm2) ||
7933 (bDist2B && r2 < r_bcomm2)) &&
7934 (!bBondComm ||
7935 (GET_CGINFO_BOND_INTER(cginfo[cg]) &&
7936 missing_link(comm->cglink, index_gl[cg],
7937 comm->bLocalCG)))))
7939 /* Make an index to the local charge groups */
7940 if (nsend+1 > ind->nalloc)
7942 ind->nalloc = over_alloc_large(nsend+1);
7943 srenew(ind->index, ind->nalloc);
7945 if (nsend+1 > *ibuf_nalloc)
7947 *ibuf_nalloc = over_alloc_large(nsend+1);
7948 srenew(*ibuf, *ibuf_nalloc);
7950 ind->index[nsend] = cg;
7951 (*ibuf)[nsend] = index_gl[cg];
7952 nsend_z++;
7953 vec_rvec_check_alloc(vbuf, nsend+1);
7955 if (dd->ci[dim] == 0)
7957 /* Correct cg_cm for pbc */
7958 rvec_add(cg_cm[cg], box[dim], vbuf->v[nsend]);
7959 if (bScrew)
7961 vbuf->v[nsend][YY] = box[YY][YY] - vbuf->v[nsend][YY];
7962 vbuf->v[nsend][ZZ] = box[ZZ][ZZ] - vbuf->v[nsend][ZZ];
7965 else
7967 copy_rvec(cg_cm[cg], vbuf->v[nsend]);
7969 nsend++;
7970 nat += cgindex[cg+1] - cgindex[cg];
7974 *nsend_ptr = nsend;
7975 *nat_ptr = nat;
7976 *nsend_z_ptr = nsend_z;
7979 static void setup_dd_communication(gmx_domdec_t *dd,
7980 matrix box, gmx_ddbox_t *ddbox,
7981 t_forcerec *fr,
7982 t_state *state, PaddedRVecVector *f)
7984 int dim_ind, dim, dim0, dim1, dim2, dimd, p, nat_tot;
7985 int nzone, nzone_send, zone, zonei, cg0, cg1;
7986 int c, i, cg, cg_gl, nrcg;
7987 int *zone_cg_range, pos_cg, *index_gl, *cgindex, *recv_i;
7988 gmx_domdec_comm_t *comm;
7989 gmx_domdec_zones_t *zones;
7990 gmx_domdec_comm_dim_t *cd;
7991 gmx_domdec_ind_t *ind;
7992 cginfo_mb_t *cginfo_mb;
7993 gmx_bool bBondComm, bDist2B, bDistMB, bDistBonded;
7994 real r_comm2, r_bcomm2;
7995 dd_corners_t corners;
7996 ivec tric_dist;
7997 rvec *cg_cm, *normal, *v_d, *v_0 = nullptr, *v_1 = nullptr, *recv_vr;
7998 real skew_fac2_d, skew_fac_01;
7999 rvec sf2_round;
8000 int nsend, nat;
8001 int th;
8003 if (debug)
8005 fprintf(debug, "Setting up DD communication\n");
8008 comm = dd->comm;
8010 if (comm->nth == 0)
8012 /* Initialize the thread data.
8013 * This can not be done in init_domain_decomposition,
8014 * as the numbers of threads is determined later.
8016 comm->nth = gmx_omp_nthreads_get(emntDomdec);
8017 if (comm->nth > 1)
8019 snew(comm->dth, comm->nth);
8023 switch (fr->cutoff_scheme)
8025 case ecutsGROUP:
8026 cg_cm = fr->cg_cm;
8027 break;
8028 case ecutsVERLET:
8029 cg_cm = as_rvec_array(state->x.data());
8030 break;
8031 default:
8032 gmx_incons("unimplemented");
8033 cg_cm = nullptr;
8036 for (dim_ind = 0; dim_ind < dd->ndim; dim_ind++)
8038 /* Check if we need to use triclinic distances */
8039 tric_dist[dim_ind] = 0;
8040 for (i = 0; i <= dim_ind; i++)
8042 if (ddbox->tric_dir[dd->dim[i]])
8044 tric_dist[dim_ind] = 1;
8049 bBondComm = comm->bBondComm;
8051 /* Do we need to determine extra distances for multi-body bondeds? */
8052 bDistMB = (comm->bInterCGMultiBody && isDlbOn(dd->comm) && dd->ndim > 1);
8054 /* Do we need to determine extra distances for only two-body bondeds? */
8055 bDist2B = (bBondComm && !bDistMB);
8057 r_comm2 = gmx::square(comm->cutoff);
8058 r_bcomm2 = gmx::square(comm->cutoff_mbody);
8060 if (debug)
8062 fprintf(debug, "bBondComm %d, r_bc %f\n", bBondComm, std::sqrt(r_bcomm2));
8065 zones = &comm->zones;
8067 dim0 = dd->dim[0];
8068 dim1 = (dd->ndim >= 2 ? dd->dim[1] : -1);
8069 dim2 = (dd->ndim >= 3 ? dd->dim[2] : -1);
8071 set_dd_corners(dd, dim0, dim1, dim2, bDistMB, &corners);
8073 /* Triclinic stuff */
8074 normal = ddbox->normal;
8075 skew_fac_01 = 0;
8076 if (dd->ndim >= 2)
8078 v_0 = ddbox->v[dim0];
8079 if (ddbox->tric_dir[dim0] && ddbox->tric_dir[dim1])
8081 /* Determine the coupling coefficient for the distances
8082 * to the cell planes along dim0 and dim1 through dim2.
8083 * This is required for correct rounding.
8085 skew_fac_01 =
8086 ddbox->v[dim0][dim1+1][dim0]*ddbox->v[dim1][dim1+1][dim1];
8087 if (debug)
8089 fprintf(debug, "\nskew_fac_01 %f\n", skew_fac_01);
8093 if (dd->ndim >= 3)
8095 v_1 = ddbox->v[dim1];
8098 zone_cg_range = zones->cg_range;
8099 index_gl = dd->index_gl;
8100 cgindex = dd->cgindex;
8101 cginfo_mb = fr->cginfo_mb;
8103 zone_cg_range[0] = 0;
8104 zone_cg_range[1] = dd->ncg_home;
8105 comm->zone_ncg1[0] = dd->ncg_home;
8106 pos_cg = dd->ncg_home;
8108 nat_tot = dd->nat_home;
8109 nzone = 1;
8110 for (dim_ind = 0; dim_ind < dd->ndim; dim_ind++)
8112 dim = dd->dim[dim_ind];
8113 cd = &comm->cd[dim_ind];
8115 if (dim >= ddbox->npbcdim && dd->ci[dim] == 0)
8117 /* No pbc in this dimension, the first node should not comm. */
8118 nzone_send = 0;
8120 else
8122 nzone_send = nzone;
8125 v_d = ddbox->v[dim];
8126 skew_fac2_d = gmx::square(ddbox->skew_fac[dim]);
8128 cd->bInPlace = TRUE;
8129 for (p = 0; p < cd->np; p++)
8131 /* Only atoms communicated in the first pulse are used
8132 * for multi-body bonded interactions or for bBondComm.
8134 bDistBonded = ((bDistMB || bDist2B) && p == 0);
8136 ind = &cd->ind[p];
8137 nsend = 0;
8138 nat = 0;
8139 for (zone = 0; zone < nzone_send; zone++)
8141 if (tric_dist[dim_ind] && dim_ind > 0)
8143 /* Determine slightly more optimized skew_fac's
8144 * for rounding.
8145 * This reduces the number of communicated atoms
8146 * by about 10% for 3D DD of rhombic dodecahedra.
8148 for (dimd = 0; dimd < dim; dimd++)
8150 sf2_round[dimd] = 1;
8151 if (ddbox->tric_dir[dimd])
8153 for (i = dd->dim[dimd]+1; i < DIM; i++)
8155 /* If we are shifted in dimension i
8156 * and the cell plane is tilted forward
8157 * in dimension i, skip this coupling.
8159 if (!(zones->shift[nzone+zone][i] &&
8160 ddbox->v[dimd][i][dimd] >= 0))
8162 sf2_round[dimd] +=
8163 gmx::square(ddbox->v[dimd][i][dimd]);
8166 sf2_round[dimd] = 1/sf2_round[dimd];
8171 zonei = zone_perm[dim_ind][zone];
8172 if (p == 0)
8174 /* Here we permutate the zones to obtain a convenient order
8175 * for neighbor searching
8177 cg0 = zone_cg_range[zonei];
8178 cg1 = zone_cg_range[zonei+1];
8180 else
8182 /* Look only at the cg's received in the previous grid pulse
8184 cg1 = zone_cg_range[nzone+zone+1];
8185 cg0 = cg1 - cd->ind[p-1].nrecv[zone];
8188 #pragma omp parallel for num_threads(comm->nth) schedule(static)
8189 for (th = 0; th < comm->nth; th++)
8193 gmx_domdec_ind_t *ind_p;
8194 int **ibuf_p, *ibuf_nalloc_p;
8195 vec_rvec_t *vbuf_p;
8196 int *nsend_p, *nat_p;
8197 int *nsend_zone_p;
8198 int cg0_th, cg1_th;
8200 if (th == 0)
8202 /* Thread 0 writes in the comm buffers */
8203 ind_p = ind;
8204 ibuf_p = &comm->buf_int;
8205 ibuf_nalloc_p = &comm->nalloc_int;
8206 vbuf_p = &comm->vbuf;
8207 nsend_p = &nsend;
8208 nat_p = &nat;
8209 nsend_zone_p = &ind->nsend[zone];
8211 else
8213 /* Other threads write into temp buffers */
8214 ind_p = &comm->dth[th].ind;
8215 ibuf_p = &comm->dth[th].ibuf;
8216 ibuf_nalloc_p = &comm->dth[th].ibuf_nalloc;
8217 vbuf_p = &comm->dth[th].vbuf;
8218 nsend_p = &comm->dth[th].nsend;
8219 nat_p = &comm->dth[th].nat;
8220 nsend_zone_p = &comm->dth[th].nsend_zone;
8222 comm->dth[th].nsend = 0;
8223 comm->dth[th].nat = 0;
8224 comm->dth[th].nsend_zone = 0;
8227 if (comm->nth == 1)
8229 cg0_th = cg0;
8230 cg1_th = cg1;
8232 else
8234 cg0_th = cg0 + ((cg1 - cg0)* th )/comm->nth;
8235 cg1_th = cg0 + ((cg1 - cg0)*(th+1))/comm->nth;
8238 /* Get the cg's for this pulse in this zone */
8239 get_zone_pulse_cgs(dd, zonei, zone, cg0_th, cg1_th,
8240 index_gl, cgindex,
8241 dim, dim_ind, dim0, dim1, dim2,
8242 r_comm2, r_bcomm2,
8243 box, tric_dist,
8244 normal, skew_fac2_d, skew_fac_01,
8245 v_d, v_0, v_1, &corners, sf2_round,
8246 bDistBonded, bBondComm,
8247 bDist2B, bDistMB,
8248 cg_cm, fr->cginfo,
8249 ind_p,
8250 ibuf_p, ibuf_nalloc_p,
8251 vbuf_p,
8252 nsend_p, nat_p,
8253 nsend_zone_p);
8255 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
8256 } // END
8258 /* Append data of threads>=1 to the communication buffers */
8259 for (th = 1; th < comm->nth; th++)
8261 dd_comm_setup_work_t *dth;
8262 int i, ns1;
8264 dth = &comm->dth[th];
8266 ns1 = nsend + dth->nsend_zone;
8267 if (ns1 > ind->nalloc)
8269 ind->nalloc = over_alloc_dd(ns1);
8270 srenew(ind->index, ind->nalloc);
8272 if (ns1 > comm->nalloc_int)
8274 comm->nalloc_int = over_alloc_dd(ns1);
8275 srenew(comm->buf_int, comm->nalloc_int);
8277 if (ns1 > comm->vbuf.nalloc)
8279 comm->vbuf.nalloc = over_alloc_dd(ns1);
8280 srenew(comm->vbuf.v, comm->vbuf.nalloc);
8283 for (i = 0; i < dth->nsend_zone; i++)
8285 ind->index[nsend] = dth->ind.index[i];
8286 comm->buf_int[nsend] = dth->ibuf[i];
8287 copy_rvec(dth->vbuf.v[i],
8288 comm->vbuf.v[nsend]);
8289 nsend++;
8291 nat += dth->nat;
8292 ind->nsend[zone] += dth->nsend_zone;
8295 /* Clear the counts in case we do not have pbc */
8296 for (zone = nzone_send; zone < nzone; zone++)
8298 ind->nsend[zone] = 0;
8300 ind->nsend[nzone] = nsend;
8301 ind->nsend[nzone+1] = nat;
8302 /* Communicate the number of cg's and atoms to receive */
8303 dd_sendrecv_int(dd, dim_ind, dddirBackward,
8304 ind->nsend, nzone+2,
8305 ind->nrecv, nzone+2);
8307 /* The rvec buffer is also required for atom buffers of size nsend
8308 * in dd_move_x and dd_move_f.
8310 vec_rvec_check_alloc(&comm->vbuf, ind->nsend[nzone+1]);
8312 if (p > 0)
8314 /* We can receive in place if only the last zone is not empty */
8315 for (zone = 0; zone < nzone-1; zone++)
8317 if (ind->nrecv[zone] > 0)
8319 cd->bInPlace = FALSE;
8322 if (!cd->bInPlace)
8324 /* The int buffer is only required here for the cg indices */
8325 if (ind->nrecv[nzone] > comm->nalloc_int2)
8327 comm->nalloc_int2 = over_alloc_dd(ind->nrecv[nzone]);
8328 srenew(comm->buf_int2, comm->nalloc_int2);
8330 /* The rvec buffer is also required for atom buffers
8331 * of size nrecv in dd_move_x and dd_move_f.
8333 i = std::max(cd->ind[0].nrecv[nzone+1], ind->nrecv[nzone+1]);
8334 vec_rvec_check_alloc(&comm->vbuf2, i);
8338 /* Make space for the global cg indices */
8339 if (pos_cg + ind->nrecv[nzone] > dd->cg_nalloc
8340 || dd->cg_nalloc == 0)
8342 dd->cg_nalloc = over_alloc_dd(pos_cg + ind->nrecv[nzone]);
8343 srenew(index_gl, dd->cg_nalloc);
8344 srenew(cgindex, dd->cg_nalloc+1);
8346 /* Communicate the global cg indices */
8347 if (cd->bInPlace)
8349 recv_i = index_gl + pos_cg;
8351 else
8353 recv_i = comm->buf_int2;
8355 dd_sendrecv_int(dd, dim_ind, dddirBackward,
8356 comm->buf_int, nsend,
8357 recv_i, ind->nrecv[nzone]);
8359 /* Make space for cg_cm */
8360 dd_check_alloc_ncg(fr, state, f, pos_cg + ind->nrecv[nzone]);
8361 if (fr->cutoff_scheme == ecutsGROUP)
8363 cg_cm = fr->cg_cm;
8365 else
8367 cg_cm = as_rvec_array(state->x.data());
8369 /* Communicate cg_cm */
8370 if (cd->bInPlace)
8372 recv_vr = cg_cm + pos_cg;
8374 else
8376 recv_vr = comm->vbuf2.v;
8378 dd_sendrecv_rvec(dd, dim_ind, dddirBackward,
8379 comm->vbuf.v, nsend,
8380 recv_vr, ind->nrecv[nzone]);
8382 /* Make the charge group index */
8383 if (cd->bInPlace)
8385 zone = (p == 0 ? 0 : nzone - 1);
8386 while (zone < nzone)
8388 for (cg = 0; cg < ind->nrecv[zone]; cg++)
8390 cg_gl = index_gl[pos_cg];
8391 fr->cginfo[pos_cg] = ddcginfo(cginfo_mb, cg_gl);
8392 nrcg = GET_CGINFO_NATOMS(fr->cginfo[pos_cg]);
8393 cgindex[pos_cg+1] = cgindex[pos_cg] + nrcg;
8394 if (bBondComm)
8396 /* Update the charge group presence,
8397 * so we can use it in the next pass of the loop.
8399 comm->bLocalCG[cg_gl] = TRUE;
8401 pos_cg++;
8403 if (p == 0)
8405 comm->zone_ncg1[nzone+zone] = ind->nrecv[zone];
8407 zone++;
8408 zone_cg_range[nzone+zone] = pos_cg;
8411 else
8413 /* This part of the code is never executed with bBondComm. */
8414 merge_cg_buffers(nzone, cd, p, zone_cg_range,
8415 index_gl, recv_i, cg_cm, recv_vr,
8416 cgindex, fr->cginfo_mb, fr->cginfo);
8417 pos_cg += ind->nrecv[nzone];
8419 nat_tot += ind->nrecv[nzone+1];
8421 if (!cd->bInPlace)
8423 /* Store the atom block for easy copying of communication buffers */
8424 make_cell2at_index(cd, nzone, zone_cg_range[nzone], cgindex);
8426 nzone += nzone;
8428 dd->index_gl = index_gl;
8429 dd->cgindex = cgindex;
8431 dd->ncg_tot = zone_cg_range[zones->n];
8432 dd->nat_tot = nat_tot;
8433 comm->nat[ddnatHOME] = dd->nat_home;
8434 for (i = ddnatZONE; i < ddnatNR; i++)
8436 comm->nat[i] = dd->nat_tot;
8439 if (!bBondComm)
8441 /* We don't need to update cginfo, since that was alrady done above.
8442 * So we pass NULL for the forcerec.
8444 dd_set_cginfo(dd->index_gl, dd->ncg_home, dd->ncg_tot,
8445 nullptr, comm->bLocalCG);
8448 if (debug)
8450 fprintf(debug, "Finished setting up DD communication, zones:");
8451 for (c = 0; c < zones->n; c++)
8453 fprintf(debug, " %d", zones->cg_range[c+1]-zones->cg_range[c]);
8455 fprintf(debug, "\n");
8459 static void set_cg_boundaries(gmx_domdec_zones_t *zones)
8461 int c;
8463 for (c = 0; c < zones->nizone; c++)
8465 zones->izone[c].cg1 = zones->cg_range[c+1];
8466 zones->izone[c].jcg0 = zones->cg_range[zones->izone[c].j0];
8467 zones->izone[c].jcg1 = zones->cg_range[zones->izone[c].j1];
8471 /* \brief Set zone dimensions for zones \p zone_start to \p zone_end-1
8473 * Also sets the atom density for the home zone when \p zone_start=0.
8474 * For this \p numMovedChargeGroupsInHomeZone needs to be passed to tell
8475 * how many charge groups will move but are still part of the current range.
8476 * \todo When converting domdec to use proper classes, all these variables
8477 * should be private and a method should return the correct count
8478 * depending on an internal state.
8480 * \param[in,out] dd The domain decomposition struct
8481 * \param[in] box The box
8482 * \param[in] ddbox The domain decomposition box struct
8483 * \param[in] zone_start The start of the zone range to set sizes for
8484 * \param[in] zone_end The end of the zone range to set sizes for
8485 * \param[in] numMovedChargeGroupsInHomeZone The number of charge groups in the home zone that should moved but are still present in dd->comm->zones.cg_range
8487 static void set_zones_size(gmx_domdec_t *dd,
8488 matrix box, const gmx_ddbox_t *ddbox,
8489 int zone_start, int zone_end,
8490 int numMovedChargeGroupsInHomeZone)
8492 gmx_domdec_comm_t *comm;
8493 gmx_domdec_zones_t *zones;
8494 gmx_bool bDistMB;
8495 int z, zi, d, dim;
8496 real rcs, rcmbs;
8497 int i, j;
8498 real vol;
8500 comm = dd->comm;
8502 zones = &comm->zones;
8504 /* Do we need to determine extra distances for multi-body bondeds? */
8505 bDistMB = (comm->bInterCGMultiBody && isDlbOn(dd->comm) && dd->ndim > 1);
8507 for (z = zone_start; z < zone_end; z++)
8509 /* Copy cell limits to zone limits.
8510 * Valid for non-DD dims and non-shifted dims.
8512 copy_rvec(comm->cell_x0, zones->size[z].x0);
8513 copy_rvec(comm->cell_x1, zones->size[z].x1);
8516 for (d = 0; d < dd->ndim; d++)
8518 dim = dd->dim[d];
8520 for (z = 0; z < zones->n; z++)
8522 /* With a staggered grid we have different sizes
8523 * for non-shifted dimensions.
8525 if (isDlbOn(dd->comm) && zones->shift[z][dim] == 0)
8527 if (d == 1)
8529 zones->size[z].x0[dim] = comm->zone_d1[zones->shift[z][dd->dim[d-1]]].min0;
8530 zones->size[z].x1[dim] = comm->zone_d1[zones->shift[z][dd->dim[d-1]]].max1;
8532 else if (d == 2)
8534 zones->size[z].x0[dim] = comm->zone_d2[zones->shift[z][dd->dim[d-2]]][zones->shift[z][dd->dim[d-1]]].min0;
8535 zones->size[z].x1[dim] = comm->zone_d2[zones->shift[z][dd->dim[d-2]]][zones->shift[z][dd->dim[d-1]]].max1;
8540 rcs = comm->cutoff;
8541 rcmbs = comm->cutoff_mbody;
8542 if (ddbox->tric_dir[dim])
8544 rcs /= ddbox->skew_fac[dim];
8545 rcmbs /= ddbox->skew_fac[dim];
8548 /* Set the lower limit for the shifted zone dimensions */
8549 for (z = zone_start; z < zone_end; z++)
8551 if (zones->shift[z][dim] > 0)
8553 dim = dd->dim[d];
8554 if (!isDlbOn(dd->comm) || d == 0)
8556 zones->size[z].x0[dim] = comm->cell_x1[dim];
8557 zones->size[z].x1[dim] = comm->cell_x1[dim] + rcs;
8559 else
8561 /* Here we take the lower limit of the zone from
8562 * the lowest domain of the zone below.
8564 if (z < 4)
8566 zones->size[z].x0[dim] =
8567 comm->zone_d1[zones->shift[z][dd->dim[d-1]]].min1;
8569 else
8571 if (d == 1)
8573 zones->size[z].x0[dim] =
8574 zones->size[zone_perm[2][z-4]].x0[dim];
8576 else
8578 zones->size[z].x0[dim] =
8579 comm->zone_d2[zones->shift[z][dd->dim[d-2]]][zones->shift[z][dd->dim[d-1]]].min1;
8582 /* A temporary limit, is updated below */
8583 zones->size[z].x1[dim] = zones->size[z].x0[dim];
8585 if (bDistMB)
8587 for (zi = 0; zi < zones->nizone; zi++)
8589 if (zones->shift[zi][dim] == 0)
8591 /* This takes the whole zone into account.
8592 * With multiple pulses this will lead
8593 * to a larger zone then strictly necessary.
8595 zones->size[z].x1[dim] = std::max(zones->size[z].x1[dim],
8596 zones->size[zi].x1[dim]+rcmbs);
8604 /* Loop over the i-zones to set the upper limit of each
8605 * j-zone they see.
8607 for (zi = 0; zi < zones->nizone; zi++)
8609 if (zones->shift[zi][dim] == 0)
8611 for (z = zones->izone[zi].j0; z < zones->izone[zi].j1; z++)
8613 if (zones->shift[z][dim] > 0)
8615 zones->size[z].x1[dim] = std::max(zones->size[z].x1[dim],
8616 zones->size[zi].x1[dim]+rcs);
8623 for (z = zone_start; z < zone_end; z++)
8625 /* Initialization only required to keep the compiler happy */
8626 rvec corner_min = {0, 0, 0}, corner_max = {0, 0, 0}, corner;
8627 int nc, c;
8629 /* To determine the bounding box for a zone we need to find
8630 * the extreme corners of 4, 2 or 1 corners.
8632 nc = 1 << (ddbox->nboundeddim - 1);
8634 for (c = 0; c < nc; c++)
8636 /* Set up a zone corner at x=0, ignoring trilinic couplings */
8637 corner[XX] = 0;
8638 if ((c & 1) == 0)
8640 corner[YY] = zones->size[z].x0[YY];
8642 else
8644 corner[YY] = zones->size[z].x1[YY];
8646 if ((c & 2) == 0)
8648 corner[ZZ] = zones->size[z].x0[ZZ];
8650 else
8652 corner[ZZ] = zones->size[z].x1[ZZ];
8654 if (dd->ndim == 1 && dd->dim[0] < ZZ && ZZ < dd->npbcdim &&
8655 box[ZZ][1 - dd->dim[0]] != 0)
8657 /* With 1D domain decomposition the cg's are not in
8658 * the triclinic box, but triclinic x-y and rectangular y/x-z.
8659 * Shift the corner of the z-vector back to along the box
8660 * vector of dimension d, so it will later end up at 0 along d.
8661 * This can affect the location of this corner along dd->dim[0]
8662 * through the matrix operation below if box[d][dd->dim[0]]!=0.
8664 int d = 1 - dd->dim[0];
8666 corner[d] -= corner[ZZ]*box[ZZ][d]/box[ZZ][ZZ];
8668 /* Apply the triclinic couplings */
8669 assert(ddbox->npbcdim <= DIM);
8670 for (i = YY; i < ddbox->npbcdim; i++)
8672 for (j = XX; j < i; j++)
8674 corner[j] += corner[i]*box[i][j]/box[i][i];
8677 if (c == 0)
8679 copy_rvec(corner, corner_min);
8680 copy_rvec(corner, corner_max);
8682 else
8684 for (i = 0; i < DIM; i++)
8686 corner_min[i] = std::min(corner_min[i], corner[i]);
8687 corner_max[i] = std::max(corner_max[i], corner[i]);
8691 /* Copy the extreme cornes without offset along x */
8692 for (i = 0; i < DIM; i++)
8694 zones->size[z].bb_x0[i] = corner_min[i];
8695 zones->size[z].bb_x1[i] = corner_max[i];
8697 /* Add the offset along x */
8698 zones->size[z].bb_x0[XX] += zones->size[z].x0[XX];
8699 zones->size[z].bb_x1[XX] += zones->size[z].x1[XX];
8702 if (zone_start == 0)
8704 vol = 1;
8705 for (dim = 0; dim < DIM; dim++)
8707 vol *= zones->size[0].x1[dim] - zones->size[0].x0[dim];
8709 zones->dens_zone0 = (zones->cg_range[1] - zones->cg_range[0] - numMovedChargeGroupsInHomeZone)/vol;
8712 if (debug)
8714 for (z = zone_start; z < zone_end; z++)
8716 fprintf(debug, "zone %d %6.3f - %6.3f %6.3f - %6.3f %6.3f - %6.3f\n",
8718 zones->size[z].x0[XX], zones->size[z].x1[XX],
8719 zones->size[z].x0[YY], zones->size[z].x1[YY],
8720 zones->size[z].x0[ZZ], zones->size[z].x1[ZZ]);
8721 fprintf(debug, "zone %d bb %6.3f - %6.3f %6.3f - %6.3f %6.3f - %6.3f\n",
8723 zones->size[z].bb_x0[XX], zones->size[z].bb_x1[XX],
8724 zones->size[z].bb_x0[YY], zones->size[z].bb_x1[YY],
8725 zones->size[z].bb_x0[ZZ], zones->size[z].bb_x1[ZZ]);
8730 static int comp_cgsort(const void *a, const void *b)
8732 int comp;
8734 gmx_cgsort_t *cga, *cgb;
8735 cga = (gmx_cgsort_t *)a;
8736 cgb = (gmx_cgsort_t *)b;
8738 comp = cga->nsc - cgb->nsc;
8739 if (comp == 0)
8741 comp = cga->ind_gl - cgb->ind_gl;
8744 return comp;
8747 static void order_int_cg(int n, const gmx_cgsort_t *sort,
8748 int *a, int *buf)
8750 int i;
8752 /* Order the data */
8753 for (i = 0; i < n; i++)
8755 buf[i] = a[sort[i].ind];
8758 /* Copy back to the original array */
8759 for (i = 0; i < n; i++)
8761 a[i] = buf[i];
8765 static void order_vec_cg(int n, const gmx_cgsort_t *sort,
8766 rvec *v, rvec *buf)
8768 int i;
8770 /* Order the data */
8771 for (i = 0; i < n; i++)
8773 copy_rvec(v[sort[i].ind], buf[i]);
8776 /* Copy back to the original array */
8777 for (i = 0; i < n; i++)
8779 copy_rvec(buf[i], v[i]);
8783 static void order_vec_atom(int ncg, const int *cgindex, const gmx_cgsort_t *sort,
8784 rvec *v, rvec *buf)
8786 int a, atot, cg, cg0, cg1, i;
8788 if (cgindex == nullptr)
8790 /* Avoid the useless loop of the atoms within a cg */
8791 order_vec_cg(ncg, sort, v, buf);
8793 return;
8796 /* Order the data */
8797 a = 0;
8798 for (cg = 0; cg < ncg; cg++)
8800 cg0 = cgindex[sort[cg].ind];
8801 cg1 = cgindex[sort[cg].ind+1];
8802 for (i = cg0; i < cg1; i++)
8804 copy_rvec(v[i], buf[a]);
8805 a++;
8808 atot = a;
8810 /* Copy back to the original array */
8811 for (a = 0; a < atot; a++)
8813 copy_rvec(buf[a], v[a]);
8817 static void ordered_sort(int nsort2, gmx_cgsort_t *sort2,
8818 int nsort_new, gmx_cgsort_t *sort_new,
8819 gmx_cgsort_t *sort1)
8821 int i1, i2, i_new;
8823 /* The new indices are not very ordered, so we qsort them */
8824 gmx_qsort_threadsafe(sort_new, nsort_new, sizeof(sort_new[0]), comp_cgsort);
8826 /* sort2 is already ordered, so now we can merge the two arrays */
8827 i1 = 0;
8828 i2 = 0;
8829 i_new = 0;
8830 while (i2 < nsort2 || i_new < nsort_new)
8832 if (i2 == nsort2)
8834 sort1[i1++] = sort_new[i_new++];
8836 else if (i_new == nsort_new)
8838 sort1[i1++] = sort2[i2++];
8840 else if (sort2[i2].nsc < sort_new[i_new].nsc ||
8841 (sort2[i2].nsc == sort_new[i_new].nsc &&
8842 sort2[i2].ind_gl < sort_new[i_new].ind_gl))
8844 sort1[i1++] = sort2[i2++];
8846 else
8848 sort1[i1++] = sort_new[i_new++];
8853 static int dd_sort_order(gmx_domdec_t *dd, t_forcerec *fr, int ncg_home_old)
8855 gmx_domdec_sort_t *sort;
8856 gmx_cgsort_t *cgsort, *sort_i;
8857 int ncg_new, nsort2, nsort_new, i, *a, moved;
8859 sort = dd->comm->sort;
8861 a = fr->ns->grid->cell_index;
8863 moved = NSGRID_SIGNAL_MOVED_FAC*fr->ns->grid->ncells;
8865 if (ncg_home_old >= 0)
8867 /* The charge groups that remained in the same ns grid cell
8868 * are completely ordered. So we can sort efficiently by sorting
8869 * the charge groups that did move into the stationary list.
8871 ncg_new = 0;
8872 nsort2 = 0;
8873 nsort_new = 0;
8874 for (i = 0; i < dd->ncg_home; i++)
8876 /* Check if this cg did not move to another node */
8877 if (a[i] < moved)
8879 if (i >= ncg_home_old || a[i] != sort->sort[i].nsc)
8881 /* This cg is new on this node or moved ns grid cell */
8882 if (nsort_new >= sort->sort_new_nalloc)
8884 sort->sort_new_nalloc = over_alloc_dd(nsort_new+1);
8885 srenew(sort->sort_new, sort->sort_new_nalloc);
8887 sort_i = &(sort->sort_new[nsort_new++]);
8889 else
8891 /* This cg did not move */
8892 sort_i = &(sort->sort2[nsort2++]);
8894 /* Sort on the ns grid cell indices
8895 * and the global topology index.
8896 * index_gl is irrelevant with cell ns,
8897 * but we set it here anyhow to avoid a conditional.
8899 sort_i->nsc = a[i];
8900 sort_i->ind_gl = dd->index_gl[i];
8901 sort_i->ind = i;
8902 ncg_new++;
8905 if (debug)
8907 fprintf(debug, "ordered sort cgs: stationary %d moved %d\n",
8908 nsort2, nsort_new);
8910 /* Sort efficiently */
8911 ordered_sort(nsort2, sort->sort2, nsort_new, sort->sort_new,
8912 sort->sort);
8914 else
8916 cgsort = sort->sort;
8917 ncg_new = 0;
8918 for (i = 0; i < dd->ncg_home; i++)
8920 /* Sort on the ns grid cell indices
8921 * and the global topology index
8923 cgsort[i].nsc = a[i];
8924 cgsort[i].ind_gl = dd->index_gl[i];
8925 cgsort[i].ind = i;
8926 if (cgsort[i].nsc < moved)
8928 ncg_new++;
8931 if (debug)
8933 fprintf(debug, "qsort cgs: %d new home %d\n", dd->ncg_home, ncg_new);
8935 /* Determine the order of the charge groups using qsort */
8936 gmx_qsort_threadsafe(cgsort, dd->ncg_home, sizeof(cgsort[0]), comp_cgsort);
8939 return ncg_new;
8942 static int dd_sort_order_nbnxn(gmx_domdec_t *dd, t_forcerec *fr)
8944 gmx_cgsort_t *sort;
8945 int ncg_new, i, na;
8946 const int *a;
8948 sort = dd->comm->sort->sort;
8950 nbnxn_get_atomorder(fr->nbv->nbs, &a, &na);
8952 ncg_new = 0;
8953 for (i = 0; i < na; i++)
8955 if (a[i] >= 0)
8957 sort[ncg_new].ind = a[i];
8958 ncg_new++;
8962 return ncg_new;
8965 static void dd_sort_state(gmx_domdec_t *dd, rvec *cgcm, t_forcerec *fr, t_state *state,
8966 int ncg_home_old)
8968 gmx_domdec_sort_t *sort;
8969 gmx_cgsort_t *cgsort;
8970 int *cgindex;
8971 int ncg_new, i, *ibuf, cgsize;
8972 rvec *vbuf;
8974 sort = dd->comm->sort;
8976 if (dd->ncg_home > sort->sort_nalloc)
8978 sort->sort_nalloc = over_alloc_dd(dd->ncg_home);
8979 srenew(sort->sort, sort->sort_nalloc);
8980 srenew(sort->sort2, sort->sort_nalloc);
8982 cgsort = sort->sort;
8984 switch (fr->cutoff_scheme)
8986 case ecutsGROUP:
8987 ncg_new = dd_sort_order(dd, fr, ncg_home_old);
8988 break;
8989 case ecutsVERLET:
8990 ncg_new = dd_sort_order_nbnxn(dd, fr);
8991 break;
8992 default:
8993 gmx_incons("unimplemented");
8994 ncg_new = 0;
8997 /* We alloc with the old size, since cgindex is still old */
8998 vec_rvec_check_alloc(&dd->comm->vbuf, dd->cgindex[dd->ncg_home]);
8999 vbuf = dd->comm->vbuf.v;
9001 if (dd->comm->bCGs)
9003 cgindex = dd->cgindex;
9005 else
9007 cgindex = nullptr;
9010 /* Remove the charge groups which are no longer at home here */
9011 dd->ncg_home = ncg_new;
9012 if (debug)
9014 fprintf(debug, "Set the new home charge group count to %d\n",
9015 dd->ncg_home);
9018 /* Reorder the state */
9019 if (state->flags & (1 << estX))
9021 order_vec_atom(dd->ncg_home, cgindex, cgsort, as_rvec_array(state->x.data()), vbuf);
9023 if (state->flags & (1 << estV))
9025 order_vec_atom(dd->ncg_home, cgindex, cgsort, as_rvec_array(state->v.data()), vbuf);
9027 if (state->flags & (1 << estCGP))
9029 order_vec_atom(dd->ncg_home, cgindex, cgsort, as_rvec_array(state->cg_p.data()), vbuf);
9032 if (fr->cutoff_scheme == ecutsGROUP)
9034 /* Reorder cgcm */
9035 order_vec_cg(dd->ncg_home, cgsort, cgcm, vbuf);
9038 if (dd->ncg_home+1 > sort->ibuf_nalloc)
9040 sort->ibuf_nalloc = over_alloc_dd(dd->ncg_home+1);
9041 srenew(sort->ibuf, sort->ibuf_nalloc);
9043 ibuf = sort->ibuf;
9044 /* Reorder the global cg index */
9045 order_int_cg(dd->ncg_home, cgsort, dd->index_gl, ibuf);
9046 /* Reorder the cginfo */
9047 order_int_cg(dd->ncg_home, cgsort, fr->cginfo, ibuf);
9048 /* Rebuild the local cg index */
9049 if (dd->comm->bCGs)
9051 ibuf[0] = 0;
9052 for (i = 0; i < dd->ncg_home; i++)
9054 cgsize = dd->cgindex[cgsort[i].ind+1] - dd->cgindex[cgsort[i].ind];
9055 ibuf[i+1] = ibuf[i] + cgsize;
9057 for (i = 0; i < dd->ncg_home+1; i++)
9059 dd->cgindex[i] = ibuf[i];
9062 else
9064 for (i = 0; i < dd->ncg_home+1; i++)
9066 dd->cgindex[i] = i;
9069 /* Set the home atom number */
9070 dd->nat_home = dd->cgindex[dd->ncg_home];
9072 if (fr->cutoff_scheme == ecutsVERLET)
9074 /* The atoms are now exactly in grid order, update the grid order */
9075 nbnxn_set_atomorder(fr->nbv->nbs);
9077 else
9079 /* Copy the sorted ns cell indices back to the ns grid struct */
9080 for (i = 0; i < dd->ncg_home; i++)
9082 fr->ns->grid->cell_index[i] = cgsort[i].nsc;
9084 fr->ns->grid->nr = dd->ncg_home;
9088 static void add_dd_statistics(gmx_domdec_t *dd)
9090 gmx_domdec_comm_t *comm;
9091 int ddnat;
9093 comm = dd->comm;
9095 for (ddnat = ddnatZONE; ddnat < ddnatNR; ddnat++)
9097 comm->sum_nat[ddnat-ddnatZONE] +=
9098 comm->nat[ddnat] - comm->nat[ddnat-1];
9100 comm->ndecomp++;
9103 void reset_dd_statistics_counters(gmx_domdec_t *dd)
9105 gmx_domdec_comm_t *comm;
9106 int ddnat;
9108 comm = dd->comm;
9110 /* Reset all the statistics and counters for total run counting */
9111 for (ddnat = ddnatZONE; ddnat < ddnatNR; ddnat++)
9113 comm->sum_nat[ddnat-ddnatZONE] = 0;
9115 comm->ndecomp = 0;
9116 comm->nload = 0;
9117 comm->load_step = 0;
9118 comm->load_sum = 0;
9119 comm->load_max = 0;
9120 clear_ivec(comm->load_lim);
9121 comm->load_mdf = 0;
9122 comm->load_pme = 0;
9125 void print_dd_statistics(const t_commrec *cr, const t_inputrec *ir, FILE *fplog)
9127 gmx_domdec_comm_t *comm;
9128 int ddnat;
9129 double av;
9131 comm = cr->dd->comm;
9133 gmx_sumd(ddnatNR-ddnatZONE, comm->sum_nat, cr);
9135 if (fplog == nullptr)
9137 return;
9140 fprintf(fplog, "\n D O M A I N D E C O M P O S I T I O N S T A T I S T I C S\n\n");
9142 for (ddnat = ddnatZONE; ddnat < ddnatNR; ddnat++)
9144 av = comm->sum_nat[ddnat-ddnatZONE]/comm->ndecomp;
9145 switch (ddnat)
9147 case ddnatZONE:
9148 fprintf(fplog,
9149 " av. #atoms communicated per step for force: %d x %.1f\n",
9150 2, av);
9151 break;
9152 case ddnatVSITE:
9153 if (cr->dd->vsite_comm)
9155 fprintf(fplog,
9156 " av. #atoms communicated per step for vsites: %d x %.1f\n",
9157 (EEL_PME(ir->coulombtype) || ir->coulombtype == eelEWALD) ? 3 : 2,
9158 av);
9160 break;
9161 case ddnatCON:
9162 if (cr->dd->constraint_comm)
9164 fprintf(fplog,
9165 " av. #atoms communicated per step for LINCS: %d x %.1f\n",
9166 1 + ir->nLincsIter, av);
9168 break;
9169 default:
9170 gmx_incons(" Unknown type for DD statistics");
9173 fprintf(fplog, "\n");
9175 if (comm->bRecordLoad && EI_DYNAMICS(ir->eI))
9177 print_dd_load_av(fplog, cr->dd);
9181 void dd_partition_system(FILE *fplog,
9182 gmx_int64_t step,
9183 const t_commrec *cr,
9184 gmx_bool bMasterState,
9185 int nstglobalcomm,
9186 t_state *state_global,
9187 const gmx_mtop_t *top_global,
9188 const t_inputrec *ir,
9189 t_state *state_local,
9190 PaddedRVecVector *f,
9191 gmx::MDAtoms *mdAtoms,
9192 gmx_localtop_t *top_local,
9193 t_forcerec *fr,
9194 gmx_vsite_t *vsite,
9195 gmx::Constraints *constr,
9196 t_nrnb *nrnb,
9197 gmx_wallcycle *wcycle,
9198 gmx_bool bVerbose)
9200 gmx_domdec_t *dd;
9201 gmx_domdec_comm_t *comm;
9202 gmx_ddbox_t ddbox = {0};
9203 t_block *cgs_gl;
9204 gmx_int64_t step_pcoupl;
9205 rvec cell_ns_x0, cell_ns_x1;
9206 int i, n, ncgindex_set, ncg_home_old = -1, ncg_moved, nat_f_novirsum;
9207 gmx_bool bBoxChanged, bNStGlobalComm, bDoDLB, bCheckWhetherToTurnDlbOn, bLogLoad;
9208 gmx_bool bRedist, bSortCG, bResortAll;
9209 ivec ncells_old = {0, 0, 0}, ncells_new = {0, 0, 0}, np;
9210 real grid_density;
9211 char sbuf[22];
9213 wallcycle_start(wcycle, ewcDOMDEC);
9215 dd = cr->dd;
9216 comm = dd->comm;
9218 bBoxChanged = (bMasterState || inputrecDeform(ir));
9219 if (ir->epc != epcNO)
9221 /* With nstpcouple > 1 pressure coupling happens.
9222 * one step after calculating the pressure.
9223 * Box scaling happens at the end of the MD step,
9224 * after the DD partitioning.
9225 * We therefore have to do DLB in the first partitioning
9226 * after an MD step where P-coupling occurred.
9227 * We need to determine the last step in which p-coupling occurred.
9228 * MRS -- need to validate this for vv?
9230 n = ir->nstpcouple;
9231 if (n == 1)
9233 step_pcoupl = step - 1;
9235 else
9237 step_pcoupl = ((step - 1)/n)*n + 1;
9239 if (step_pcoupl >= comm->partition_step)
9241 bBoxChanged = TRUE;
9245 bNStGlobalComm = (step % nstglobalcomm == 0);
9247 if (!isDlbOn(comm))
9249 bDoDLB = FALSE;
9251 else
9253 /* Should we do dynamic load balacing this step?
9254 * Since it requires (possibly expensive) global communication,
9255 * we might want to do DLB less frequently.
9257 if (bBoxChanged || ir->epc != epcNO)
9259 bDoDLB = bBoxChanged;
9261 else
9263 bDoDLB = bNStGlobalComm;
9267 /* Check if we have recorded loads on the nodes */
9268 if (comm->bRecordLoad && dd_load_count(comm) > 0)
9270 bCheckWhetherToTurnDlbOn = dd_dlb_get_should_check_whether_to_turn_dlb_on(dd);
9272 /* Print load every nstlog, first and last step to the log file */
9273 bLogLoad = ((ir->nstlog > 0 && step % ir->nstlog == 0) ||
9274 comm->n_load_collect == 0 ||
9275 (ir->nsteps >= 0 &&
9276 (step + ir->nstlist > ir->init_step + ir->nsteps)));
9278 /* Avoid extra communication due to verbose screen output
9279 * when nstglobalcomm is set.
9281 if (bDoDLB || bLogLoad || bCheckWhetherToTurnDlbOn ||
9282 (bVerbose && (ir->nstlist == 0 || nstglobalcomm <= ir->nstlist)))
9284 get_load_distribution(dd, wcycle);
9285 if (DDMASTER(dd))
9287 if (bLogLoad)
9289 dd_print_load(fplog, dd, step-1);
9291 if (bVerbose)
9293 dd_print_load_verbose(dd);
9296 comm->n_load_collect++;
9298 if (isDlbOn(comm))
9300 if (DDMASTER(dd))
9302 /* Add the measured cycles to the running average */
9303 const float averageFactor = 0.1f;
9304 comm->cyclesPerStepDlbExpAverage =
9305 (1 - averageFactor)*comm->cyclesPerStepDlbExpAverage +
9306 averageFactor*comm->cycl[ddCyclStep]/comm->cycl_n[ddCyclStep];
9308 if (comm->dlbState == edlbsOnCanTurnOff &&
9309 dd->comm->n_load_have % c_checkTurnDlbOffInterval == c_checkTurnDlbOffInterval - 1)
9311 gmx_bool turnOffDlb;
9312 if (DDMASTER(dd))
9314 /* If the running averaged cycles with DLB are more
9315 * than before we turned on DLB, turn off DLB.
9316 * We will again run and check the cycles without DLB
9317 * and we can then decide if to turn off DLB forever.
9319 turnOffDlb = (comm->cyclesPerStepDlbExpAverage >
9320 comm->cyclesPerStepBeforeDLB);
9322 dd_bcast(dd, sizeof(turnOffDlb), &turnOffDlb);
9323 if (turnOffDlb)
9325 /* To turn off DLB, we need to redistribute the atoms */
9326 dd_collect_state(dd, state_local, state_global);
9327 bMasterState = TRUE;
9328 turn_off_dlb(fplog, cr, step);
9332 else if (bCheckWhetherToTurnDlbOn)
9334 gmx_bool turnOffDlbForever = FALSE;
9335 gmx_bool turnOnDlb = FALSE;
9337 /* Since the timings are node dependent, the master decides */
9338 if (DDMASTER(dd))
9340 /* If we recently turned off DLB, we want to check if
9341 * performance is better without DLB. We want to do this
9342 * ASAP to minimize the chance that external factors
9343 * slowed down the DLB step are gone here and we
9344 * incorrectly conclude that DLB was causing the slowdown.
9345 * So we measure one nstlist block, no running average.
9347 if (comm->haveTurnedOffDlb &&
9348 comm->cycl[ddCyclStep]/comm->cycl_n[ddCyclStep] <
9349 comm->cyclesPerStepDlbExpAverage)
9351 /* After turning off DLB we ran nstlist steps in fewer
9352 * cycles than with DLB. This likely means that DLB
9353 * in not benefical, but this could be due to a one
9354 * time unlucky fluctuation, so we require two such
9355 * observations in close succession to turn off DLB
9356 * forever.
9358 if (comm->dlbSlowerPartitioningCount > 0 &&
9359 dd->ddp_count < comm->dlbSlowerPartitioningCount + 10*c_checkTurnDlbOnInterval)
9361 turnOffDlbForever = TRUE;
9363 comm->haveTurnedOffDlb = false;
9364 /* Register when we last measured DLB slowdown */
9365 comm->dlbSlowerPartitioningCount = dd->ddp_count;
9367 else
9369 /* Here we check if the max PME rank load is more than 0.98
9370 * the max PP force load. If so, PP DLB will not help,
9371 * since we are (almost) limited by PME. Furthermore,
9372 * DLB will cause a significant extra x/f redistribution
9373 * cost on the PME ranks, which will then surely result
9374 * in lower total performance.
9376 if (cr->npmenodes > 0 &&
9377 dd_pme_f_ratio(dd) > 1 - DD_PERF_LOSS_DLB_ON)
9379 turnOnDlb = FALSE;
9381 else
9383 turnOnDlb = (dd_force_imb_perf_loss(dd) >= DD_PERF_LOSS_DLB_ON);
9387 struct
9389 gmx_bool turnOffDlbForever;
9390 gmx_bool turnOnDlb;
9392 bools {
9393 turnOffDlbForever, turnOnDlb
9395 dd_bcast(dd, sizeof(bools), &bools);
9396 if (bools.turnOffDlbForever)
9398 turn_off_dlb_forever(fplog, cr, step);
9400 else if (bools.turnOnDlb)
9402 turn_on_dlb(fplog, cr, step);
9403 bDoDLB = TRUE;
9407 comm->n_load_have++;
9410 cgs_gl = &comm->cgs_gl;
9412 bRedist = FALSE;
9413 if (bMasterState)
9415 /* Clear the old state */
9416 clear_dd_indices(dd, 0, 0);
9417 ncgindex_set = 0;
9419 rvec *xGlobal = (SIMMASTER(cr) ? as_rvec_array(state_global->x.data()) : nullptr);
9421 set_ddbox(dd, bMasterState, ir,
9422 SIMMASTER(cr) ? state_global->box : nullptr,
9423 TRUE, cgs_gl, xGlobal,
9424 &ddbox);
9426 get_cg_distribution(fplog, dd, cgs_gl,
9427 SIMMASTER(cr) ? state_global->box : nullptr,
9428 &ddbox, xGlobal);
9430 dd_distribute_state(dd, cgs_gl,
9431 state_global, state_local, f);
9433 dd_make_local_cgs(dd, &top_local->cgs);
9435 /* Ensure that we have space for the new distribution */
9436 dd_check_alloc_ncg(fr, state_local, f, dd->ncg_home);
9438 if (fr->cutoff_scheme == ecutsGROUP)
9440 calc_cgcm(fplog, 0, dd->ncg_home,
9441 &top_local->cgs, as_rvec_array(state_local->x.data()), fr->cg_cm);
9444 inc_nrnb(nrnb, eNR_CGCM, dd->nat_home);
9446 dd_set_cginfo(dd->index_gl, 0, dd->ncg_home, fr, comm->bLocalCG);
9448 else if (state_local->ddp_count != dd->ddp_count)
9450 if (state_local->ddp_count > dd->ddp_count)
9452 gmx_fatal(FARGS, "Internal inconsistency state_local->ddp_count (%d) > dd->ddp_count (%d)", state_local->ddp_count, dd->ddp_count);
9455 if (state_local->ddp_count_cg_gl != state_local->ddp_count)
9457 gmx_fatal(FARGS, "Internal inconsistency state_local->ddp_count_cg_gl (%d) != state_local->ddp_count (%d)", state_local->ddp_count_cg_gl, state_local->ddp_count);
9460 /* Clear the old state */
9461 clear_dd_indices(dd, 0, 0);
9463 /* Build the new indices */
9464 rebuild_cgindex(dd, cgs_gl->index, state_local);
9465 make_dd_indices(dd, cgs_gl->index, 0);
9466 ncgindex_set = dd->ncg_home;
9468 if (fr->cutoff_scheme == ecutsGROUP)
9470 /* Redetermine the cg COMs */
9471 calc_cgcm(fplog, 0, dd->ncg_home,
9472 &top_local->cgs, as_rvec_array(state_local->x.data()), fr->cg_cm);
9475 inc_nrnb(nrnb, eNR_CGCM, dd->nat_home);
9477 dd_set_cginfo(dd->index_gl, 0, dd->ncg_home, fr, comm->bLocalCG);
9479 set_ddbox(dd, bMasterState, ir, state_local->box,
9480 TRUE, &top_local->cgs, as_rvec_array(state_local->x.data()), &ddbox);
9482 bRedist = isDlbOn(comm);
9484 else
9486 /* We have the full state, only redistribute the cgs */
9488 /* Clear the non-home indices */
9489 clear_dd_indices(dd, dd->ncg_home, dd->nat_home);
9490 ncgindex_set = 0;
9492 /* Avoid global communication for dim's without pbc and -gcom */
9493 if (!bNStGlobalComm)
9495 copy_rvec(comm->box0, ddbox.box0 );
9496 copy_rvec(comm->box_size, ddbox.box_size);
9498 set_ddbox(dd, bMasterState, ir, state_local->box,
9499 bNStGlobalComm, &top_local->cgs, as_rvec_array(state_local->x.data()), &ddbox);
9501 bBoxChanged = TRUE;
9502 bRedist = TRUE;
9504 /* For dim's without pbc and -gcom */
9505 copy_rvec(ddbox.box0, comm->box0 );
9506 copy_rvec(ddbox.box_size, comm->box_size);
9508 set_dd_cell_sizes(dd, &ddbox, dynamic_dd_box(&ddbox, ir), bMasterState, bDoDLB,
9509 step, wcycle);
9511 if (comm->nstDDDumpGrid > 0 && step % comm->nstDDDumpGrid == 0)
9513 write_dd_grid_pdb("dd_grid", step, dd, state_local->box, &ddbox);
9516 /* Check if we should sort the charge groups */
9517 bSortCG = (bMasterState || bRedist);
9519 ncg_home_old = dd->ncg_home;
9521 /* When repartitioning we mark charge groups that will move to neighboring
9522 * DD cells, but we do not move them right away for performance reasons.
9523 * Thus we need to keep track of how many charge groups will move for
9524 * obtaining correct local charge group / atom counts.
9526 ncg_moved = 0;
9527 if (bRedist)
9529 wallcycle_sub_start(wcycle, ewcsDD_REDIST);
9531 dd_redistribute_cg(fplog, step, dd, ddbox.tric_dir,
9532 state_local, f, fr,
9533 !bSortCG, nrnb, &ncgindex_set, &ncg_moved);
9535 wallcycle_sub_stop(wcycle, ewcsDD_REDIST);
9538 get_nsgrid_boundaries(ddbox.nboundeddim, state_local->box,
9539 dd, &ddbox,
9540 &comm->cell_x0, &comm->cell_x1,
9541 dd->ncg_home, fr->cg_cm,
9542 cell_ns_x0, cell_ns_x1, &grid_density);
9544 if (bBoxChanged)
9546 comm_dd_ns_cell_sizes(dd, &ddbox, cell_ns_x0, cell_ns_x1, step);
9549 switch (fr->cutoff_scheme)
9551 case ecutsGROUP:
9552 copy_ivec(fr->ns->grid->n, ncells_old);
9553 grid_first(fplog, fr->ns->grid, dd, &ddbox,
9554 state_local->box, cell_ns_x0, cell_ns_x1,
9555 fr->rlist, grid_density);
9556 break;
9557 case ecutsVERLET:
9558 nbnxn_get_ncells(fr->nbv->nbs, &ncells_old[XX], &ncells_old[YY]);
9559 break;
9560 default:
9561 gmx_incons("unimplemented");
9563 /* We need to store tric_dir for dd_get_ns_ranges called from ns.c */
9564 copy_ivec(ddbox.tric_dir, comm->tric_dir);
9566 if (bSortCG)
9568 wallcycle_sub_start(wcycle, ewcsDD_GRID);
9570 /* Sort the state on charge group position.
9571 * This enables exact restarts from this step.
9572 * It also improves performance by about 15% with larger numbers
9573 * of atoms per node.
9576 /* Fill the ns grid with the home cell,
9577 * so we can sort with the indices.
9579 set_zones_ncg_home(dd);
9581 switch (fr->cutoff_scheme)
9583 case ecutsVERLET:
9584 set_zones_size(dd, state_local->box, &ddbox, 0, 1, ncg_moved);
9586 nbnxn_put_on_grid(fr->nbv->nbs, fr->ePBC, state_local->box,
9588 comm->zones.size[0].bb_x0,
9589 comm->zones.size[0].bb_x1,
9590 0, dd->ncg_home,
9591 comm->zones.dens_zone0,
9592 fr->cginfo,
9593 as_rvec_array(state_local->x.data()),
9594 ncg_moved, bRedist ? comm->moved : nullptr,
9595 fr->nbv->grp[eintLocal].kernel_type,
9596 fr->nbv->nbat);
9598 nbnxn_get_ncells(fr->nbv->nbs, &ncells_new[XX], &ncells_new[YY]);
9599 break;
9600 case ecutsGROUP:
9601 fill_grid(&comm->zones, fr->ns->grid, dd->ncg_home,
9602 0, dd->ncg_home, fr->cg_cm);
9604 copy_ivec(fr->ns->grid->n, ncells_new);
9605 break;
9606 default:
9607 gmx_incons("unimplemented");
9610 bResortAll = bMasterState;
9612 /* Check if we can user the old order and ns grid cell indices
9613 * of the charge groups to sort the charge groups efficiently.
9615 if (ncells_new[XX] != ncells_old[XX] ||
9616 ncells_new[YY] != ncells_old[YY] ||
9617 ncells_new[ZZ] != ncells_old[ZZ])
9619 bResortAll = TRUE;
9622 if (debug)
9624 fprintf(debug, "Step %s, sorting the %d home charge groups\n",
9625 gmx_step_str(step, sbuf), dd->ncg_home);
9627 dd_sort_state(dd, fr->cg_cm, fr, state_local,
9628 bResortAll ? -1 : ncg_home_old);
9630 /* After sorting and compacting we set the correct size */
9631 dd_resize_state(state_local, f, dd->nat_home);
9633 /* Rebuild all the indices */
9634 ga2la_clear(dd->ga2la);
9635 ncgindex_set = 0;
9637 wallcycle_sub_stop(wcycle, ewcsDD_GRID);
9640 wallcycle_sub_start(wcycle, ewcsDD_SETUPCOMM);
9642 /* Setup up the communication and communicate the coordinates */
9643 setup_dd_communication(dd, state_local->box, &ddbox, fr, state_local, f);
9645 /* Set the indices */
9646 make_dd_indices(dd, cgs_gl->index, ncgindex_set);
9648 /* Set the charge group boundaries for neighbor searching */
9649 set_cg_boundaries(&comm->zones);
9651 if (fr->cutoff_scheme == ecutsVERLET)
9653 set_zones_size(dd, state_local->box, &ddbox,
9654 bSortCG ? 1 : 0, comm->zones.n,
9658 wallcycle_sub_stop(wcycle, ewcsDD_SETUPCOMM);
9661 write_dd_pdb("dd_home",step,"dump",top_global,cr,
9662 -1,as_rvec_array(state_local->x.data()),state_local->box);
9665 wallcycle_sub_start(wcycle, ewcsDD_MAKETOP);
9667 /* Extract a local topology from the global topology */
9668 for (i = 0; i < dd->ndim; i++)
9670 np[dd->dim[i]] = comm->cd[i].np;
9672 dd_make_local_top(dd, &comm->zones, dd->npbcdim, state_local->box,
9673 comm->cellsize_min, np,
9675 fr->cutoff_scheme == ecutsGROUP ? fr->cg_cm : as_rvec_array(state_local->x.data()),
9676 vsite, top_global, top_local);
9678 wallcycle_sub_stop(wcycle, ewcsDD_MAKETOP);
9680 wallcycle_sub_start(wcycle, ewcsDD_MAKECONSTR);
9682 /* Set up the special atom communication */
9683 n = comm->nat[ddnatZONE];
9684 for (i = ddnatZONE+1; i < ddnatNR; i++)
9686 switch (i)
9688 case ddnatVSITE:
9689 if (vsite && vsite->n_intercg_vsite)
9691 n = dd_make_local_vsites(dd, n, top_local->idef.il);
9693 break;
9694 case ddnatCON:
9695 if (dd->bInterCGcons || dd->bInterCGsettles)
9697 /* Only for inter-cg constraints we need special code */
9698 n = dd_make_local_constraints(dd, n, top_global, fr->cginfo,
9699 constr, ir->nProjOrder,
9700 top_local->idef.il);
9702 break;
9703 default:
9704 gmx_incons("Unknown special atom type setup");
9706 comm->nat[i] = n;
9709 wallcycle_sub_stop(wcycle, ewcsDD_MAKECONSTR);
9711 wallcycle_sub_start(wcycle, ewcsDD_TOPOTHER);
9713 /* Make space for the extra coordinates for virtual site
9714 * or constraint communication.
9716 state_local->natoms = comm->nat[ddnatNR-1];
9718 dd_resize_state(state_local, f, state_local->natoms);
9720 if (fr->haveDirectVirialContributions)
9722 if (vsite && vsite->n_intercg_vsite)
9724 nat_f_novirsum = comm->nat[ddnatVSITE];
9726 else
9728 if (EEL_FULL(ir->coulombtype) && dd->n_intercg_excl > 0)
9730 nat_f_novirsum = dd->nat_tot;
9732 else
9734 nat_f_novirsum = dd->nat_home;
9738 else
9740 nat_f_novirsum = 0;
9743 /* Set the number of atoms required for the force calculation.
9744 * Forces need to be constrained when doing energy
9745 * minimization. For simple simulations we could avoid some
9746 * allocation, zeroing and copying, but this is probably not worth
9747 * the complications and checking.
9749 forcerec_set_ranges(fr, dd->ncg_home, dd->ncg_tot,
9750 dd->nat_tot, comm->nat[ddnatCON], nat_f_novirsum);
9752 /* Update atom data for mdatoms and several algorithms */
9753 mdAlgorithmsSetupAtomData(cr, ir, top_global, top_local, fr,
9754 nullptr, mdAtoms, vsite, nullptr);
9756 auto mdatoms = mdAtoms->mdatoms();
9757 if (!thisRankHasDuty(cr, DUTY_PME))
9759 /* Send the charges and/or c6/sigmas to our PME only node */
9760 gmx_pme_send_parameters(cr,
9761 fr->ic,
9762 mdatoms->nChargePerturbed, mdatoms->nTypePerturbed,
9763 mdatoms->chargeA, mdatoms->chargeB,
9764 mdatoms->sqrt_c6A, mdatoms->sqrt_c6B,
9765 mdatoms->sigmaA, mdatoms->sigmaB,
9766 dd_pme_maxshift_x(dd), dd_pme_maxshift_y(dd));
9769 if (constr)
9771 set_constraints(constr, top_local, ir, mdatoms, cr);
9774 if (ir->bPull)
9776 /* Update the local pull groups */
9777 dd_make_local_pull_groups(cr, ir->pull_work, mdatoms);
9780 if (ir->bRot)
9782 /* Update the local rotation groups */
9783 dd_make_local_rotation_groups(dd, ir->rot);
9786 if (ir->eSwapCoords != eswapNO)
9788 /* Update the local groups needed for ion swapping */
9789 dd_make_local_swap_groups(dd, ir->swap);
9792 /* Update the local atoms to be communicated via the IMD protocol if bIMD is TRUE. */
9793 dd_make_local_IMD_atoms(ir->bIMD, dd, ir->imd);
9795 add_dd_statistics(dd);
9797 /* Make sure we only count the cycles for this DD partitioning */
9798 clear_dd_cycle_counts(dd);
9800 /* Because the order of the atoms might have changed since
9801 * the last vsite construction, we need to communicate the constructing
9802 * atom coordinates again (for spreading the forces this MD step).
9804 dd_move_x_vsites(dd, state_local->box, as_rvec_array(state_local->x.data()));
9806 wallcycle_sub_stop(wcycle, ewcsDD_TOPOTHER);
9808 if (comm->nstDDDump > 0 && step % comm->nstDDDump == 0)
9810 dd_move_x(dd, state_local->box, as_rvec_array(state_local->x.data()), nullWallcycle);
9811 write_dd_pdb("dd_dump", step, "dump", top_global, cr,
9812 -1, as_rvec_array(state_local->x.data()), state_local->box);
9815 /* Store the partitioning step */
9816 comm->partition_step = step;
9818 /* Increase the DD partitioning counter */
9819 dd->ddp_count++;
9820 /* The state currently matches this DD partitioning count, store it */
9821 state_local->ddp_count = dd->ddp_count;
9822 if (bMasterState)
9824 /* The DD master node knows the complete cg distribution,
9825 * store the count so we can possibly skip the cg info communication.
9827 comm->master_cg_ddp_count = (bSortCG ? 0 : dd->ddp_count);
9830 if (comm->DD_debug > 0)
9832 /* Set the env var GMX_DD_DEBUG if you suspect corrupted indices */
9833 check_index_consistency(dd, top_global->natoms, ncg_mtop(top_global),
9834 "after partitioning");
9837 wallcycle_stop(wcycle, ewcDOMDEC);
9840 /*! \brief Check whether bonded interactions are missing, if appropriate */
9841 void checkNumberOfBondedInteractions(FILE *fplog,
9842 t_commrec *cr,
9843 int totalNumberOfBondedInteractions,
9844 const gmx_mtop_t *top_global,
9845 const gmx_localtop_t *top_local,
9846 const t_state *state,
9847 bool *shouldCheckNumberOfBondedInteractions)
9849 if (*shouldCheckNumberOfBondedInteractions)
9851 if (totalNumberOfBondedInteractions != cr->dd->nbonded_global)
9853 dd_print_missing_interactions(fplog, cr, totalNumberOfBondedInteractions, top_global, top_local, state); // Does not return
9855 *shouldCheckNumberOfBondedInteractions = false;