Move constraint and bonded filtering info into DDSystemInfo
[gromacs.git] / src / gromacs / domdec / domdec.cpp
blob37514e9ef2397e4479006c86547811a9d753a4b6
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,2019, 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 <cassert>
43 #include <cinttypes>
44 #include <climits>
45 #include <cmath>
46 #include <cstdio>
47 #include <cstdlib>
48 #include <cstring>
50 #include <algorithm>
51 #include <memory>
53 #include "gromacs/domdec/collect.h"
54 #include "gromacs/domdec/dlb.h"
55 #include "gromacs/domdec/dlbtiming.h"
56 #include "gromacs/domdec/domdec_network.h"
57 #include "gromacs/domdec/ga2la.h"
58 #include "gromacs/domdec/options.h"
59 #include "gromacs/domdec/partition.h"
60 #include "gromacs/gmxlib/network.h"
61 #include "gromacs/gmxlib/nrnb.h"
62 #include "gromacs/gpu_utils/gpu_utils.h"
63 #include "gromacs/hardware/hw_info.h"
64 #include "gromacs/listed_forces/manage_threading.h"
65 #include "gromacs/math/vec.h"
66 #include "gromacs/math/vectypes.h"
67 #include "gromacs/mdlib/calc_verletbuf.h"
68 #include "gromacs/mdlib/constr.h"
69 #include "gromacs/mdlib/constraintrange.h"
70 #include "gromacs/mdlib/updategroups.h"
71 #include "gromacs/mdlib/vsite.h"
72 #include "gromacs/mdtypes/commrec.h"
73 #include "gromacs/mdtypes/forceoutput.h"
74 #include "gromacs/mdtypes/inputrec.h"
75 #include "gromacs/mdtypes/mdrunoptions.h"
76 #include "gromacs/mdtypes/state.h"
77 #include "gromacs/pbcutil/ishift.h"
78 #include "gromacs/pbcutil/pbc.h"
79 #include "gromacs/pulling/pull.h"
80 #include "gromacs/timing/wallcycle.h"
81 #include "gromacs/topology/block.h"
82 #include "gromacs/topology/idef.h"
83 #include "gromacs/topology/ifunc.h"
84 #include "gromacs/topology/mtop_lookup.h"
85 #include "gromacs/topology/mtop_util.h"
86 #include "gromacs/topology/topology.h"
87 #include "gromacs/utility/basedefinitions.h"
88 #include "gromacs/utility/basenetwork.h"
89 #include "gromacs/utility/cstringutil.h"
90 #include "gromacs/utility/exceptions.h"
91 #include "gromacs/utility/fatalerror.h"
92 #include "gromacs/utility/gmxmpi.h"
93 #include "gromacs/utility/logger.h"
94 #include "gromacs/utility/real.h"
95 #include "gromacs/utility/smalloc.h"
96 #include "gromacs/utility/strconvert.h"
97 #include "gromacs/utility/stringstream.h"
98 #include "gromacs/utility/stringutil.h"
99 #include "gromacs/utility/textwriter.h"
101 #include "atomdistribution.h"
102 #include "box.h"
103 #include "cellsizes.h"
104 #include "distribute.h"
105 #include "domdec_constraints.h"
106 #include "domdec_internal.h"
107 #include "domdec_vsite.h"
108 #include "redistribute.h"
109 #include "utility.h"
111 // TODO remove this when moving domdec into gmx namespace
112 using gmx::DdRankOrder;
113 using gmx::DlbOption;
114 using gmx::DomdecOptions;
116 static const char *edlbs_names[int(DlbState::nr)] = { "off", "auto", "locked", "on", "on" };
118 /* The size per atom group of the cggl_flag buffer in gmx_domdec_comm_t */
119 #define DD_CGIBS 2
121 /* The flags for the cggl_flag buffer in gmx_domdec_comm_t */
122 #define DD_FLAG_NRCG 65535
123 #define DD_FLAG_FW(d) (1<<(16+(d)*2))
124 #define DD_FLAG_BW(d) (1<<(16+(d)*2+1))
126 /* The DD zone order */
127 static const ivec dd_zo[DD_MAXZONE] =
128 {{0, 0, 0}, {1, 0, 0}, {1, 1, 0}, {0, 1, 0}, {0, 1, 1}, {0, 0, 1}, {1, 0, 1}, {1, 1, 1}};
130 /* The non-bonded zone-pair setup for domain decomposition
131 * The first number is the i-zone, the second number the first j-zone seen by
132 * this i-zone, the third number the last+1 j-zone seen by this i-zone.
133 * As is, this is for 3D decomposition, where there are 4 i-zones.
134 * With 2D decomposition use only the first 2 i-zones and a last+1 j-zone of 4.
135 * With 1D decomposition use only the first i-zone and a last+1 j-zone of 2.
137 static const int
138 ddNonbondedZonePairRanges[DD_MAXIZONE][3] = {{0, 0, 8},
139 {1, 3, 6},
140 {2, 5, 6},
141 {3, 5, 7}};
145 #define dd_index(n,i) ((((i)[ZZ]*(n)[YY] + (i)[YY])*(n)[XX]) + (i)[XX])
147 static void index2xyz(ivec nc,int ind,ivec xyz)
149 xyz[XX] = ind % nc[XX];
150 xyz[YY] = (ind / nc[XX]) % nc[YY];
151 xyz[ZZ] = ind / (nc[YY]*nc[XX]);
155 static void ddindex2xyz(const ivec nc, int ind, ivec xyz)
157 xyz[XX] = ind / (nc[YY]*nc[ZZ]);
158 xyz[YY] = (ind / nc[ZZ]) % nc[YY];
159 xyz[ZZ] = ind % nc[ZZ];
162 static int ddcoord2ddnodeid(gmx_domdec_t *dd, ivec c)
164 int ddindex;
165 int ddnodeid = -1;
167 ddindex = dd_index(dd->nc, c);
168 if (dd->comm->bCartesianPP_PME)
170 ddnodeid = dd->comm->ddindex2ddnodeid[ddindex];
172 else if (dd->comm->bCartesianPP)
174 #if GMX_MPI
175 MPI_Cart_rank(dd->mpi_comm_all, c, &ddnodeid);
176 #endif
178 else
180 ddnodeid = ddindex;
183 return ddnodeid;
186 int ddglatnr(const gmx_domdec_t *dd, int i)
188 int atnr;
190 if (dd == nullptr)
192 atnr = i + 1;
194 else
196 if (i >= dd->comm->atomRanges.numAtomsTotal())
198 gmx_fatal(FARGS, "glatnr called with %d, which is larger than the local number of atoms (%d)", i, dd->comm->atomRanges.numAtomsTotal());
200 atnr = dd->globalAtomIndices[i] + 1;
203 return atnr;
206 t_block *dd_charge_groups_global(gmx_domdec_t *dd)
208 return &dd->comm->cgs_gl;
211 gmx::ArrayRef<const gmx::RangePartitioning> getUpdateGroupingPerMoleculetype(const gmx_domdec_t &dd)
213 GMX_RELEASE_ASSERT(dd.comm, "Need a valid dd.comm");
214 return dd.comm->systemInfo.updateGroupingPerMoleculetype;
217 void dd_store_state(gmx_domdec_t *dd, t_state *state)
219 int i;
221 if (state->ddp_count != dd->ddp_count)
223 gmx_incons("The MD state does not match the domain decomposition state");
226 state->cg_gl.resize(dd->ncg_home);
227 for (i = 0; i < dd->ncg_home; i++)
229 state->cg_gl[i] = dd->globalAtomGroupIndices[i];
232 state->ddp_count_cg_gl = dd->ddp_count;
235 gmx_domdec_zones_t *domdec_zones(gmx_domdec_t *dd)
237 return &dd->comm->zones;
240 void dd_get_ns_ranges(const gmx_domdec_t *dd, int icg,
241 int *jcg0, int *jcg1, ivec shift0, ivec shift1)
243 gmx_domdec_zones_t *zones;
244 int izone, d, dim;
246 zones = &dd->comm->zones;
248 izone = 0;
249 while (icg >= zones->izone[izone].cg1)
251 izone++;
254 if (izone == 0)
256 *jcg0 = icg;
258 else if (izone < zones->nizone)
260 *jcg0 = zones->izone[izone].jcg0;
262 else
264 gmx_fatal(FARGS, "DD icg %d out of range: izone (%d) >= nizone (%d)",
265 icg, izone, zones->nizone);
268 *jcg1 = zones->izone[izone].jcg1;
270 for (d = 0; d < dd->ndim; d++)
272 dim = dd->dim[d];
273 shift0[dim] = zones->izone[izone].shift0[dim];
274 shift1[dim] = zones->izone[izone].shift1[dim];
275 if (dd->comm->tric_dir[dim] || (isDlbOn(dd->comm) && d > 0))
277 /* A conservative approach, this can be optimized */
278 shift0[dim] -= 1;
279 shift1[dim] += 1;
284 int dd_numHomeAtoms(const gmx_domdec_t &dd)
286 return dd.comm->atomRanges.numHomeAtoms();
289 int dd_natoms_mdatoms(const gmx_domdec_t *dd)
291 /* We currently set mdatoms entries for all atoms:
292 * local + non-local + communicated for vsite + constraints
295 return dd->comm->atomRanges.numAtomsTotal();
298 int dd_natoms_vsite(const gmx_domdec_t *dd)
300 return dd->comm->atomRanges.end(DDAtomRanges::Type::Vsites);
303 void dd_get_constraint_range(const gmx_domdec_t *dd, int *at_start, int *at_end)
305 *at_start = dd->comm->atomRanges.start(DDAtomRanges::Type::Constraints);
306 *at_end = dd->comm->atomRanges.end(DDAtomRanges::Type::Constraints);
309 void dd_move_x(gmx_domdec_t *dd,
310 const matrix box,
311 gmx::ArrayRef<gmx::RVec> x,
312 gmx_wallcycle *wcycle)
314 wallcycle_start(wcycle, ewcMOVEX);
316 int nzone, nat_tot;
317 gmx_domdec_comm_t *comm;
318 gmx_domdec_comm_dim_t *cd;
319 rvec shift = {0, 0, 0};
320 gmx_bool bPBC, bScrew;
322 comm = dd->comm;
324 nzone = 1;
325 nat_tot = comm->atomRanges.numHomeAtoms();
326 for (int d = 0; d < dd->ndim; d++)
328 bPBC = (dd->ci[dd->dim[d]] == 0);
329 bScrew = (bPBC && dd->unitCellInfo.haveScrewPBC && dd->dim[d] == XX);
330 if (bPBC)
332 copy_rvec(box[dd->dim[d]], shift);
334 cd = &comm->cd[d];
335 for (const gmx_domdec_ind_t &ind : cd->ind)
337 DDBufferAccess<gmx::RVec> sendBufferAccess(comm->rvecBuffer, ind.nsend[nzone + 1]);
338 gmx::ArrayRef<gmx::RVec> &sendBuffer = sendBufferAccess.buffer;
339 int n = 0;
340 if (!bPBC)
342 for (int j : ind.index)
344 sendBuffer[n] = x[j];
345 n++;
348 else if (!bScrew)
350 for (int j : ind.index)
352 /* We need to shift the coordinates */
353 for (int d = 0; d < DIM; d++)
355 sendBuffer[n][d] = x[j][d] + shift[d];
357 n++;
360 else
362 for (int j : ind.index)
364 /* Shift x */
365 sendBuffer[n][XX] = x[j][XX] + shift[XX];
366 /* Rotate y and z.
367 * This operation requires a special shift force
368 * treatment, which is performed in calc_vir.
370 sendBuffer[n][YY] = box[YY][YY] - x[j][YY];
371 sendBuffer[n][ZZ] = box[ZZ][ZZ] - x[j][ZZ];
372 n++;
376 DDBufferAccess<gmx::RVec> receiveBufferAccess(comm->rvecBuffer2, cd->receiveInPlace ? 0 : ind.nrecv[nzone + 1]);
378 gmx::ArrayRef<gmx::RVec> receiveBuffer;
379 if (cd->receiveInPlace)
381 receiveBuffer = gmx::arrayRefFromArray(x.data() + nat_tot, ind.nrecv[nzone + 1]);
383 else
385 receiveBuffer = receiveBufferAccess.buffer;
387 /* Send and receive the coordinates */
388 ddSendrecv(dd, d, dddirBackward,
389 sendBuffer, receiveBuffer);
391 if (!cd->receiveInPlace)
393 int j = 0;
394 for (int zone = 0; zone < nzone; zone++)
396 for (int i = ind.cell2at0[zone]; i < ind.cell2at1[zone]; i++)
398 x[i] = receiveBuffer[j++];
402 nat_tot += ind.nrecv[nzone+1];
404 nzone += nzone;
407 wallcycle_stop(wcycle, ewcMOVEX);
410 void dd_move_f(gmx_domdec_t *dd,
411 gmx::ForceWithShiftForces *forceWithShiftForces,
412 gmx_wallcycle *wcycle)
414 wallcycle_start(wcycle, ewcMOVEF);
416 gmx::ArrayRef<gmx::RVec> f = forceWithShiftForces->force();
417 gmx::ArrayRef<gmx::RVec> fshift = forceWithShiftForces->shiftForces();
419 gmx_domdec_comm_t &comm = *dd->comm;
420 int nzone = comm.zones.n/2;
421 int nat_tot = comm.atomRanges.end(DDAtomRanges::Type::Zones);
422 for (int d = dd->ndim-1; d >= 0; d--)
424 /* Only forces in domains near the PBC boundaries need to
425 consider PBC in the treatment of fshift */
426 const bool shiftForcesNeedPbc = (forceWithShiftForces->computeVirial() && dd->ci[dd->dim[d]] == 0);
427 const bool applyScrewPbc = (shiftForcesNeedPbc && dd->unitCellInfo.haveScrewPBC && dd->dim[d] == XX);
428 /* Determine which shift vector we need */
429 ivec vis = { 0, 0, 0 };
430 vis[dd->dim[d]] = 1;
431 const int is = IVEC2IS(vis);
433 /* Loop over the pulses */
434 const gmx_domdec_comm_dim_t &cd = comm.cd[d];
435 for (int p = cd.numPulses() - 1; p >= 0; p--)
437 const gmx_domdec_ind_t &ind = cd.ind[p];
438 DDBufferAccess<gmx::RVec> receiveBufferAccess(comm.rvecBuffer, ind.nsend[nzone + 1]);
439 gmx::ArrayRef<gmx::RVec> &receiveBuffer = receiveBufferAccess.buffer;
441 nat_tot -= ind.nrecv[nzone+1];
443 DDBufferAccess<gmx::RVec> sendBufferAccess(comm.rvecBuffer2, cd.receiveInPlace ? 0 : ind.nrecv[nzone + 1]);
445 gmx::ArrayRef<gmx::RVec> sendBuffer;
446 if (cd.receiveInPlace)
448 sendBuffer = gmx::arrayRefFromArray(f.data() + nat_tot, ind.nrecv[nzone + 1]);
450 else
452 sendBuffer = sendBufferAccess.buffer;
453 int j = 0;
454 for (int zone = 0; zone < nzone; zone++)
456 for (int i = ind.cell2at0[zone]; i < ind.cell2at1[zone]; i++)
458 sendBuffer[j++] = f[i];
462 /* Communicate the forces */
463 ddSendrecv(dd, d, dddirForward,
464 sendBuffer, receiveBuffer);
465 /* Add the received forces */
466 int n = 0;
467 if (!shiftForcesNeedPbc)
469 for (int j : ind.index)
471 for (int d = 0; d < DIM; d++)
473 f[j][d] += receiveBuffer[n][d];
475 n++;
478 else if (!applyScrewPbc)
480 for (int j : ind.index)
482 for (int d = 0; d < DIM; d++)
484 f[j][d] += receiveBuffer[n][d];
486 /* Add this force to the shift force */
487 for (int d = 0; d < DIM; d++)
489 fshift[is][d] += receiveBuffer[n][d];
491 n++;
494 else
496 for (int j : ind.index)
498 /* Rotate the force */
499 f[j][XX] += receiveBuffer[n][XX];
500 f[j][YY] -= receiveBuffer[n][YY];
501 f[j][ZZ] -= receiveBuffer[n][ZZ];
502 if (shiftForcesNeedPbc)
504 /* Add this force to the shift force */
505 for (int d = 0; d < DIM; d++)
507 fshift[is][d] += receiveBuffer[n][d];
510 n++;
514 nzone /= 2;
516 wallcycle_stop(wcycle, ewcMOVEF);
519 /* Convenience function for extracting a real buffer from an rvec buffer
521 * To reduce the number of temporary communication buffers and avoid
522 * cache polution, we reuse gmx::RVec buffers for storing reals.
523 * This functions return a real buffer reference with the same number
524 * of elements as the gmx::RVec buffer (so 1/3 of the size in bytes).
526 static gmx::ArrayRef<real>
527 realArrayRefFromRvecArrayRef(gmx::ArrayRef<gmx::RVec> arrayRef)
529 return gmx::arrayRefFromArray(as_rvec_array(arrayRef.data())[0],
530 arrayRef.size());
533 void dd_atom_spread_real(gmx_domdec_t *dd, real v[])
535 int nzone, nat_tot;
536 gmx_domdec_comm_t *comm;
537 gmx_domdec_comm_dim_t *cd;
539 comm = dd->comm;
541 nzone = 1;
542 nat_tot = comm->atomRanges.numHomeAtoms();
543 for (int d = 0; d < dd->ndim; d++)
545 cd = &comm->cd[d];
546 for (const gmx_domdec_ind_t &ind : cd->ind)
548 /* Note: We provision for RVec instead of real, so a factor of 3
549 * more than needed. The buffer actually already has this size
550 * and we pass a plain pointer below, so this does not matter.
552 DDBufferAccess<gmx::RVec> sendBufferAccess(comm->rvecBuffer, ind.nsend[nzone + 1]);
553 gmx::ArrayRef<real> sendBuffer = realArrayRefFromRvecArrayRef(sendBufferAccess.buffer);
554 int n = 0;
555 for (int j : ind.index)
557 sendBuffer[n++] = v[j];
560 DDBufferAccess<gmx::RVec> receiveBufferAccess(comm->rvecBuffer2, cd->receiveInPlace ? 0 : ind.nrecv[nzone + 1]);
562 gmx::ArrayRef<real> receiveBuffer;
563 if (cd->receiveInPlace)
565 receiveBuffer = gmx::arrayRefFromArray(v + nat_tot, ind.nrecv[nzone + 1]);
567 else
569 receiveBuffer = realArrayRefFromRvecArrayRef(receiveBufferAccess.buffer);
571 /* Send and receive the data */
572 ddSendrecv(dd, d, dddirBackward,
573 sendBuffer, receiveBuffer);
574 if (!cd->receiveInPlace)
576 int j = 0;
577 for (int zone = 0; zone < nzone; zone++)
579 for (int i = ind.cell2at0[zone]; i < ind.cell2at1[zone]; i++)
581 v[i] = receiveBuffer[j++];
585 nat_tot += ind.nrecv[nzone+1];
587 nzone += nzone;
591 void dd_atom_sum_real(gmx_domdec_t *dd, real v[])
593 int nzone, nat_tot;
594 gmx_domdec_comm_t *comm;
595 gmx_domdec_comm_dim_t *cd;
597 comm = dd->comm;
599 nzone = comm->zones.n/2;
600 nat_tot = comm->atomRanges.end(DDAtomRanges::Type::Zones);
601 for (int d = dd->ndim-1; d >= 0; d--)
603 cd = &comm->cd[d];
604 for (int p = cd->numPulses() - 1; p >= 0; p--)
606 const gmx_domdec_ind_t &ind = cd->ind[p];
608 /* Note: We provision for RVec instead of real, so a factor of 3
609 * more than needed. The buffer actually already has this size
610 * and we typecast, so this works as intended.
612 DDBufferAccess<gmx::RVec> receiveBufferAccess(comm->rvecBuffer, ind.nsend[nzone + 1]);
613 gmx::ArrayRef<real> receiveBuffer = realArrayRefFromRvecArrayRef(receiveBufferAccess.buffer);
614 nat_tot -= ind.nrecv[nzone + 1];
616 DDBufferAccess<gmx::RVec> sendBufferAccess(comm->rvecBuffer2, cd->receiveInPlace ? 0 : ind.nrecv[nzone + 1]);
618 gmx::ArrayRef<real> sendBuffer;
619 if (cd->receiveInPlace)
621 sendBuffer = gmx::arrayRefFromArray(v + nat_tot, ind.nrecv[nzone + 1]);
623 else
625 sendBuffer = realArrayRefFromRvecArrayRef(sendBufferAccess.buffer);
626 int j = 0;
627 for (int zone = 0; zone < nzone; zone++)
629 for (int i = ind.cell2at0[zone]; i < ind.cell2at1[zone]; i++)
631 sendBuffer[j++] = v[i];
635 /* Communicate the forces */
636 ddSendrecv(dd, d, dddirForward,
637 sendBuffer, receiveBuffer);
638 /* Add the received forces */
639 int n = 0;
640 for (int j : ind.index)
642 v[j] += receiveBuffer[n];
643 n++;
646 nzone /= 2;
650 real dd_cutoff_multibody(const gmx_domdec_t *dd)
652 const gmx_domdec_comm_t &comm = *dd->comm;
653 const DDSystemInfo &systemInfo = comm.systemInfo;
655 real r = -1;
656 if (systemInfo.haveInterDomainMultiBodyBondeds)
658 if (comm.cutoff_mbody > 0)
660 r = comm.cutoff_mbody;
662 else
664 /* cutoff_mbody=0 means we do not have DLB */
665 r = comm.cellsize_min[dd->dim[0]];
666 for (int di = 1; di < dd->ndim; di++)
668 r = std::min(r, comm.cellsize_min[dd->dim[di]]);
670 if (comm.systemInfo.filterBondedCommunication)
672 r = std::max(r, comm.cutoff_mbody);
674 else
676 r = std::min(r, systemInfo.cutoff);
681 return r;
684 real dd_cutoff_twobody(const gmx_domdec_t *dd)
686 real r_mb;
688 r_mb = dd_cutoff_multibody(dd);
690 return std::max(dd->comm->systemInfo.cutoff, r_mb);
694 static void dd_cart_coord2pmecoord(const gmx_domdec_t *dd, const ivec coord,
695 ivec coord_pme)
697 int nc, ntot;
699 nc = dd->nc[dd->comm->cartpmedim];
700 ntot = dd->comm->ntot[dd->comm->cartpmedim];
701 copy_ivec(coord, coord_pme);
702 coord_pme[dd->comm->cartpmedim] =
703 nc + (coord[dd->comm->cartpmedim]*(ntot - nc) + (ntot - nc)/2)/nc;
706 static int ddindex2pmeindex(const gmx_domdec_t *dd, int ddindex)
708 int npp, npme;
710 npp = dd->nnodes;
711 npme = dd->comm->npmenodes;
713 /* Here we assign a PME node to communicate with this DD node
714 * by assuming that the major index of both is x.
715 * We add cr->npmenodes/2 to obtain an even distribution.
717 return (ddindex*npme + npme/2)/npp;
720 static int *dd_interleaved_pme_ranks(const gmx_domdec_t *dd)
722 int *pme_rank;
723 int n, i, p0, p1;
725 snew(pme_rank, dd->comm->npmenodes);
726 n = 0;
727 for (i = 0; i < dd->nnodes; i++)
729 p0 = ddindex2pmeindex(dd, i);
730 p1 = ddindex2pmeindex(dd, i+1);
731 if (i+1 == dd->nnodes || p1 > p0)
733 if (debug)
735 fprintf(debug, "pme_rank[%d] = %d\n", n, i+1+n);
737 pme_rank[n] = i + 1 + n;
738 n++;
742 return pme_rank;
745 static int gmx_ddcoord2pmeindex(const t_commrec *cr, int x, int y, int z)
747 gmx_domdec_t *dd;
748 ivec coords;
749 int slab;
751 dd = cr->dd;
753 if (dd->comm->bCartesian) {
754 gmx_ddindex2xyz(dd->nc,ddindex,coords);
755 dd_coords2pmecoords(dd,coords,coords_pme);
756 copy_ivec(dd->ntot,nc);
757 nc[dd->cartpmedim] -= dd->nc[dd->cartpmedim];
758 coords_pme[dd->cartpmedim] -= dd->nc[dd->cartpmedim];
760 slab = (coords_pme[XX]*nc[YY] + coords_pme[YY])*nc[ZZ] + coords_pme[ZZ];
761 } else {
762 slab = (ddindex*cr->npmenodes + cr->npmenodes/2)/dd->nnodes;
765 coords[XX] = x;
766 coords[YY] = y;
767 coords[ZZ] = z;
768 slab = ddindex2pmeindex(dd, dd_index(dd->nc, coords));
770 return slab;
773 static int ddcoord2simnodeid(const t_commrec *cr, int x, int y, int z)
775 gmx_domdec_comm_t *comm;
776 ivec coords;
777 int ddindex, nodeid = -1;
779 comm = cr->dd->comm;
781 coords[XX] = x;
782 coords[YY] = y;
783 coords[ZZ] = z;
784 if (comm->bCartesianPP_PME)
786 #if GMX_MPI
787 MPI_Cart_rank(cr->mpi_comm_mysim, coords, &nodeid);
788 #endif
790 else
792 ddindex = dd_index(cr->dd->nc, coords);
793 if (comm->bCartesianPP)
795 nodeid = comm->ddindex2simnodeid[ddindex];
797 else
799 if (comm->pmenodes)
801 nodeid = ddindex + gmx_ddcoord2pmeindex(cr, x, y, z);
803 else
805 nodeid = ddindex;
810 return nodeid;
813 static int dd_simnode2pmenode(const gmx_domdec_t *dd,
814 const t_commrec gmx_unused *cr,
815 int sim_nodeid)
817 int pmenode = -1;
819 const gmx_domdec_comm_t *comm = dd->comm;
821 /* This assumes a uniform x domain decomposition grid cell size */
822 if (comm->bCartesianPP_PME)
824 #if GMX_MPI
825 ivec coord, coord_pme;
826 MPI_Cart_coords(cr->mpi_comm_mysim, sim_nodeid, DIM, coord);
827 if (coord[comm->cartpmedim] < dd->nc[comm->cartpmedim])
829 /* This is a PP node */
830 dd_cart_coord2pmecoord(dd, coord, coord_pme);
831 MPI_Cart_rank(cr->mpi_comm_mysim, coord_pme, &pmenode);
833 #endif
835 else if (comm->bCartesianPP)
837 if (sim_nodeid < dd->nnodes)
839 pmenode = dd->nnodes + ddindex2pmeindex(dd, sim_nodeid);
842 else
844 /* This assumes DD cells with identical x coordinates
845 * are numbered sequentially.
847 if (dd->comm->pmenodes == nullptr)
849 if (sim_nodeid < dd->nnodes)
851 /* The DD index equals the nodeid */
852 pmenode = dd->nnodes + ddindex2pmeindex(dd, sim_nodeid);
855 else
857 int i = 0;
858 while (sim_nodeid > dd->comm->pmenodes[i])
860 i++;
862 if (sim_nodeid < dd->comm->pmenodes[i])
864 pmenode = dd->comm->pmenodes[i];
869 return pmenode;
872 NumPmeDomains getNumPmeDomains(const gmx_domdec_t *dd)
874 if (dd != nullptr)
876 return {
877 dd->comm->npmenodes_x, dd->comm->npmenodes_y
880 else
882 return {
883 1, 1
888 std::vector<int> get_pme_ddranks(const t_commrec *cr, int pmenodeid)
890 gmx_domdec_t *dd;
891 int x, y, z;
892 ivec coord, coord_pme;
894 dd = cr->dd;
896 std::vector<int> ddranks;
897 ddranks.reserve((dd->nnodes+cr->npmenodes-1)/cr->npmenodes);
899 for (x = 0; x < dd->nc[XX]; x++)
901 for (y = 0; y < dd->nc[YY]; y++)
903 for (z = 0; z < dd->nc[ZZ]; z++)
905 if (dd->comm->bCartesianPP_PME)
907 coord[XX] = x;
908 coord[YY] = y;
909 coord[ZZ] = z;
910 dd_cart_coord2pmecoord(dd, coord, coord_pme);
911 if (dd->ci[XX] == coord_pme[XX] &&
912 dd->ci[YY] == coord_pme[YY] &&
913 dd->ci[ZZ] == coord_pme[ZZ])
915 ddranks.push_back(ddcoord2simnodeid(cr, x, y, z));
918 else
920 /* The slab corresponds to the nodeid in the PME group */
921 if (gmx_ddcoord2pmeindex(cr, x, y, z) == pmenodeid)
923 ddranks.push_back(ddcoord2simnodeid(cr, x, y, z));
929 return ddranks;
932 static gmx_bool receive_vir_ener(const gmx_domdec_t *dd, const t_commrec *cr)
934 gmx_bool bReceive = TRUE;
936 if (cr->npmenodes < dd->nnodes)
938 gmx_domdec_comm_t *comm = dd->comm;
939 if (comm->bCartesianPP_PME)
941 #if GMX_MPI
942 int pmenode = dd_simnode2pmenode(dd, cr, cr->sim_nodeid);
943 ivec coords;
944 MPI_Cart_coords(cr->mpi_comm_mysim, cr->sim_nodeid, DIM, coords);
945 coords[comm->cartpmedim]++;
946 if (coords[comm->cartpmedim] < dd->nc[comm->cartpmedim])
948 int rank;
949 MPI_Cart_rank(cr->mpi_comm_mysim, coords, &rank);
950 if (dd_simnode2pmenode(dd, cr, rank) == pmenode)
952 /* This is not the last PP node for pmenode */
953 bReceive = FALSE;
956 #else
957 GMX_RELEASE_ASSERT(false, "Without MPI we should not have Cartesian PP-PME with #PMEnodes < #DDnodes");
958 #endif
960 else
962 int pmenode = dd_simnode2pmenode(dd, cr, cr->sim_nodeid);
963 if (cr->sim_nodeid+1 < cr->nnodes &&
964 dd_simnode2pmenode(dd, cr, cr->sim_nodeid+1) == pmenode)
966 /* This is not the last PP node for pmenode */
967 bReceive = FALSE;
972 return bReceive;
975 static void set_slb_pme_dim_f(gmx_domdec_t *dd, int dim, real **dim_f)
977 gmx_domdec_comm_t *comm;
978 int i;
980 comm = dd->comm;
982 snew(*dim_f, dd->nc[dim]+1);
983 (*dim_f)[0] = 0;
984 for (i = 1; i < dd->nc[dim]; i++)
986 if (comm->slb_frac[dim])
988 (*dim_f)[i] = (*dim_f)[i-1] + comm->slb_frac[dim][i-1];
990 else
992 (*dim_f)[i] = static_cast<real>(i)/static_cast<real>(dd->nc[dim]);
995 (*dim_f)[dd->nc[dim]] = 1;
998 static void init_ddpme(gmx_domdec_t *dd, gmx_ddpme_t *ddpme, int dimind)
1000 int pmeindex, slab, nso, i;
1001 ivec xyz;
1003 if (dimind == 0 && dd->dim[0] == YY && dd->comm->npmenodes_x == 1)
1005 ddpme->dim = YY;
1007 else
1009 ddpme->dim = dimind;
1011 ddpme->dim_match = (ddpme->dim == dd->dim[dimind]);
1013 ddpme->nslab = (ddpme->dim == 0 ?
1014 dd->comm->npmenodes_x :
1015 dd->comm->npmenodes_y);
1017 if (ddpme->nslab <= 1)
1019 return;
1022 nso = dd->comm->npmenodes/ddpme->nslab;
1023 /* Determine for each PME slab the PP location range for dimension dim */
1024 snew(ddpme->pp_min, ddpme->nslab);
1025 snew(ddpme->pp_max, ddpme->nslab);
1026 for (slab = 0; slab < ddpme->nslab; slab++)
1028 ddpme->pp_min[slab] = dd->nc[dd->dim[dimind]] - 1;
1029 ddpme->pp_max[slab] = 0;
1031 for (i = 0; i < dd->nnodes; i++)
1033 ddindex2xyz(dd->nc, i, xyz);
1034 /* For y only use our y/z slab.
1035 * This assumes that the PME x grid size matches the DD grid size.
1037 if (dimind == 0 || xyz[XX] == dd->ci[XX])
1039 pmeindex = ddindex2pmeindex(dd, i);
1040 if (dimind == 0)
1042 slab = pmeindex/nso;
1044 else
1046 slab = pmeindex % ddpme->nslab;
1048 ddpme->pp_min[slab] = std::min(ddpme->pp_min[slab], xyz[dimind]);
1049 ddpme->pp_max[slab] = std::max(ddpme->pp_max[slab], xyz[dimind]);
1053 set_slb_pme_dim_f(dd, ddpme->dim, &ddpme->slb_dim_f);
1056 int dd_pme_maxshift_x(const gmx_domdec_t *dd)
1058 if (dd->comm->ddpme[0].dim == XX)
1060 return dd->comm->ddpme[0].maxshift;
1062 else
1064 return 0;
1068 int dd_pme_maxshift_y(const gmx_domdec_t *dd)
1070 if (dd->comm->ddpme[0].dim == YY)
1072 return dd->comm->ddpme[0].maxshift;
1074 else if (dd->comm->npmedecompdim >= 2 && dd->comm->ddpme[1].dim == YY)
1076 return dd->comm->ddpme[1].maxshift;
1078 else
1080 return 0;
1084 bool ddHaveSplitConstraints(const gmx_domdec_t &dd)
1086 return dd.comm->systemInfo.haveSplitConstraints;
1089 void dd_cycles_add(const gmx_domdec_t *dd, float cycles, int ddCycl)
1091 /* Note that the cycles value can be incorrect, either 0 or some
1092 * extremely large value, when our thread migrated to another core
1093 * with an unsynchronized cycle counter. If this happens less often
1094 * that once per nstlist steps, this will not cause issues, since
1095 * we later subtract the maximum value from the sum over nstlist steps.
1096 * A zero count will slightly lower the total, but that's a small effect.
1097 * Note that the main purpose of the subtraction of the maximum value
1098 * is to avoid throwing off the load balancing when stalls occur due
1099 * e.g. system activity or network congestion.
1101 dd->comm->cycl[ddCycl] += cycles;
1102 dd->comm->cycl_n[ddCycl]++;
1103 if (cycles > dd->comm->cycl_max[ddCycl])
1105 dd->comm->cycl_max[ddCycl] = cycles;
1109 #if GMX_MPI
1110 static void make_load_communicator(gmx_domdec_t *dd, int dim_ind, ivec loc)
1112 MPI_Comm c_row;
1113 int dim, i, rank;
1114 ivec loc_c;
1115 gmx_bool bPartOfGroup = FALSE;
1117 dim = dd->dim[dim_ind];
1118 copy_ivec(loc, loc_c);
1119 for (i = 0; i < dd->nc[dim]; i++)
1121 loc_c[dim] = i;
1122 rank = dd_index(dd->nc, loc_c);
1123 if (rank == dd->rank)
1125 /* This process is part of the group */
1126 bPartOfGroup = TRUE;
1129 MPI_Comm_split(dd->mpi_comm_all, bPartOfGroup ? 0 : MPI_UNDEFINED, dd->rank,
1130 &c_row);
1131 if (bPartOfGroup)
1133 dd->comm->mpi_comm_load[dim_ind] = c_row;
1134 if (!isDlbDisabled(dd->comm))
1136 DDCellsizesWithDlb &cellsizes = dd->comm->cellsizesWithDlb[dim_ind];
1138 if (dd->ci[dim] == dd->master_ci[dim])
1140 /* This is the root process of this row */
1141 cellsizes.rowMaster = std::make_unique<RowMaster>();
1143 RowMaster &rowMaster = *cellsizes.rowMaster;
1144 rowMaster.cellFrac.resize(ddCellFractionBufferSize(dd, dim_ind));
1145 rowMaster.oldCellFrac.resize(dd->nc[dim] + 1);
1146 rowMaster.isCellMin.resize(dd->nc[dim]);
1147 if (dim_ind > 0)
1149 rowMaster.bounds.resize(dd->nc[dim]);
1151 rowMaster.buf_ncd.resize(dd->nc[dim]);
1153 else
1155 /* This is not a root process, we only need to receive cell_f */
1156 cellsizes.fracRow.resize(ddCellFractionBufferSize(dd, dim_ind));
1159 if (dd->ci[dim] == dd->master_ci[dim])
1161 snew(dd->comm->load[dim_ind].load, dd->nc[dim]*DD_NLOAD_MAX);
1165 #endif
1167 void dd_setup_dlb_resource_sharing(t_commrec *cr,
1168 int gpu_id)
1170 #if GMX_MPI
1171 int physicalnode_id_hash;
1172 gmx_domdec_t *dd;
1173 MPI_Comm mpi_comm_pp_physicalnode;
1175 if (!thisRankHasDuty(cr, DUTY_PP) || gpu_id < 0)
1177 /* Only ranks with short-ranged tasks (currently) use GPUs.
1178 * If we don't have GPUs assigned, there are no resources to share.
1180 return;
1183 physicalnode_id_hash = gmx_physicalnode_id_hash();
1185 dd = cr->dd;
1187 if (debug)
1189 fprintf(debug, "dd_setup_dd_dlb_gpu_sharing:\n");
1190 fprintf(debug, "DD PP rank %d physical node hash %d gpu_id %d\n",
1191 dd->rank, physicalnode_id_hash, gpu_id);
1193 /* Split the PP communicator over the physical nodes */
1194 /* TODO: See if we should store this (before), as it's also used for
1195 * for the nodecomm summation.
1197 // TODO PhysicalNodeCommunicator could be extended/used to handle
1198 // the need for per-node per-group communicators.
1199 MPI_Comm_split(dd->mpi_comm_all, physicalnode_id_hash, dd->rank,
1200 &mpi_comm_pp_physicalnode);
1201 MPI_Comm_split(mpi_comm_pp_physicalnode, gpu_id, dd->rank,
1202 &dd->comm->mpi_comm_gpu_shared);
1203 MPI_Comm_free(&mpi_comm_pp_physicalnode);
1204 MPI_Comm_size(dd->comm->mpi_comm_gpu_shared, &dd->comm->nrank_gpu_shared);
1206 if (debug)
1208 fprintf(debug, "nrank_gpu_shared %d\n", dd->comm->nrank_gpu_shared);
1211 /* Note that some ranks could share a GPU, while others don't */
1213 if (dd->comm->nrank_gpu_shared == 1)
1215 MPI_Comm_free(&dd->comm->mpi_comm_gpu_shared);
1217 #else
1218 GMX_UNUSED_VALUE(cr);
1219 GMX_UNUSED_VALUE(gpu_id);
1220 #endif
1223 static void make_load_communicators(gmx_domdec_t gmx_unused *dd)
1225 #if GMX_MPI
1226 int dim0, dim1, i, j;
1227 ivec loc;
1229 if (debug)
1231 fprintf(debug, "Making load communicators\n");
1234 dd->comm->load = new domdec_load_t[std::max(dd->ndim, 1)];
1235 snew(dd->comm->mpi_comm_load, std::max(dd->ndim, 1));
1237 if (dd->ndim == 0)
1239 return;
1242 clear_ivec(loc);
1243 make_load_communicator(dd, 0, loc);
1244 if (dd->ndim > 1)
1246 dim0 = dd->dim[0];
1247 for (i = 0; i < dd->nc[dim0]; i++)
1249 loc[dim0] = i;
1250 make_load_communicator(dd, 1, loc);
1253 if (dd->ndim > 2)
1255 dim0 = dd->dim[0];
1256 for (i = 0; i < dd->nc[dim0]; i++)
1258 loc[dim0] = i;
1259 dim1 = dd->dim[1];
1260 for (j = 0; j < dd->nc[dim1]; j++)
1262 loc[dim1] = j;
1263 make_load_communicator(dd, 2, loc);
1268 if (debug)
1270 fprintf(debug, "Finished making load communicators\n");
1272 #endif
1275 /*! \brief Sets up the relation between neighboring domains and zones */
1276 static void setup_neighbor_relations(gmx_domdec_t *dd)
1278 int d, dim, i, j, m;
1279 ivec tmp, s;
1280 gmx_domdec_zones_t *zones;
1281 gmx_domdec_ns_ranges_t *izone;
1282 GMX_ASSERT(dd->ndim >= 0, "Must have non-negative number of dimensions for DD");
1284 for (d = 0; d < dd->ndim; d++)
1286 dim = dd->dim[d];
1287 copy_ivec(dd->ci, tmp);
1288 tmp[dim] = (tmp[dim] + 1) % dd->nc[dim];
1289 dd->neighbor[d][0] = ddcoord2ddnodeid(dd, tmp);
1290 copy_ivec(dd->ci, tmp);
1291 tmp[dim] = (tmp[dim] - 1 + dd->nc[dim]) % dd->nc[dim];
1292 dd->neighbor[d][1] = ddcoord2ddnodeid(dd, tmp);
1293 if (debug)
1295 fprintf(debug, "DD rank %d neighbor ranks in dir %d are + %d - %d\n",
1296 dd->rank, dim,
1297 dd->neighbor[d][0],
1298 dd->neighbor[d][1]);
1302 int nzone = (1 << dd->ndim);
1303 GMX_ASSERT(dd->ndim < DIM, "Invalid number of dimensions");
1304 int nizone = (1 << std::max(dd->ndim - 1, 0));
1305 assert(nizone >= 1 && nizone <= DD_MAXIZONE);
1307 zones = &dd->comm->zones;
1309 for (i = 0; i < nzone; i++)
1311 m = 0;
1312 clear_ivec(zones->shift[i]);
1313 for (d = 0; d < dd->ndim; d++)
1315 zones->shift[i][dd->dim[d]] = dd_zo[i][m++];
1319 zones->n = nzone;
1320 for (i = 0; i < nzone; i++)
1322 for (d = 0; d < DIM; d++)
1324 s[d] = dd->ci[d] - zones->shift[i][d];
1325 if (s[d] < 0)
1327 s[d] += dd->nc[d];
1329 else if (s[d] >= dd->nc[d])
1331 s[d] -= dd->nc[d];
1335 zones->nizone = nizone;
1336 for (i = 0; i < zones->nizone; i++)
1338 assert(ddNonbondedZonePairRanges[i][0] == i);
1340 izone = &zones->izone[i];
1341 /* dd_zp3 is for 3D decomposition, for fewer dimensions use only
1342 * j-zones up to nzone.
1344 izone->j0 = std::min(ddNonbondedZonePairRanges[i][1], nzone);
1345 izone->j1 = std::min(ddNonbondedZonePairRanges[i][2], nzone);
1346 for (dim = 0; dim < DIM; dim++)
1348 if (dd->nc[dim] == 1)
1350 /* All shifts should be allowed */
1351 izone->shift0[dim] = -1;
1352 izone->shift1[dim] = 1;
1354 else
1356 /* Determine the min/max j-zone shift wrt the i-zone */
1357 izone->shift0[dim] = 1;
1358 izone->shift1[dim] = -1;
1359 for (j = izone->j0; j < izone->j1; j++)
1361 int shift_diff = zones->shift[j][dim] - zones->shift[i][dim];
1362 if (shift_diff < izone->shift0[dim])
1364 izone->shift0[dim] = shift_diff;
1366 if (shift_diff > izone->shift1[dim])
1368 izone->shift1[dim] = shift_diff;
1375 if (!isDlbDisabled(dd->comm))
1377 dd->comm->cellsizesWithDlb.resize(dd->ndim);
1380 if (dd->comm->bRecordLoad)
1382 make_load_communicators(dd);
1386 static void make_pp_communicator(const gmx::MDLogger &mdlog,
1387 gmx_domdec_t *dd,
1388 t_commrec gmx_unused *cr,
1389 bool gmx_unused reorder)
1391 #if GMX_MPI
1392 gmx_domdec_comm_t *comm;
1393 int rank, *buf;
1394 ivec periods;
1395 MPI_Comm comm_cart;
1397 comm = dd->comm;
1399 if (comm->bCartesianPP)
1401 /* Set up cartesian communication for the particle-particle part */
1402 GMX_LOG(mdlog.info).appendTextFormatted(
1403 "Will use a Cartesian communicator: %d x %d x %d",
1404 dd->nc[XX], dd->nc[YY], dd->nc[ZZ]);
1406 for (int i = 0; i < DIM; i++)
1408 periods[i] = TRUE;
1410 MPI_Cart_create(cr->mpi_comm_mygroup, DIM, dd->nc, periods, static_cast<int>(reorder),
1411 &comm_cart);
1412 /* We overwrite the old communicator with the new cartesian one */
1413 cr->mpi_comm_mygroup = comm_cart;
1416 dd->mpi_comm_all = cr->mpi_comm_mygroup;
1417 MPI_Comm_rank(dd->mpi_comm_all, &dd->rank);
1419 if (comm->bCartesianPP_PME)
1421 /* Since we want to use the original cartesian setup for sim,
1422 * and not the one after split, we need to make an index.
1424 snew(comm->ddindex2ddnodeid, dd->nnodes);
1425 comm->ddindex2ddnodeid[dd_index(dd->nc, dd->ci)] = dd->rank;
1426 gmx_sumi(dd->nnodes, comm->ddindex2ddnodeid, cr);
1427 /* Get the rank of the DD master,
1428 * above we made sure that the master node is a PP node.
1430 if (MASTER(cr))
1432 rank = dd->rank;
1434 else
1436 rank = 0;
1438 MPI_Allreduce(&rank, &dd->masterrank, 1, MPI_INT, MPI_SUM, dd->mpi_comm_all);
1440 else if (comm->bCartesianPP)
1442 if (cr->npmenodes == 0)
1444 /* The PP communicator is also
1445 * the communicator for this simulation
1447 cr->mpi_comm_mysim = cr->mpi_comm_mygroup;
1449 cr->nodeid = dd->rank;
1451 MPI_Cart_coords(dd->mpi_comm_all, dd->rank, DIM, dd->ci);
1453 /* We need to make an index to go from the coordinates
1454 * to the nodeid of this simulation.
1456 snew(comm->ddindex2simnodeid, dd->nnodes);
1457 snew(buf, dd->nnodes);
1458 if (thisRankHasDuty(cr, DUTY_PP))
1460 buf[dd_index(dd->nc, dd->ci)] = cr->sim_nodeid;
1462 /* Communicate the ddindex to simulation nodeid index */
1463 MPI_Allreduce(buf, comm->ddindex2simnodeid, dd->nnodes, MPI_INT, MPI_SUM,
1464 cr->mpi_comm_mysim);
1465 sfree(buf);
1467 /* Determine the master coordinates and rank.
1468 * The DD master should be the same node as the master of this sim.
1470 for (int i = 0; i < dd->nnodes; i++)
1472 if (comm->ddindex2simnodeid[i] == 0)
1474 ddindex2xyz(dd->nc, i, dd->master_ci);
1475 MPI_Cart_rank(dd->mpi_comm_all, dd->master_ci, &dd->masterrank);
1478 if (debug)
1480 fprintf(debug, "The master rank is %d\n", dd->masterrank);
1483 else
1485 /* No Cartesian communicators */
1486 /* We use the rank in dd->comm->all as DD index */
1487 ddindex2xyz(dd->nc, dd->rank, dd->ci);
1488 /* The simulation master nodeid is 0, so the DD master rank is also 0 */
1489 dd->masterrank = 0;
1490 clear_ivec(dd->master_ci);
1492 #endif
1494 GMX_LOG(mdlog.info).appendTextFormatted(
1495 "Domain decomposition rank %d, coordinates %d %d %d\n",
1496 dd->rank, dd->ci[XX], dd->ci[YY], dd->ci[ZZ]);
1497 if (debug)
1499 fprintf(debug,
1500 "Domain decomposition rank %d, coordinates %d %d %d\n\n",
1501 dd->rank, dd->ci[XX], dd->ci[YY], dd->ci[ZZ]);
1505 static void receive_ddindex2simnodeid(gmx_domdec_t *dd,
1506 t_commrec *cr)
1508 #if GMX_MPI
1509 gmx_domdec_comm_t *comm = dd->comm;
1511 if (!comm->bCartesianPP_PME && comm->bCartesianPP)
1513 int *buf;
1514 snew(comm->ddindex2simnodeid, dd->nnodes);
1515 snew(buf, dd->nnodes);
1516 if (thisRankHasDuty(cr, DUTY_PP))
1518 buf[dd_index(dd->nc, dd->ci)] = cr->sim_nodeid;
1520 /* Communicate the ddindex to simulation nodeid index */
1521 MPI_Allreduce(buf, comm->ddindex2simnodeid, dd->nnodes, MPI_INT, MPI_SUM,
1522 cr->mpi_comm_mysim);
1523 sfree(buf);
1525 #else
1526 GMX_UNUSED_VALUE(dd);
1527 GMX_UNUSED_VALUE(cr);
1528 #endif
1531 static void split_communicator(const gmx::MDLogger &mdlog,
1532 t_commrec *cr, gmx_domdec_t *dd,
1533 DdRankOrder gmx_unused rankOrder,
1534 bool gmx_unused reorder)
1536 gmx_domdec_comm_t *comm;
1537 int i;
1538 gmx_bool bDiv[DIM];
1539 #if GMX_MPI
1540 MPI_Comm comm_cart;
1541 #endif
1543 comm = dd->comm;
1545 if (comm->bCartesianPP)
1547 for (i = 1; i < DIM; i++)
1549 bDiv[i] = ((cr->npmenodes*dd->nc[i]) % (dd->nnodes) == 0);
1551 if (bDiv[YY] || bDiv[ZZ])
1553 comm->bCartesianPP_PME = TRUE;
1554 /* If we have 2D PME decomposition, which is always in x+y,
1555 * we stack the PME only nodes in z.
1556 * Otherwise we choose the direction that provides the thinnest slab
1557 * of PME only nodes as this will have the least effect
1558 * on the PP communication.
1559 * But for the PME communication the opposite might be better.
1561 if (bDiv[ZZ] && (comm->npmenodes_y > 1 ||
1562 !bDiv[YY] ||
1563 dd->nc[YY] > dd->nc[ZZ]))
1565 comm->cartpmedim = ZZ;
1567 else
1569 comm->cartpmedim = YY;
1571 comm->ntot[comm->cartpmedim]
1572 += (cr->npmenodes*dd->nc[comm->cartpmedim])/dd->nnodes;
1574 else
1576 GMX_LOG(mdlog.info).appendTextFormatted(
1577 "Number of PME-only ranks (%d) is not a multiple of nx*ny (%d*%d) or nx*nz (%d*%d)",
1578 cr->npmenodes, dd->nc[XX], dd->nc[YY], dd->nc[XX], dd->nc[ZZ]);
1579 GMX_LOG(mdlog.info).appendText("Will not use a Cartesian communicator for PP <-> PME\n");
1583 if (comm->bCartesianPP_PME)
1585 #if GMX_MPI
1586 int rank;
1587 ivec periods;
1589 GMX_LOG(mdlog.info).appendTextFormatted(
1590 "Will use a Cartesian communicator for PP <-> PME: %d x %d x %d",
1591 comm->ntot[XX], comm->ntot[YY], comm->ntot[ZZ]);
1593 for (i = 0; i < DIM; i++)
1595 periods[i] = TRUE;
1597 MPI_Cart_create(cr->mpi_comm_mysim, DIM, comm->ntot, periods, static_cast<int>(reorder),
1598 &comm_cart);
1599 MPI_Comm_rank(comm_cart, &rank);
1600 if (MASTER(cr) && rank != 0)
1602 gmx_fatal(FARGS, "MPI rank 0 was renumbered by MPI_Cart_create, we do not allow this");
1605 /* With this assigment we loose the link to the original communicator
1606 * which will usually be MPI_COMM_WORLD, unless have multisim.
1608 cr->mpi_comm_mysim = comm_cart;
1609 cr->sim_nodeid = rank;
1611 MPI_Cart_coords(cr->mpi_comm_mysim, cr->sim_nodeid, DIM, dd->ci);
1613 GMX_LOG(mdlog.info).appendTextFormatted(
1614 "Cartesian rank %d, coordinates %d %d %d\n",
1615 cr->sim_nodeid, dd->ci[XX], dd->ci[YY], dd->ci[ZZ]);
1617 if (dd->ci[comm->cartpmedim] < dd->nc[comm->cartpmedim])
1619 cr->duty = DUTY_PP;
1621 if (cr->npmenodes == 0 ||
1622 dd->ci[comm->cartpmedim] >= dd->nc[comm->cartpmedim])
1624 cr->duty = DUTY_PME;
1627 /* Split the sim communicator into PP and PME only nodes */
1628 MPI_Comm_split(cr->mpi_comm_mysim,
1629 getThisRankDuties(cr),
1630 dd_index(comm->ntot, dd->ci),
1631 &cr->mpi_comm_mygroup);
1632 #endif
1634 else
1636 switch (rankOrder)
1638 case DdRankOrder::pp_pme:
1639 GMX_LOG(mdlog.info).appendText("Order of the ranks: PP first, PME last");
1640 break;
1641 case DdRankOrder::interleave:
1642 /* Interleave the PP-only and PME-only ranks */
1643 GMX_LOG(mdlog.info).appendText("Interleaving PP and PME ranks");
1644 comm->pmenodes = dd_interleaved_pme_ranks(dd);
1645 break;
1646 case DdRankOrder::cartesian:
1647 break;
1648 default:
1649 gmx_fatal(FARGS, "Invalid ddRankOrder=%d", static_cast<int>(rankOrder));
1652 if (dd_simnode2pmenode(dd, cr, cr->sim_nodeid) == -1)
1654 cr->duty = DUTY_PME;
1656 else
1658 cr->duty = DUTY_PP;
1660 #if GMX_MPI
1661 /* Split the sim communicator into PP and PME only nodes */
1662 MPI_Comm_split(cr->mpi_comm_mysim,
1663 getThisRankDuties(cr),
1664 cr->nodeid,
1665 &cr->mpi_comm_mygroup);
1666 MPI_Comm_rank(cr->mpi_comm_mygroup, &cr->nodeid);
1667 #endif
1670 GMX_LOG(mdlog.info).appendTextFormatted(
1671 "This rank does only %s work.\n",
1672 thisRankHasDuty(cr, DUTY_PP) ? "particle-particle" : "PME-mesh");
1675 /*! \brief Generates the MPI communicators for domain decomposition */
1676 static void make_dd_communicators(const gmx::MDLogger &mdlog,
1677 t_commrec *cr,
1678 gmx_domdec_t *dd, DdRankOrder ddRankOrder)
1680 gmx_domdec_comm_t *comm;
1681 bool CartReorder;
1683 comm = dd->comm;
1685 copy_ivec(dd->nc, comm->ntot);
1687 comm->bCartesianPP = (ddRankOrder == DdRankOrder::cartesian);
1688 comm->bCartesianPP_PME = FALSE;
1690 /* Reorder the nodes by default. This might change the MPI ranks.
1691 * Real reordering is only supported on very few architectures,
1692 * Blue Gene is one of them.
1694 CartReorder = getenv("GMX_NO_CART_REORDER") == nullptr;
1696 if (cr->npmenodes > 0)
1698 /* Split the communicator into a PP and PME part */
1699 split_communicator(mdlog, cr, dd, ddRankOrder, CartReorder);
1700 if (comm->bCartesianPP_PME)
1702 /* We (possibly) reordered the nodes in split_communicator,
1703 * so it is no longer required in make_pp_communicator.
1705 CartReorder = FALSE;
1708 else
1710 /* All nodes do PP and PME */
1711 #if GMX_MPI
1712 /* We do not require separate communicators */
1713 cr->mpi_comm_mygroup = cr->mpi_comm_mysim;
1714 #endif
1717 if (thisRankHasDuty(cr, DUTY_PP))
1719 /* Copy or make a new PP communicator */
1720 make_pp_communicator(mdlog, dd, cr, CartReorder);
1722 else
1724 receive_ddindex2simnodeid(dd, cr);
1727 if (!thisRankHasDuty(cr, DUTY_PME))
1729 /* Set up the commnuication to our PME node */
1730 dd->pme_nodeid = dd_simnode2pmenode(dd, cr, cr->sim_nodeid);
1731 dd->pme_receive_vir_ener = receive_vir_ener(dd, cr);
1732 if (debug)
1734 fprintf(debug, "My pme_nodeid %d receive ener %s\n",
1735 dd->pme_nodeid, gmx::boolToString(dd->pme_receive_vir_ener));
1738 else
1740 dd->pme_nodeid = -1;
1743 /* We can not use DDMASTER(dd), because dd->masterrank is set later */
1744 if (MASTER(cr))
1746 dd->ma = std::make_unique<AtomDistribution>(dd->nc,
1747 comm->cgs_gl.nr,
1748 comm->cgs_gl.index[comm->cgs_gl.nr]);
1752 static real *get_slb_frac(const gmx::MDLogger &mdlog,
1753 const char *dir, int nc, const char *size_string)
1755 real *slb_frac, tot;
1756 int i, n;
1757 double dbl;
1759 slb_frac = nullptr;
1760 if (nc > 1 && size_string != nullptr)
1762 GMX_LOG(mdlog.info).appendTextFormatted(
1763 "Using static load balancing for the %s direction", dir);
1764 snew(slb_frac, nc);
1765 tot = 0;
1766 for (i = 0; i < nc; i++)
1768 dbl = 0;
1769 sscanf(size_string, "%20lf%n", &dbl, &n);
1770 if (dbl == 0)
1772 gmx_fatal(FARGS, "Incorrect or not enough DD cell size entries for direction %s: '%s'", dir, size_string);
1774 slb_frac[i] = dbl;
1775 size_string += n;
1776 tot += slb_frac[i];
1778 /* Normalize */
1779 std::string relativeCellSizes = "Relative cell sizes:";
1780 for (i = 0; i < nc; i++)
1782 slb_frac[i] /= tot;
1783 relativeCellSizes += gmx::formatString(" %5.3f", slb_frac[i]);
1785 GMX_LOG(mdlog.info).appendText(relativeCellSizes);
1788 return slb_frac;
1791 static int multi_body_bondeds_count(const gmx_mtop_t *mtop)
1793 int n = 0;
1794 gmx_mtop_ilistloop_t iloop = gmx_mtop_ilistloop_init(mtop);
1795 int nmol;
1796 while (const InteractionLists *ilists = gmx_mtop_ilistloop_next(iloop, &nmol))
1798 for (auto &ilist : extractILists(*ilists, IF_BOND))
1800 if (NRAL(ilist.functionType) > 2)
1802 n += nmol*(ilist.iatoms.size()/ilistStride(ilist));
1807 return n;
1810 static int dd_getenv(const gmx::MDLogger &mdlog,
1811 const char *env_var, int def)
1813 char *val;
1814 int nst;
1816 nst = def;
1817 val = getenv(env_var);
1818 if (val)
1820 if (sscanf(val, "%20d", &nst) <= 0)
1822 nst = 1;
1824 GMX_LOG(mdlog.info).appendTextFormatted(
1825 "Found env.var. %s = %s, using value %d",
1826 env_var, val, nst);
1829 return nst;
1832 static void check_dd_restrictions(const gmx_domdec_t *dd,
1833 const t_inputrec *ir,
1834 const gmx::MDLogger &mdlog)
1836 if (ir->ePBC == epbcSCREW &&
1837 (dd->nc[XX] == 1 || dd->nc[YY] > 1 || dd->nc[ZZ] > 1))
1839 gmx_fatal(FARGS, "With pbc=%s can only do domain decomposition in the x-direction", epbc_names[ir->ePBC]);
1842 if (ir->ns_type == ensSIMPLE)
1844 gmx_fatal(FARGS, "Domain decomposition does not support simple neighbor searching, use grid searching or run with one MPI rank");
1847 if (ir->nstlist == 0)
1849 gmx_fatal(FARGS, "Domain decomposition does not work with nstlist=0");
1852 if (ir->comm_mode == ecmANGULAR && ir->ePBC != epbcNONE)
1854 GMX_LOG(mdlog.warning).appendText("comm-mode angular will give incorrect results when the comm group partially crosses a periodic boundary");
1858 static real average_cellsize_min(const gmx_ddbox_t &ddbox,
1859 const ivec numDomains)
1861 real r = ddbox.box_size[XX];
1862 for (int d = 0; d < DIM; d++)
1864 if (numDomains[d] > 1)
1866 /* Check using the initial average cell size */
1867 r = std::min(r, ddbox.box_size[d]*ddbox.skew_fac[d]/numDomains[d]);
1871 return r;
1874 /*! \brief Depending on the DLB initial value return the DLB switched off state or issue an error.
1876 static DlbState forceDlbOffOrBail(DlbState cmdlineDlbState,
1877 const std::string &reasonStr,
1878 const gmx::MDLogger &mdlog)
1880 std::string dlbNotSupportedErr = "Dynamic load balancing requested, but ";
1881 std::string dlbDisableNote = "NOTE: disabling dynamic load balancing as ";
1883 if (cmdlineDlbState == DlbState::onUser)
1885 gmx_fatal(FARGS, "%s", (dlbNotSupportedErr + reasonStr).c_str());
1887 else if (cmdlineDlbState == DlbState::offCanTurnOn)
1889 GMX_LOG(mdlog.info).appendText(dlbDisableNote + reasonStr);
1891 return DlbState::offForever;
1894 /*! \brief Return the dynamic load balancer's initial state based on initial conditions and user inputs.
1896 * This function parses the parameters of "-dlb" command line option setting
1897 * corresponding state values. Then it checks the consistency of the determined
1898 * state with other run parameters and settings. As a result, the initial state
1899 * may be altered or an error may be thrown if incompatibility of options is detected.
1901 * \param [in] mdlog Logger.
1902 * \param [in] dlbOption Enum value for the DLB option.
1903 * \param [in] bRecordLoad True if the load balancer is recording load information.
1904 * \param [in] mdrunOptions Options for mdrun.
1905 * \param [in] ir Pointer mdrun to input parameters.
1906 * \returns DLB initial/startup state.
1908 static DlbState determineInitialDlbState(const gmx::MDLogger &mdlog,
1909 DlbOption dlbOption, gmx_bool bRecordLoad,
1910 const gmx::MdrunOptions &mdrunOptions,
1911 const t_inputrec *ir)
1913 DlbState dlbState = DlbState::offCanTurnOn;
1915 switch (dlbOption)
1917 case DlbOption::turnOnWhenUseful: dlbState = DlbState::offCanTurnOn; break;
1918 case DlbOption::no: dlbState = DlbState::offUser; break;
1919 case DlbOption::yes: dlbState = DlbState::onUser; break;
1920 default: gmx_incons("Invalid dlbOption enum value");
1923 /* Reruns don't support DLB: bail or override auto mode */
1924 if (mdrunOptions.rerun)
1926 std::string reasonStr = "it is not supported in reruns.";
1927 return forceDlbOffOrBail(dlbState, reasonStr, mdlog);
1930 /* Unsupported integrators */
1931 if (!EI_DYNAMICS(ir->eI))
1933 auto reasonStr = gmx::formatString("it is only supported with dynamics, not with integrator '%s'.", EI(ir->eI));
1934 return forceDlbOffOrBail(dlbState, reasonStr, mdlog);
1937 /* Without cycle counters we can't time work to balance on */
1938 if (!bRecordLoad)
1940 std::string reasonStr = "cycle counters unsupported or not enabled in the operating system kernel.";
1941 return forceDlbOffOrBail(dlbState, reasonStr, mdlog);
1944 if (mdrunOptions.reproducible)
1946 std::string reasonStr = "you started a reproducible run.";
1947 switch (dlbState)
1949 case DlbState::offUser:
1950 break;
1951 case DlbState::offForever:
1952 GMX_RELEASE_ASSERT(false, "DlbState::offForever is not a valid initial state");
1953 break;
1954 case DlbState::offCanTurnOn:
1955 return forceDlbOffOrBail(dlbState, reasonStr, mdlog);
1956 case DlbState::onCanTurnOff:
1957 GMX_RELEASE_ASSERT(false, "DlbState::offCanTurnOff is not a valid initial state");
1958 break;
1959 case DlbState::onUser:
1960 return forceDlbOffOrBail(dlbState, reasonStr + " In load balanced runs binary reproducibility cannot be ensured.", mdlog);
1961 default:
1962 gmx_fatal(FARGS, "Death horror: undefined case (%d) for load balancing choice", static_cast<int>(dlbState));
1966 return dlbState;
1969 static void set_dd_dim(const gmx::MDLogger &mdlog, gmx_domdec_t *dd)
1971 dd->ndim = 0;
1972 if (getenv("GMX_DD_ORDER_ZYX") != nullptr)
1974 /* Decomposition order z,y,x */
1975 GMX_LOG(mdlog.info).appendText("Using domain decomposition order z, y, x");
1976 for (int dim = DIM-1; dim >= 0; dim--)
1978 if (dd->nc[dim] > 1)
1980 dd->dim[dd->ndim++] = dim;
1984 else
1986 /* Decomposition order x,y,z */
1987 for (int dim = 0; dim < DIM; dim++)
1989 if (dd->nc[dim] > 1)
1991 dd->dim[dd->ndim++] = dim;
1996 if (dd->ndim == 0)
1998 /* Set dim[0] to avoid extra checks on ndim in several places */
1999 dd->dim[0] = XX;
2003 static gmx_domdec_comm_t *init_dd_comm()
2005 gmx_domdec_comm_t *comm = new gmx_domdec_comm_t;
2007 comm->n_load_have = 0;
2008 comm->n_load_collect = 0;
2010 comm->haveTurnedOffDlb = false;
2012 for (int i = 0; i < static_cast<int>(DDAtomRanges::Type::Number); i++)
2014 comm->sum_nat[i] = 0;
2016 comm->ndecomp = 0;
2017 comm->nload = 0;
2018 comm->load_step = 0;
2019 comm->load_sum = 0;
2020 comm->load_max = 0;
2021 clear_ivec(comm->load_lim);
2022 comm->load_mdf = 0;
2023 comm->load_pme = 0;
2025 /* This should be replaced by a unique pointer */
2026 comm->balanceRegion = ddBalanceRegionAllocate();
2028 return comm;
2031 /* Returns whether mtop contains constraints and/or vsites */
2032 static bool systemHasConstraintsOrVsites(const gmx_mtop_t &mtop)
2034 auto ilistLoop = gmx_mtop_ilistloop_init(mtop);
2035 int nmol;
2036 while (const InteractionLists *ilists = gmx_mtop_ilistloop_next(ilistLoop, &nmol))
2038 if (!extractILists(*ilists, IF_CONSTRAINT | IF_VSITE).empty())
2040 return true;
2044 return false;
2047 static void setupUpdateGroups(const gmx::MDLogger &mdlog,
2048 const gmx_mtop_t &mtop,
2049 const t_inputrec &inputrec,
2050 const real cutoffMargin,
2051 DDSystemInfo *systemInfo)
2053 /* When we have constraints and/or vsites, it is beneficial to use
2054 * update groups (when possible) to allow independent update of groups.
2056 if (!systemHasConstraintsOrVsites(mtop))
2058 /* No constraints or vsites, atoms can be updated independently */
2059 return;
2062 systemInfo->updateGroupingPerMoleculetype = gmx::makeUpdateGroups(mtop);
2063 systemInfo->useUpdateGroups =
2064 (!systemInfo->updateGroupingPerMoleculetype.empty() &&
2065 getenv("GMX_NO_UPDATEGROUPS") == nullptr);
2067 if (systemInfo->useUpdateGroups)
2069 int numUpdateGroups = 0;
2070 for (const auto &molblock : mtop.molblock)
2072 numUpdateGroups += molblock.nmol*systemInfo->updateGroupingPerMoleculetype[molblock.type].numBlocks();
2075 systemInfo->maxUpdateGroupRadius =
2076 computeMaxUpdateGroupRadius(mtop,
2077 systemInfo->updateGroupingPerMoleculetype,
2078 maxReferenceTemperature(inputrec));
2080 /* To use update groups, the large domain-to-domain cutoff distance
2081 * should be compatible with the box size.
2083 systemInfo->useUpdateGroups = (atomToAtomIntoDomainToDomainCutoff(*systemInfo, 0) < cutoffMargin);
2085 if (systemInfo->useUpdateGroups)
2087 GMX_LOG(mdlog.info).appendTextFormatted(
2088 "Using update groups, nr %d, average size %.1f atoms, max. radius %.3f nm\n",
2089 numUpdateGroups,
2090 mtop.natoms/static_cast<double>(numUpdateGroups),
2091 systemInfo->maxUpdateGroupRadius);
2093 else
2095 GMX_LOG(mdlog.info).appendTextFormatted("The combination of rlist and box size prohibits the use of update groups\n");
2096 systemInfo->updateGroupingPerMoleculetype.clear();
2101 UnitCellInfo::UnitCellInfo(const t_inputrec &ir) :
2102 npbcdim(ePBC2npbcdim(ir.ePBC)),
2103 numBoundedDimensions(inputrec2nboundeddim(&ir)),
2104 ddBoxIsDynamic(numBoundedDimensions < DIM || inputrecDynamicBox(&ir)),
2105 haveScrewPBC(ir.ePBC == epbcSCREW)
2109 /*! \brief Set the cell size and interaction limits, as well as the DD grid */
2110 static void set_dd_limits_and_grid(const gmx::MDLogger &mdlog,
2111 t_commrec *cr, gmx_domdec_t *dd,
2112 const DomdecOptions &options,
2113 const gmx::MdrunOptions &mdrunOptions,
2114 const gmx_mtop_t *mtop,
2115 const t_inputrec *ir,
2116 const matrix box,
2117 gmx::ArrayRef<const gmx::RVec> xGlobal,
2118 gmx_ddbox_t *ddbox)
2120 real r_bonded = -1;
2121 real r_bonded_limit = -1;
2122 const real tenPercentMargin = 1.1;
2123 gmx_domdec_comm_t *comm = dd->comm;
2125 /* Initialize to GPU share count to 0, might change later */
2126 comm->nrank_gpu_shared = 0;
2128 comm->dlbState = determineInitialDlbState(mdlog, options.dlbOption, comm->bRecordLoad, mdrunOptions, ir);
2129 dd_dlb_set_should_check_whether_to_turn_dlb_on(dd, TRUE);
2130 /* To consider turning DLB on after 2*nstlist steps we need to check
2131 * at partitioning count 3. Thus we need to increase the first count by 2.
2133 comm->ddPartioningCountFirstDlbOff += 2;
2135 GMX_LOG(mdlog.info).appendTextFormatted(
2136 "Dynamic load balancing: %s", edlbs_names[int(comm->dlbState)]);
2138 comm->bPMELoadBalDLBLimits = FALSE;
2140 /* Allocate the charge group/atom sorting struct */
2141 comm->sort = std::make_unique<gmx_domdec_sort_t>();
2143 /* Generate the simulation system information */
2144 DDSystemInfo &systemInfo = comm->systemInfo;
2146 /* We need to decide on update groups early, as this affects communication distances */
2147 systemInfo.useUpdateGroups = false;
2148 if (ir->cutoff_scheme == ecutsVERLET)
2150 real cutoffMargin = std::sqrt(max_cutoff2(ir->ePBC, box)) - ir->rlist;
2151 setupUpdateGroups(mdlog, *mtop, *ir, cutoffMargin, &systemInfo);
2153 if (systemInfo.useUpdateGroups)
2155 /* Note: We would like to use dd->nnodes for the atom count estimate,
2156 * but that is not yet available here. But this anyhow only
2157 * affect performance up to the second dd_partition_system call.
2159 const int homeAtomCountEstimate = mtop->natoms/cr->nnodes;
2160 comm->updateGroupsCog =
2161 std::make_unique<gmx::UpdateGroupsCog>(*mtop,
2162 systemInfo.updateGroupingPerMoleculetype,
2163 maxReferenceTemperature(*ir),
2164 homeAtomCountEstimate);
2168 // TODO: Check whether all bondeds are within update groups
2169 systemInfo.haveInterDomainBondeds = (mtop->natoms > gmx_mtop_num_molecules(*mtop) ||
2170 mtop->bIntermolecularInteractions);
2171 systemInfo.haveInterDomainMultiBodyBondeds = (multi_body_bondeds_count(mtop) > 0);
2173 if (systemInfo.useUpdateGroups)
2175 systemInfo.haveSplitConstraints = false;
2176 systemInfo.haveSplitSettles = false;
2178 else
2180 systemInfo.haveSplitConstraints = gmx::inter_charge_group_constraints(*mtop);
2181 systemInfo.haveSplitSettles = gmx::inter_charge_group_settles(*mtop);
2184 if (ir->rlist == 0)
2186 /* Set the cut-off to some very large value,
2187 * so we don't need if statements everywhere in the code.
2188 * We use sqrt, since the cut-off is squared in some places.
2190 systemInfo.cutoff = GMX_CUTOFF_INF;
2192 else
2194 systemInfo.cutoff = atomToAtomIntoDomainToDomainCutoff(systemInfo, ir->rlist);
2196 systemInfo.minCutoffForMultiBody = 0;
2198 /* Determine the minimum cell size limit, affected by many factors */
2199 systemInfo.cellsizeLimit = 0;
2200 systemInfo.filterBondedCommunication = false;
2202 /* We do not allow home atoms to move beyond the neighboring domain
2203 * between domain decomposition steps, which limits the cell size.
2204 * Get an estimate of cell size limit due to atom displacement.
2205 * In most cases this is a large overestimate, because it assumes
2206 * non-interaction atoms.
2207 * We set the chance to 1 in a trillion steps.
2209 constexpr real c_chanceThatAtomMovesBeyondDomain = 1e-12;
2210 const real limitForAtomDisplacement =
2211 minCellSizeForAtomDisplacement(*mtop, *ir,
2212 systemInfo.updateGroupingPerMoleculetype,
2213 c_chanceThatAtomMovesBeyondDomain);
2214 GMX_LOG(mdlog.info).appendTextFormatted(
2215 "Minimum cell size due to atom displacement: %.3f nm",
2216 limitForAtomDisplacement);
2218 systemInfo.cellsizeLimit = std::max(systemInfo.cellsizeLimit,
2219 limitForAtomDisplacement);
2221 /* TODO: PME decomposition currently requires atoms not to be more than
2222 * 2/3 of comm->cutoff, which is >=rlist, outside of their domain.
2223 * In nearly all cases, limitForAtomDisplacement will be smaller
2224 * than 2/3*rlist, so the PME requirement is satisfied.
2225 * But it would be better for both correctness and performance
2226 * to use limitForAtomDisplacement instead of 2/3*comm->cutoff.
2227 * Note that we would need to improve the pairlist buffer case.
2230 if (systemInfo.haveInterDomainBondeds)
2232 if (options.minimumCommunicationRange > 0)
2234 systemInfo.minCutoffForMultiBody =
2235 atomToAtomIntoDomainToDomainCutoff(systemInfo, options.minimumCommunicationRange);
2236 if (options.useBondedCommunication)
2238 systemInfo.filterBondedCommunication = (systemInfo.minCutoffForMultiBody > systemInfo.cutoff);
2240 else
2242 systemInfo.cutoff = std::max(systemInfo.cutoff,
2243 systemInfo.minCutoffForMultiBody);
2245 r_bonded_limit = systemInfo.minCutoffForMultiBody;
2247 else if (ir->bPeriodicMols)
2249 /* Can not easily determine the required cut-off */
2250 GMX_LOG(mdlog.warning).appendText("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.");
2251 systemInfo.minCutoffForMultiBody = systemInfo.cutoff/2;
2252 r_bonded_limit = systemInfo.minCutoffForMultiBody;
2254 else
2256 real r_2b, r_mb;
2258 if (MASTER(cr))
2260 dd_bonded_cg_distance(mdlog, mtop, ir, as_rvec_array(xGlobal.data()), box,
2261 options.checkBondedInteractions,
2262 &r_2b, &r_mb);
2264 gmx_bcast(sizeof(r_2b), &r_2b, cr);
2265 gmx_bcast(sizeof(r_mb), &r_mb, cr);
2267 /* We use an initial margin of 10% for the minimum cell size,
2268 * except when we are just below the non-bonded cut-off.
2270 if (options.useBondedCommunication)
2272 if (std::max(r_2b, r_mb) > comm->systemInfo.cutoff)
2274 r_bonded = std::max(r_2b, r_mb);
2275 r_bonded_limit = tenPercentMargin*r_bonded;
2276 /* This is the (only) place where we turn on the filtering */
2277 systemInfo.filterBondedCommunication = true;
2279 else
2281 r_bonded = r_mb;
2282 r_bonded_limit = std::min(tenPercentMargin*r_bonded, systemInfo.cutoff);
2284 /* We determine cutoff_mbody later */
2286 else
2288 /* No special bonded communication,
2289 * simply increase the DD cut-off.
2291 r_bonded_limit = tenPercentMargin*std::max(r_2b, r_mb);
2292 systemInfo.minCutoffForMultiBody = r_bonded_limit;
2293 systemInfo.cutoff = std::max(systemInfo.cutoff,
2294 systemInfo.minCutoffForMultiBody);
2297 GMX_LOG(mdlog.info).appendTextFormatted(
2298 "Minimum cell size due to bonded interactions: %.3f nm",
2299 r_bonded_limit);
2301 systemInfo.cellsizeLimit = std::max(systemInfo.cellsizeLimit, r_bonded_limit);
2304 real rconstr = 0;
2305 if (systemInfo.haveSplitConstraints && options.constraintCommunicationRange <= 0)
2307 /* There is a cell size limit due to the constraints (P-LINCS) */
2308 rconstr = gmx::constr_r_max(mdlog, mtop, ir);
2309 GMX_LOG(mdlog.info).appendTextFormatted(
2310 "Estimated maximum distance required for P-LINCS: %.3f nm",
2311 rconstr);
2312 if (rconstr > systemInfo.cellsizeLimit)
2314 GMX_LOG(mdlog.info).appendText("This distance will limit the DD cell size, you can override this with -rcon");
2317 else if (options.constraintCommunicationRange > 0)
2319 /* Here we do not check for dd->splitConstraints.
2320 * because one can also set a cell size limit for virtual sites only
2321 * and at this point we don't know yet if there are intercg v-sites.
2323 GMX_LOG(mdlog.info).appendTextFormatted(
2324 "User supplied maximum distance required for P-LINCS: %.3f nm",
2325 options.constraintCommunicationRange);
2326 rconstr = options.constraintCommunicationRange;
2328 systemInfo.cellsizeLimit = std::max(systemInfo.cellsizeLimit, rconstr);
2330 comm->cgs_gl = gmx_mtop_global_cgs(mtop);
2332 DDSetup ddSetup;
2333 if (options.numCells[XX] > 0)
2335 copy_ivec(options.numCells, ddSetup.numDomains);
2336 set_ddbox_cr(*cr, &ddSetup.numDomains, *ir, box, xGlobal, ddbox);
2338 if (options.numPmeRanks >= 0)
2340 ddSetup.numPmeRanks = options.numPmeRanks;
2342 else
2344 /* When the DD grid is set explicitly and -npme is set to auto,
2345 * don't use PME ranks. We check later if the DD grid is
2346 * compatible with the total number of ranks.
2348 ddSetup.numPmeRanks = 0;
2351 else
2353 set_ddbox_cr(*cr, nullptr, *ir, box, xGlobal, ddbox);
2355 /* We need to choose the optimal DD grid and possibly PME nodes */
2356 ddSetup =
2357 dd_choose_grid(mdlog, cr, ir, mtop, box, ddbox,
2358 options.numPmeRanks,
2359 !isDlbDisabled(comm),
2360 options.dlbScaling,
2361 systemInfo);
2363 if (ddSetup.numDomains[XX] == 0)
2365 char buf[STRLEN];
2366 gmx_bool bC = (systemInfo.haveSplitConstraints && rconstr > r_bonded_limit);
2367 sprintf(buf, "Change the number of ranks or mdrun option %s%s%s",
2368 !bC ? "-rdd" : "-rcon",
2369 comm->dlbState != DlbState::offUser ? " or -dds" : "",
2370 bC ? " or your LINCS settings" : "");
2372 gmx_fatal_collective(FARGS, cr->mpi_comm_mysim, MASTER(cr),
2373 "There is no domain decomposition for %d ranks that is compatible with the given box and a minimum cell size of %g nm\n"
2374 "%s\n"
2375 "Look in the log file for details on the domain decomposition",
2376 cr->nnodes - ddSetup.numPmeRanks,
2377 ddSetup.cellsizeLimit,
2378 buf);
2382 const real acs = average_cellsize_min(*ddbox, ddSetup.numDomains);
2383 if (acs < systemInfo.cellsizeLimit)
2385 if (options.numCells[XX] <= 0)
2387 GMX_RELEASE_ASSERT(false, "dd_choose_grid() should return a grid that satisfies the cell size limits");
2389 else
2391 gmx_fatal_collective(FARGS, cr->mpi_comm_mysim, MASTER(cr),
2392 "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",
2393 acs, systemInfo.cellsizeLimit);
2397 /* Set the DD setup given by ddSetup */
2398 cr->npmenodes = ddSetup.numPmeRanks;
2399 copy_ivec(ddSetup.numDomains, dd->nc);
2400 set_dd_dim(mdlog, dd);
2402 GMX_LOG(mdlog.info).appendTextFormatted(
2403 "Domain decomposition grid %d x %d x %d, separate PME ranks %d",
2404 dd->nc[XX], dd->nc[YY], dd->nc[ZZ], cr->npmenodes);
2406 dd->nnodes = dd->nc[XX]*dd->nc[YY]*dd->nc[ZZ];
2407 if (cr->nnodes - dd->nnodes != cr->npmenodes)
2409 gmx_fatal_collective(FARGS, cr->mpi_comm_mysim, MASTER(cr),
2410 "The size of the domain decomposition grid (%d) does not match the number of ranks (%d). The total number of ranks is %d",
2411 dd->nnodes, cr->nnodes - cr->npmenodes, cr->nnodes);
2413 if (cr->npmenodes > dd->nnodes)
2415 gmx_fatal_collective(FARGS, cr->mpi_comm_mysim, MASTER(cr),
2416 "The number of separate PME ranks (%d) is larger than the number of PP ranks (%d), this is not supported.", cr->npmenodes, dd->nnodes);
2418 if (cr->npmenodes > 0)
2420 comm->npmenodes = cr->npmenodes;
2422 else
2424 comm->npmenodes = dd->nnodes;
2427 if (EEL_PME(ir->coulombtype) || EVDW_PME(ir->vdwtype))
2429 /* The following choices should match those
2430 * in comm_cost_est in domdec_setup.c.
2431 * Note that here the checks have to take into account
2432 * that the decomposition might occur in a different order than xyz
2433 * (for instance through the env.var. GMX_DD_ORDER_ZYX),
2434 * in which case they will not match those in comm_cost_est,
2435 * but since that is mainly for testing purposes that's fine.
2437 if (dd->ndim >= 2 && dd->dim[0] == XX && dd->dim[1] == YY &&
2438 comm->npmenodes > dd->nc[XX] && comm->npmenodes % dd->nc[XX] == 0 &&
2439 getenv("GMX_PMEONEDD") == nullptr)
2441 comm->npmedecompdim = 2;
2442 comm->npmenodes_x = dd->nc[XX];
2443 comm->npmenodes_y = comm->npmenodes/comm->npmenodes_x;
2445 else
2447 /* In case nc is 1 in both x and y we could still choose to
2448 * decompose pme in y instead of x, but we use x for simplicity.
2450 comm->npmedecompdim = 1;
2451 if (dd->dim[0] == YY)
2453 comm->npmenodes_x = 1;
2454 comm->npmenodes_y = comm->npmenodes;
2456 else
2458 comm->npmenodes_x = comm->npmenodes;
2459 comm->npmenodes_y = 1;
2462 GMX_LOG(mdlog.info).appendTextFormatted(
2463 "PME domain decomposition: %d x %d x %d",
2464 comm->npmenodes_x, comm->npmenodes_y, 1);
2466 else
2468 comm->npmedecompdim = 0;
2469 comm->npmenodes_x = 0;
2470 comm->npmenodes_y = 0;
2473 snew(comm->slb_frac, DIM);
2474 if (isDlbDisabled(comm))
2476 comm->slb_frac[XX] = get_slb_frac(mdlog, "x", dd->nc[XX], options.cellSizeX);
2477 comm->slb_frac[YY] = get_slb_frac(mdlog, "y", dd->nc[YY], options.cellSizeY);
2478 comm->slb_frac[ZZ] = get_slb_frac(mdlog, "z", dd->nc[ZZ], options.cellSizeZ);
2481 /* Set the multi-body cut-off and cellsize limit for DLB */
2482 comm->cutoff_mbody = systemInfo.minCutoffForMultiBody;
2483 comm->cellsize_limit = systemInfo.cellsizeLimit;
2484 if (systemInfo.haveInterDomainBondeds && comm->cutoff_mbody == 0)
2486 if (systemInfo.filterBondedCommunication || !isDlbDisabled(comm))
2488 /* Set the bonded communication distance to halfway
2489 * the minimum and the maximum,
2490 * since the extra communication cost is nearly zero.
2492 real acs = average_cellsize_min(*ddbox, dd->nc);
2493 comm->cutoff_mbody = 0.5*(r_bonded + acs);
2494 if (!isDlbDisabled(comm))
2496 /* Check if this does not limit the scaling */
2497 comm->cutoff_mbody = std::min(comm->cutoff_mbody,
2498 options.dlbScaling*acs);
2500 if (!systemInfo.filterBondedCommunication)
2502 /* Without bBondComm do not go beyond the n.b. cut-off */
2503 comm->cutoff_mbody = std::min(comm->cutoff_mbody, systemInfo.cutoff);
2504 if (comm->cellsize_limit >= systemInfo.cutoff)
2506 /* We don't loose a lot of efficieny
2507 * when increasing it to the n.b. cut-off.
2508 * It can even be slightly faster, because we need
2509 * less checks for the communication setup.
2511 comm->cutoff_mbody = systemInfo.cutoff;
2514 /* Check if we did not end up below our original limit */
2515 comm->cutoff_mbody = std::max(comm->cutoff_mbody, r_bonded_limit);
2517 if (comm->cutoff_mbody > comm->cellsize_limit)
2519 comm->cellsize_limit = comm->cutoff_mbody;
2522 /* Without DLB and cutoff_mbody<cutoff, cutoff_mbody is dynamic */
2525 if (debug)
2527 fprintf(debug, "Bonded atom communication beyond the cut-off: %s\n"
2528 "cellsize limit %f\n",
2529 gmx::boolToString(systemInfo.filterBondedCommunication),
2530 comm->cellsize_limit);
2533 if (MASTER(cr))
2535 check_dd_restrictions(dd, ir, mdlog);
2539 static char *init_bLocalCG(const gmx_mtop_t *mtop)
2541 int ncg, cg;
2542 char *bLocalCG;
2544 ncg = ncg_mtop(mtop);
2545 snew(bLocalCG, ncg);
2546 for (cg = 0; cg < ncg; cg++)
2548 bLocalCG[cg] = FALSE;
2551 return bLocalCG;
2554 void dd_init_bondeds(FILE *fplog,
2555 gmx_domdec_t *dd,
2556 const gmx_mtop_t *mtop,
2557 const gmx_vsite_t *vsite,
2558 const t_inputrec *ir,
2559 gmx_bool bBCheck, cginfo_mb_t *cginfo_mb)
2561 gmx_domdec_comm_t *comm;
2563 dd_make_reverse_top(fplog, dd, mtop, vsite, ir, bBCheck);
2565 comm = dd->comm;
2567 if (comm->systemInfo.filterBondedCommunication)
2569 /* Communicate atoms beyond the cut-off for bonded interactions */
2570 comm = dd->comm;
2572 comm->cglink = make_charge_group_links(mtop, dd, cginfo_mb);
2574 comm->bLocalCG = init_bLocalCG(mtop);
2576 else
2578 /* Only communicate atoms based on cut-off */
2579 comm->cglink = nullptr;
2580 comm->bLocalCG = nullptr;
2584 static void writeSettings(gmx::TextWriter *log,
2585 gmx_domdec_t *dd,
2586 const gmx_mtop_t *mtop,
2587 const t_inputrec *ir,
2588 gmx_bool bDynLoadBal,
2589 real dlb_scale,
2590 const gmx_ddbox_t *ddbox)
2592 gmx_domdec_comm_t *comm;
2593 int d;
2594 ivec np;
2595 real limit, shrink;
2597 comm = dd->comm;
2599 if (bDynLoadBal)
2601 log->writeString("The maximum number of communication pulses is:");
2602 for (d = 0; d < dd->ndim; d++)
2604 log->writeStringFormatted(" %c %d", dim2char(dd->dim[d]), comm->cd[d].np_dlb);
2606 log->ensureLineBreak();
2607 log->writeLineFormatted("The minimum size for domain decomposition cells is %.3f nm", comm->cellsize_limit);
2608 log->writeLineFormatted("The requested allowed shrink of DD cells (option -dds) is: %.2f", dlb_scale);
2609 log->writeString("The allowed shrink of domain decomposition cells is:");
2610 for (d = 0; d < DIM; d++)
2612 if (dd->nc[d] > 1)
2614 if (d >= ddbox->npbcdim && dd->nc[d] == 2)
2616 shrink = 0;
2618 else
2620 shrink =
2621 comm->cellsize_min_dlb[d]/
2622 (ddbox->box_size[d]*ddbox->skew_fac[d]/dd->nc[d]);
2624 log->writeStringFormatted(" %c %.2f", dim2char(d), shrink);
2627 log->ensureLineBreak();
2629 else
2631 set_dd_cell_sizes_slb(dd, ddbox, setcellsizeslbPULSE_ONLY, np);
2632 log->writeString("The initial number of communication pulses is:");
2633 for (d = 0; d < dd->ndim; d++)
2635 log->writeStringFormatted(" %c %d", dim2char(dd->dim[d]), np[dd->dim[d]]);
2637 log->ensureLineBreak();
2638 log->writeString("The initial domain decomposition cell size is:");
2639 for (d = 0; d < DIM; d++)
2641 if (dd->nc[d] > 1)
2643 log->writeStringFormatted(" %c %.2f nm",
2644 dim2char(d), dd->comm->cellsize_min[d]);
2647 log->ensureLineBreak();
2648 log->writeLine();
2651 const bool haveInterDomainVsites =
2652 (countInterUpdategroupVsites(*mtop, comm->systemInfo.updateGroupingPerMoleculetype) != 0);
2654 if (comm->systemInfo.haveInterDomainBondeds ||
2655 haveInterDomainVsites ||
2656 comm->systemInfo.haveSplitConstraints ||
2657 comm->systemInfo.haveSplitSettles)
2659 std::string decompUnits;
2660 if (comm->systemInfo.useUpdateGroups)
2662 decompUnits = "atom groups";
2664 else
2666 decompUnits = "atoms";
2669 log->writeLineFormatted("The maximum allowed distance for %s involved in interactions is:", decompUnits.c_str());
2670 log->writeLineFormatted("%40s %-7s %6.3f nm", "non-bonded interactions", "", comm->systemInfo.cutoff);
2672 if (bDynLoadBal)
2674 limit = dd->comm->cellsize_limit;
2676 else
2678 if (dd->unitCellInfo.ddBoxIsDynamic)
2680 log->writeLine("(the following are initial values, they could change due to box deformation)");
2682 limit = dd->comm->cellsize_min[XX];
2683 for (d = 1; d < DIM; d++)
2685 limit = std::min(limit, dd->comm->cellsize_min[d]);
2689 if (comm->systemInfo.haveInterDomainBondeds)
2691 log->writeLineFormatted("%40s %-7s %6.3f nm",
2692 "two-body bonded interactions", "(-rdd)",
2693 std::max(comm->systemInfo.cutoff, comm->cutoff_mbody));
2694 log->writeLineFormatted("%40s %-7s %6.3f nm",
2695 "multi-body bonded interactions", "(-rdd)",
2696 (comm->systemInfo.filterBondedCommunication || isDlbOn(dd->comm)) ? comm->cutoff_mbody : std::min(comm->systemInfo.cutoff, limit));
2698 if (haveInterDomainVsites)
2700 log->writeLineFormatted("%40s %-7s %6.3f nm",
2701 "virtual site constructions", "(-rcon)", limit);
2703 if (comm->systemInfo.haveSplitConstraints || comm->systemInfo.haveSplitSettles)
2705 std::string separation = gmx::formatString("atoms separated by up to %d constraints",
2706 1+ir->nProjOrder);
2707 log->writeLineFormatted("%40s %-7s %6.3f nm\n",
2708 separation.c_str(), "(-rcon)", limit);
2710 log->ensureLineBreak();
2714 static void logSettings(const gmx::MDLogger &mdlog,
2715 gmx_domdec_t *dd,
2716 const gmx_mtop_t *mtop,
2717 const t_inputrec *ir,
2718 real dlb_scale,
2719 const gmx_ddbox_t *ddbox)
2721 gmx::StringOutputStream stream;
2722 gmx::TextWriter log(&stream);
2723 writeSettings(&log, dd, mtop, ir, isDlbOn(dd->comm), dlb_scale, ddbox);
2724 if (dd->comm->dlbState == DlbState::offCanTurnOn)
2727 log.ensureEmptyLine();
2728 log.writeLine("When dynamic load balancing gets turned on, these settings will change to:");
2730 writeSettings(&log, dd, mtop, ir, true, dlb_scale, ddbox);
2732 GMX_LOG(mdlog.info).asParagraph().appendText(stream.toString());
2735 static void set_cell_limits_dlb(const gmx::MDLogger &mdlog,
2736 gmx_domdec_t *dd,
2737 real dlb_scale,
2738 const t_inputrec *ir,
2739 const gmx_ddbox_t *ddbox)
2741 gmx_domdec_comm_t *comm;
2742 int d, dim, npulse, npulse_d_max, npulse_d;
2743 gmx_bool bNoCutOff;
2745 comm = dd->comm;
2747 bNoCutOff = (ir->rvdw == 0 || ir->rcoulomb == 0);
2749 /* Determine the maximum number of comm. pulses in one dimension */
2751 comm->cellsize_limit = std::max(comm->cellsize_limit, comm->cutoff_mbody);
2753 /* Determine the maximum required number of grid pulses */
2754 if (comm->cellsize_limit >= comm->systemInfo.cutoff)
2756 /* Only a single pulse is required */
2757 npulse = 1;
2759 else if (!bNoCutOff && comm->cellsize_limit > 0)
2761 /* We round down slightly here to avoid overhead due to the latency
2762 * of extra communication calls when the cut-off
2763 * would be only slightly longer than the cell size.
2764 * Later cellsize_limit is redetermined,
2765 * so we can not miss interactions due to this rounding.
2767 npulse = static_cast<int>(0.96 + comm->systemInfo.cutoff/comm->cellsize_limit);
2769 else
2771 /* There is no cell size limit */
2772 npulse = std::max(dd->nc[XX]-1, std::max(dd->nc[YY]-1, dd->nc[ZZ]-1));
2775 if (!bNoCutOff && npulse > 1)
2777 /* See if we can do with less pulses, based on dlb_scale */
2778 npulse_d_max = 0;
2779 for (d = 0; d < dd->ndim; d++)
2781 dim = dd->dim[d];
2782 npulse_d = static_cast<int>(1 + dd->nc[dim]*comm->systemInfo.cutoff
2783 /(ddbox->box_size[dim]*ddbox->skew_fac[dim]*dlb_scale));
2784 npulse_d_max = std::max(npulse_d_max, npulse_d);
2786 npulse = std::min(npulse, npulse_d_max);
2789 /* This env var can override npulse */
2790 d = dd_getenv(mdlog, "GMX_DD_NPULSE", 0);
2791 if (d > 0)
2793 npulse = d;
2796 comm->maxpulse = 1;
2797 comm->bVacDLBNoLimit = (ir->ePBC == epbcNONE);
2798 for (d = 0; d < dd->ndim; d++)
2800 comm->cd[d].np_dlb = std::min(npulse, dd->nc[dd->dim[d]]-1);
2801 comm->maxpulse = std::max(comm->maxpulse, comm->cd[d].np_dlb);
2802 if (comm->cd[d].np_dlb < dd->nc[dd->dim[d]]-1)
2804 comm->bVacDLBNoLimit = FALSE;
2808 /* cellsize_limit is set for LINCS in init_domain_decomposition */
2809 if (!comm->bVacDLBNoLimit)
2811 comm->cellsize_limit = std::max(comm->cellsize_limit,
2812 comm->systemInfo.cutoff/comm->maxpulse);
2814 comm->cellsize_limit = std::max(comm->cellsize_limit, comm->cutoff_mbody);
2815 /* Set the minimum cell size for each DD dimension */
2816 for (d = 0; d < dd->ndim; d++)
2818 if (comm->bVacDLBNoLimit ||
2819 comm->cd[d].np_dlb*comm->cellsize_limit >= comm->systemInfo.cutoff)
2821 comm->cellsize_min_dlb[dd->dim[d]] = comm->cellsize_limit;
2823 else
2825 comm->cellsize_min_dlb[dd->dim[d]] =
2826 comm->systemInfo.cutoff/comm->cd[d].np_dlb;
2829 if (comm->cutoff_mbody <= 0)
2831 comm->cutoff_mbody = std::min(comm->systemInfo.cutoff, comm->cellsize_limit);
2833 if (isDlbOn(comm))
2835 set_dlb_limits(dd);
2839 gmx_bool dd_bonded_molpbc(const gmx_domdec_t *dd, int ePBC)
2841 /* If each molecule is a single charge group
2842 * or we use domain decomposition for each periodic dimension,
2843 * we do not need to take pbc into account for the bonded interactions.
2845 return (ePBC != epbcNONE && dd->comm->systemInfo.haveInterDomainBondeds &&
2846 !(dd->nc[XX] > 1 &&
2847 dd->nc[YY] > 1 &&
2848 (dd->nc[ZZ] > 1 || ePBC == epbcXY)));
2851 /*! \brief Sets grid size limits and PP-PME setup, prints settings to log */
2852 static void set_ddgrid_parameters(const gmx::MDLogger &mdlog,
2853 gmx_domdec_t *dd, real dlb_scale,
2854 const gmx_mtop_t *mtop, const t_inputrec *ir,
2855 const gmx_ddbox_t *ddbox)
2857 gmx_domdec_comm_t *comm;
2858 int natoms_tot;
2859 real vol_frac;
2861 comm = dd->comm;
2863 if (EEL_PME(ir->coulombtype) || EVDW_PME(ir->vdwtype))
2865 init_ddpme(dd, &comm->ddpme[0], 0);
2866 if (comm->npmedecompdim >= 2)
2868 init_ddpme(dd, &comm->ddpme[1], 1);
2871 else
2873 comm->npmenodes = 0;
2874 if (dd->pme_nodeid >= 0)
2876 gmx_fatal_collective(FARGS, dd->mpi_comm_all, DDMASTER(dd),
2877 "Can not have separate PME ranks without PME electrostatics");
2881 if (debug)
2883 fprintf(debug, "The DD cut-off is %f\n", comm->systemInfo.cutoff);
2885 if (!isDlbDisabled(comm))
2887 set_cell_limits_dlb(mdlog, dd, dlb_scale, ir, ddbox);
2890 logSettings(mdlog, dd, mtop, ir, dlb_scale, ddbox);
2892 if (ir->ePBC == epbcNONE)
2894 vol_frac = 1 - 1/static_cast<double>(dd->nnodes);
2896 else
2898 vol_frac =
2899 (1 + comm_box_frac(dd->nc, comm->systemInfo.cutoff, ddbox))/static_cast<double>(dd->nnodes);
2901 if (debug)
2903 fprintf(debug, "Volume fraction for all DD zones: %f\n", vol_frac);
2905 natoms_tot = comm->cgs_gl.index[comm->cgs_gl.nr];
2907 dd->ga2la = new gmx_ga2la_t(natoms_tot,
2908 static_cast<int>(vol_frac*natoms_tot));
2911 /*! \brief Set some important DD parameters that can be modified by env.vars */
2912 static void set_dd_envvar_options(const gmx::MDLogger &mdlog,
2913 gmx_domdec_t *dd, int rank_mysim)
2915 gmx_domdec_comm_t *comm = dd->comm;
2917 dd->bSendRecv2 = (dd_getenv(mdlog, "GMX_DD_USE_SENDRECV2", 0) != 0);
2918 comm->dlb_scale_lim = dd_getenv(mdlog, "GMX_DLB_MAX_BOX_SCALING", 10);
2919 comm->eFlop = dd_getenv(mdlog, "GMX_DLB_BASED_ON_FLOPS", 0);
2920 int recload = dd_getenv(mdlog, "GMX_DD_RECORD_LOAD", 1);
2921 comm->nstDDDump = dd_getenv(mdlog, "GMX_DD_NST_DUMP", 0);
2922 comm->nstDDDumpGrid = dd_getenv(mdlog, "GMX_DD_NST_DUMP_GRID", 0);
2923 comm->DD_debug = dd_getenv(mdlog, "GMX_DD_DEBUG", 0);
2925 if (dd->bSendRecv2)
2927 GMX_LOG(mdlog.info).appendText("Will use two sequential MPI_Sendrecv calls instead of two simultaneous non-blocking MPI_Irecv and MPI_Isend pairs for constraint and vsite communication");
2930 if (comm->eFlop)
2932 GMX_LOG(mdlog.info).appendText("Will load balance based on FLOP count");
2933 if (comm->eFlop > 1)
2935 srand(1 + rank_mysim);
2937 comm->bRecordLoad = TRUE;
2939 else
2941 comm->bRecordLoad = (wallcycle_have_counter() && recload > 0);
2945 gmx_domdec_t::gmx_domdec_t(const t_inputrec &ir) :
2946 unitCellInfo(ir)
2950 gmx_domdec_t *init_domain_decomposition(const gmx::MDLogger &mdlog,
2951 t_commrec *cr,
2952 const DomdecOptions &options,
2953 const gmx::MdrunOptions &mdrunOptions,
2954 const gmx_mtop_t *mtop,
2955 const t_inputrec *ir,
2956 const matrix box,
2957 gmx::ArrayRef<const gmx::RVec> xGlobal,
2958 gmx::LocalAtomSetManager *atomSets)
2960 gmx_domdec_t *dd;
2962 GMX_LOG(mdlog.info).appendTextFormatted(
2963 "\nInitializing Domain Decomposition on %d ranks", cr->nnodes);
2965 dd = new gmx_domdec_t(*ir);
2967 dd->comm = init_dd_comm();
2969 set_dd_envvar_options(mdlog, dd, cr->nodeid);
2971 gmx_ddbox_t ddbox = {0};
2972 set_dd_limits_and_grid(mdlog, cr, dd, options, mdrunOptions,
2973 mtop, ir,
2974 box, xGlobal,
2975 &ddbox);
2977 make_dd_communicators(mdlog, cr, dd, options.rankOrder);
2979 if (thisRankHasDuty(cr, DUTY_PP))
2981 set_ddgrid_parameters(mdlog, dd, options.dlbScaling, mtop, ir, &ddbox);
2983 setup_neighbor_relations(dd);
2986 /* Set overallocation to avoid frequent reallocation of arrays */
2987 set_over_alloc_dd(TRUE);
2989 dd->atomSets = atomSets;
2991 return dd;
2994 static gmx_bool test_dd_cutoff(t_commrec *cr,
2995 const t_state &state,
2996 real cutoffRequested)
2998 gmx_domdec_t *dd;
2999 gmx_ddbox_t ddbox;
3000 int d, dim, np;
3001 real inv_cell_size;
3002 int LocallyLimited;
3004 dd = cr->dd;
3006 set_ddbox(*dd, false, state.box, true, state.x, &ddbox);
3008 LocallyLimited = 0;
3010 for (d = 0; d < dd->ndim; d++)
3012 dim = dd->dim[d];
3014 inv_cell_size = DD_CELL_MARGIN*dd->nc[dim]/ddbox.box_size[dim];
3015 if (dd->unitCellInfo.ddBoxIsDynamic)
3017 inv_cell_size *= DD_PRES_SCALE_MARGIN;
3020 np = 1 + static_cast<int>(cutoffRequested*inv_cell_size*ddbox.skew_fac[dim]);
3022 if (!isDlbDisabled(dd->comm) && (dim < ddbox.npbcdim) && (dd->comm->cd[d].np_dlb > 0))
3024 if (np > dd->comm->cd[d].np_dlb)
3026 return FALSE;
3029 /* If a current local cell size is smaller than the requested
3030 * cut-off, we could still fix it, but this gets very complicated.
3031 * Without fixing here, we might actually need more checks.
3033 real cellSizeAlongDim = (dd->comm->cell_x1[dim] - dd->comm->cell_x0[dim])*ddbox.skew_fac[dim];
3034 if (cellSizeAlongDim*dd->comm->cd[d].np_dlb < cutoffRequested)
3036 LocallyLimited = 1;
3041 if (!isDlbDisabled(dd->comm))
3043 /* If DLB is not active yet, we don't need to check the grid jumps.
3044 * Actually we shouldn't, because then the grid jump data is not set.
3046 if (isDlbOn(dd->comm) &&
3047 check_grid_jump(0, dd, cutoffRequested, &ddbox, FALSE))
3049 LocallyLimited = 1;
3052 gmx_sumi(1, &LocallyLimited, cr);
3054 if (LocallyLimited > 0)
3056 return FALSE;
3060 return TRUE;
3063 gmx_bool change_dd_cutoff(t_commrec *cr,
3064 const t_state &state,
3065 real cutoffRequested)
3067 gmx_bool bCutoffAllowed;
3069 bCutoffAllowed = test_dd_cutoff(cr, state, cutoffRequested);
3071 if (bCutoffAllowed)
3073 cr->dd->comm->systemInfo.cutoff = cutoffRequested;
3076 return bCutoffAllowed;