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.
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 */
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 */
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.
155 ddNonbondedZonePairRanges
[DD_MAXIZONE
][3] = {{0, 0, 8},
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
)
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
)
238 MPI_Cart_rank(dd
->mpi_comm_all
, c
, &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
)
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;
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
)
299 static void vec_rvec_check_alloc(vec_rvec_t
*v
, int n
)
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
)
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
;
337 zones
= &dd
->comm
->zones
;
340 while (icg
>= zones
->izone
[izone
].cg1
)
349 else if (izone
< zones
->nizone
)
351 *jcg0
= zones
->izone
[izone
].jcg0
;
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
++)
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 */
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
;
409 cgindex
= dd
->cgindex
;
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
);
421 copy_rvec(box
[dd
->dim
[d
]], shift
);
424 for (p
= 0; p
< cd
->np
; p
++)
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
]);
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
]);
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
++)
465 buf
[n
][XX
] = x
[j
][XX
] + shift
[XX
];
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
];
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]);
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
]);
501 nat_tot
+= ind
->nrecv
[nzone
+1];
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
;
521 gmx_bool bShiftForcesNeedPbc
, bScrew
;
525 cgindex
= dd
->cgindex
;
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 */
547 for (p
= cd
->np
-1; p
>= 0; p
--)
550 nat_tot
-= ind
->nrecv
[nzone
+1];
557 sbuf
= comm
->vbuf2
.v
;
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
]);
568 /* Communicate the forces */
569 dd_sendrecv_rvec(dd
, d
, dddirForward
,
570 sbuf
, ind
->nrecv
[nzone
+1],
571 buf
, ind
->nsend
[nzone
+1]);
573 /* Add the received forces */
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
]);
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
]);
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
];
620 /* Add this force to the shift force */
621 rvec_inc(fshift
[is
], buf
[n
]);
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
;
644 cgindex
= dd
->cgindex
;
646 buf
= &comm
->vbuf
.v
[0][0];
649 nat_tot
= dd
->nat_home
;
650 for (d
= 0; d
< dd
->ndim
; d
++)
653 for (p
= 0; p
< cd
->np
; p
++)
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
++)
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]);
684 for (zone
= 0; zone
< nzone
; zone
++)
686 for (i
= ind
->cell2at0
[zone
]; i
< ind
->cell2at1
[zone
]; i
++)
693 nat_tot
+= ind
->nrecv
[nzone
+1];
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
;
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
--)
719 for (p
= cd
->np
-1; p
>= 0; p
--)
722 nat_tot
-= ind
->nrecv
[nzone
+1];
729 sbuf
= &comm
->vbuf2
.v
[0][0];
731 for (zone
= 0; zone
< nzone
; zone
++)
733 for (i
= ind
->cell2at0
[zone
]; i
< ind
->cell2at1
[zone
]; i
++)
740 /* Communicate the forces */
741 dd_sendrecv_real(dd
, d
, dddirForward
,
742 sbuf
, ind
->nrecv
[nzone
+1],
743 buf
, ind
->nsend
[nzone
+1]);
745 /* Add the received forces */
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
++)
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",
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
];
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
,
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];
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
;
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];
826 real dist_d
, c
= 0, det
;
827 gmx_domdec_comm_t
*comm
;
832 for (d
= 1; d
< dd
->ndim
; 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
--)
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];
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];
867 /* Store the cell corner of the dimension we communicate along */
868 buf_s
[pos
].p1_0
= comm
->cell_x0
[dim
];
873 buf_s
[pos
] = (dd
->ndim
== 2) ? comm
->zone_d1
[0] : comm
->zone_d2
[0][0];
876 if (dd
->ndim
== 3 && d
== 0)
878 buf_s
[pos
] = comm
->zone_d2
[0][1];
880 buf_s
[pos
] = comm
->zone_d1
[0];
884 /* We only need to communicate the extremes
885 * in the forward direction
887 npulse
= comm
->cd
[d
].np
;
890 /* Take the minimum to avoid double communication */
891 npulse_min
= std::min(npulse
, dd
->nc
[dim
]-1-npulse
);
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.
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);
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]);
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
,
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
];
954 det
= (1 + c
*c
)*comm
->cutoff
*comm
->cutoff
- dist_d
*dist_d
;
957 dh
[d1
] = comm
->cutoff
- (c
*dist_d
+ std::sqrt(det
))/(1 + c
*c
);
961 /* A negative value signals out of range */
967 /* Accumulate the extremes over all pulses */
968 for (i
= 0; i
< buf_size
; i
++)
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)
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 */
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
);
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
];
1026 comm
->zone_d1
[1] = buf_e
[pos
];
1036 for (i
= 0; i
< 2; i
++)
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
);
1049 for (i
= 0; i
< 2; i
++)
1051 for (j
= 0; j
< 2; j
++)
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];
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 */
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
;
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.
1102 cgs_gl
= &dd
->comm
->cgs_gl
;
1104 ncg_home
= state_local
->cg_gl
.size();
1105 cg
= state_local
->cg_gl
.data();
1107 for (i
= 0; i
< ncg_home
; i
++)
1109 nat_home
+= cgs_gl
->index
[cg
[i
]+1] - cgs_gl
->index
[cg
[i
]];
1114 gmx_incons("Attempted to collect a vector for a state for which the charge group distribution is unknown");
1128 /* Collect the charge group and atom counts on the master */
1129 dd_gather(dd
, 2*sizeof(int), buf2
, ibuf
);
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);
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 */
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;
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
);
1188 /* Copy the master coordinates to the global array */
1189 cgs_gl
= &dd
->comm
->cgs_gl
;
1191 n
= DDMASTERRANK(dd
);
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
++)
1205 if (ma
->nat
[n
] > nalloc
)
1207 nalloc
= over_alloc_dd(ma
->nat
[n
]);
1208 srenew(buf
, nalloc
);
1211 MPI_Recv(buf
, ma
->nat
[n
]*sizeof(rvec
), MPI_BYTE
, DDRANK(dd
, n
),
1212 n
, dd
->mpi_comm_all
, MPI_STATUS_IGNORE
);
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
]);
1228 static void get_commbuffer_counts(gmx_domdec_t
*dd
,
1229 int **counts
, int **disps
)
1231 gmx_domdec_master_t
*ma
;
1236 /* Make the rvec count and displacment arrays */
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;
1253 rvec
*buf
= nullptr;
1260 get_commbuffer_counts(dd
, &rcounts
, &disps
);
1265 dd_gatherv(dd
, dd
->nat_home
*sizeof(rvec
), lv
.data(), rcounts
, disps
, buf
);
1269 cgs_gl
= &dd
->comm
->cgs_gl
;
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
);
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
;
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
)
1365 fprintf(debug
, "Resizing state: currently %d, required %d\n", state
->natoms
, natoms
);
1368 state_change_natoms(state
, natoms
);
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
,
1381 PaddedRVecVector
*f
,
1382 int numChargeGroups
)
1384 if (numChargeGroups
> fr
->cg_nalloc
)
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;
1417 for (n
= 0; n
< dd
->nnodes
; n
++)
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 */
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)",
1442 MPI_Send(buf
, ma
->nat
[n
]*sizeof(rvec
), MPI_BYTE
,
1443 DDRANK(dd
, n
), n
, dd
->mpi_comm_all
);
1448 n
= DDMASTERRANK(dd
);
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
++]);
1461 MPI_Recv(lv
, dd
->nat_home
*sizeof(rvec
), MPI_BYTE
, DDMASTERRANK(dd
),
1462 MPI_ANY_TAG
, dd
->mpi_comm_all
, MPI_STATUS_IGNORE
);
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;
1473 rvec
*buf
= nullptr;
1479 get_commbuffer_counts(dd
, &scounts
, &disps
);
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
);
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)
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
;
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
)
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
);
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];
1647 int a
, i
, d
, z
, y
, x
;
1651 copy_rvec(dd
->comm
->cell_x0
, grid_s
[0]);
1652 copy_rvec(dd
->comm
->cell_x1
, grid_s
[1]);
1656 snew(grid_r
, 2*dd
->nnodes
);
1659 dd_gather(dd
, 2*sizeof(rvec
), grid_s
, DDMASTER(dd
) ? grid_r
: nullptr);
1663 for (d
= 0; d
< DIM
; d
++)
1665 for (i
= 0; i
< DIM
; i
++)
1673 if (d
< ddbox
->npbcdim
&& dd
->nc
[d
] > 1)
1675 tric
[d
][i
] = box
[i
][d
]/box
[i
][i
];
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
);
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
];
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
++)
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
);
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
, rvec x
[], matrix box
)
1733 char fname
[STRLEN
], buf
[22];
1735 int i
, ii
, resnr
, c
;
1736 const char *atomname
, *resname
;
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
);
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
])
1760 while (i
>= dd
->cgindex
[dd
->comm
->zones
.cg_range
[c
+1]])
1766 else if (i
< dd
->comm
->nat
[ddnatVSITE
])
1768 b
= dd
->comm
->zones
.n
;
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
;
1791 if (comm
->bInterCGBondeds
)
1793 if (comm
->cutoff_mbody
> 0)
1795 r
= comm
->cutoff_mbody
;
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
);
1811 r
= std::min(r
, comm
->cutoff
);
1819 real
dd_cutoff_twobody(const gmx_domdec_t
*dd
)
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
,
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
)
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
)
1860 snew(pme_rank
, dd
->comm
->npmenodes
);
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
)
1870 fprintf(debug
, "pme_rank[%d] = %d\n", n
, i
+1+n
);
1872 pme_rank
[n
] = i
+ 1 + n
;
1880 static int gmx_ddcoord2pmeindex(const t_commrec
*cr
, int x
, int y
, int z
)
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];
1897 slab = (ddindex*cr->npmenodes + cr->npmenodes/2)/dd->nnodes;
1903 slab
= ddindex2pmeindex(dd
, dd_index(dd
->nc
, coords
));
1908 static int ddcoord2simnodeid(const t_commrec
*cr
, int x
, int y
, int z
)
1910 gmx_domdec_comm_t
*comm
;
1912 int ddindex
, nodeid
= -1;
1914 comm
= cr
->dd
->comm
;
1919 if (comm
->bCartesianPP_PME
)
1922 MPI_Cart_rank(cr
->mpi_comm_mysim
, coords
, &nodeid
);
1927 ddindex
= dd_index(cr
->dd
->nc
, coords
);
1928 if (comm
->bCartesianPP
)
1930 nodeid
= comm
->ddindex2simnodeid
[ddindex
];
1936 nodeid
= ddindex
+ gmx_ddcoord2pmeindex(cr
, x
, y
, z
);
1948 static int dd_simnode2pmenode(const gmx_domdec_t
*dd
,
1949 const t_commrec gmx_unused
*cr
,
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
)
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
);
1970 else if (comm
->bCartesianPP
)
1972 if (sim_nodeid
< dd
->nnodes
)
1974 pmenode
= dd
->nnodes
+ ddindex2pmeindex(dd
, sim_nodeid
);
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
);
1993 while (sim_nodeid
> dd
->comm
->pmenodes
[i
])
1997 if (sim_nodeid
< dd
->comm
->pmenodes
[i
])
1999 pmenode
= dd
->comm
->pmenodes
[i
];
2007 void get_pme_nnodes(const gmx_domdec_t
*dd
,
2008 int *npmenodes_x
, int *npmenodes_y
)
2012 *npmenodes_x
= dd
->comm
->npmenodes_x
;
2013 *npmenodes_y
= dd
->comm
->npmenodes_y
;
2022 std::vector
<int> get_pme_ddranks(const t_commrec
*cr
, int pmenodeid
)
2026 ivec coord
, coord_pme
;
2030 std::vector
<int> ddranks
;
2031 ddranks
.reserve((dd
->nnodes
+cr
->npmenodes
-1)/cr
->npmenodes
);
2033 for (x
= 0; x
< dd
->nc
[XX
]; x
++)
2035 for (y
= 0; y
< dd
->nc
[YY
]; y
++)
2037 for (z
= 0; z
< dd
->nc
[ZZ
]; z
++)
2039 if (dd
->comm
->bCartesianPP_PME
)
2044 dd_cart_coord2pmecoord(dd
, coord
, coord_pme
);
2045 if (dd
->ci
[XX
] == coord_pme
[XX
] &&
2046 dd
->ci
[YY
] == coord_pme
[YY
] &&
2047 dd
->ci
[ZZ
] == coord_pme
[ZZ
])
2049 ddranks
.push_back(ddcoord2simnodeid(cr
, x
, y
, z
));
2054 /* The slab corresponds to the nodeid in the PME group */
2055 if (gmx_ddcoord2pmeindex(cr
, x
, y
, z
) == pmenodeid
)
2057 ddranks
.push_back(ddcoord2simnodeid(cr
, x
, y
, z
));
2066 static gmx_bool
receive_vir_ener(const gmx_domdec_t
*dd
, const t_commrec
*cr
)
2068 gmx_bool bReceive
= TRUE
;
2070 if (cr
->npmenodes
< dd
->nnodes
)
2072 gmx_domdec_comm_t
*comm
= dd
->comm
;
2073 if (comm
->bCartesianPP_PME
)
2076 int pmenode
= dd_simnode2pmenode(dd
, cr
, cr
->sim_nodeid
);
2078 MPI_Cart_coords(cr
->mpi_comm_mysim
, cr
->sim_nodeid
, DIM
, coords
);
2079 coords
[comm
->cartpmedim
]++;
2080 if (coords
[comm
->cartpmedim
] < dd
->nc
[comm
->cartpmedim
])
2083 MPI_Cart_rank(cr
->mpi_comm_mysim
, coords
, &rank
);
2084 if (dd_simnode2pmenode(dd
, cr
, rank
) == pmenode
)
2086 /* This is not the last PP node for pmenode */
2091 GMX_RELEASE_ASSERT(false, "Without MPI we should not have Cartesian PP-PME with #PMEnodes < #DDnodes");
2096 int pmenode
= dd_simnode2pmenode(dd
, cr
, cr
->sim_nodeid
);
2097 if (cr
->sim_nodeid
+1 < cr
->nnodes
&&
2098 dd_simnode2pmenode(dd
, cr
, cr
->sim_nodeid
+1) == pmenode
)
2100 /* This is not the last PP node for pmenode */
2109 static void set_zones_ncg_home(gmx_domdec_t
*dd
)
2111 gmx_domdec_zones_t
*zones
;
2114 zones
= &dd
->comm
->zones
;
2116 zones
->cg_range
[0] = 0;
2117 for (i
= 1; i
< zones
->n
+1; i
++)
2119 zones
->cg_range
[i
] = dd
->ncg_home
;
2121 /* zone_ncg1[0] should always be equal to ncg_home */
2122 dd
->comm
->zone_ncg1
[0] = dd
->ncg_home
;
2125 static void rebuild_cgindex(gmx_domdec_t
*dd
,
2126 const int *gcgs_index
, const t_state
*state
)
2128 int * gmx_restrict dd_cg_gl
= dd
->index_gl
;
2129 int * gmx_restrict cgindex
= dd
->cgindex
;
2132 /* Copy back the global charge group indices from state
2133 * and rebuild the local charge group to atom index.
2136 for (unsigned int i
= 0; i
< state
->cg_gl
.size(); i
++)
2139 int cg_gl
= state
->cg_gl
[i
];
2140 dd_cg_gl
[i
] = cg_gl
;
2141 nat
+= gcgs_index
[cg_gl
+1] - gcgs_index
[cg_gl
];
2143 cgindex
[state
->cg_gl
.size()] = nat
;
2145 dd
->ncg_home
= state
->cg_gl
.size();
2148 set_zones_ncg_home(dd
);
2151 static int ddcginfo(const cginfo_mb_t
*cginfo_mb
, int cg
)
2153 while (cg
>= cginfo_mb
->cg_end
)
2158 return cginfo_mb
->cginfo
[(cg
- cginfo_mb
->cg_start
) % cginfo_mb
->cg_mod
];
2161 static void dd_set_cginfo(int *index_gl
, int cg0
, int cg1
,
2162 t_forcerec
*fr
, char *bLocalCG
)
2164 cginfo_mb_t
*cginfo_mb
;
2170 cginfo_mb
= fr
->cginfo_mb
;
2171 cginfo
= fr
->cginfo
;
2173 for (cg
= cg0
; cg
< cg1
; cg
++)
2175 cginfo
[cg
] = ddcginfo(cginfo_mb
, index_gl
[cg
]);
2179 if (bLocalCG
!= nullptr)
2181 for (cg
= cg0
; cg
< cg1
; cg
++)
2183 bLocalCG
[index_gl
[cg
]] = TRUE
;
2188 static void make_dd_indices(gmx_domdec_t
*dd
,
2189 const int *gcgs_index
, int cg_start
)
2191 int nzone
, zone
, zone1
, cg0
, cg1
, cg1_p1
, cg
, cg_gl
, a
, a_gl
;
2192 int *zone2cg
, *zone_ncg1
, *index_gl
, *gatindex
;
2195 if (dd
->nat_tot
> dd
->gatindex_nalloc
)
2197 dd
->gatindex_nalloc
= over_alloc_dd(dd
->nat_tot
);
2198 srenew(dd
->gatindex
, dd
->gatindex_nalloc
);
2201 nzone
= dd
->comm
->zones
.n
;
2202 zone2cg
= dd
->comm
->zones
.cg_range
;
2203 zone_ncg1
= dd
->comm
->zone_ncg1
;
2204 index_gl
= dd
->index_gl
;
2205 gatindex
= dd
->gatindex
;
2206 bCGs
= dd
->comm
->bCGs
;
2208 if (zone2cg
[1] != dd
->ncg_home
)
2210 gmx_incons("dd->ncg_zone is not up to date");
2213 /* Make the local to global and global to local atom index */
2214 a
= dd
->cgindex
[cg_start
];
2215 for (zone
= 0; zone
< nzone
; zone
++)
2223 cg0
= zone2cg
[zone
];
2225 cg1
= zone2cg
[zone
+1];
2226 cg1_p1
= cg0
+ zone_ncg1
[zone
];
2228 for (cg
= cg0
; cg
< cg1
; cg
++)
2233 /* Signal that this cg is from more than one pulse away */
2236 cg_gl
= index_gl
[cg
];
2239 for (a_gl
= gcgs_index
[cg_gl
]; a_gl
< gcgs_index
[cg_gl
+1]; a_gl
++)
2242 ga2la_set(dd
->ga2la
, a_gl
, a
, zone1
);
2248 gatindex
[a
] = cg_gl
;
2249 ga2la_set(dd
->ga2la
, cg_gl
, a
, zone1
);
2256 static int check_bLocalCG(gmx_domdec_t
*dd
, int ncg_sys
, const char *bLocalCG
,
2262 if (bLocalCG
== nullptr)
2266 for (i
= 0; i
< dd
->ncg_tot
; i
++)
2268 if (!bLocalCG
[dd
->index_gl
[i
]])
2271 "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
);
2276 for (i
= 0; i
< ncg_sys
; i
++)
2283 if (ngl
!= dd
->ncg_tot
)
2285 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
);
2292 static void check_index_consistency(gmx_domdec_t
*dd
,
2293 int natoms_sys
, int ncg_sys
,
2296 int nerr
, ngl
, i
, a
, cell
;
2301 if (dd
->comm
->DD_debug
> 1)
2303 snew(have
, natoms_sys
);
2304 for (a
= 0; a
< dd
->nat_tot
; a
++)
2306 if (have
[dd
->gatindex
[a
]] > 0)
2308 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);
2312 have
[dd
->gatindex
[a
]] = a
+ 1;
2318 snew(have
, dd
->nat_tot
);
2321 for (i
= 0; i
< natoms_sys
; i
++)
2323 if (ga2la_get(dd
->ga2la
, i
, &a
, &cell
))
2325 if (a
>= dd
->nat_tot
)
2327 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
);
2333 if (dd
->gatindex
[a
] != i
)
2335 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);
2342 if (ngl
!= dd
->nat_tot
)
2345 "DD rank %d, %s: %d global atom indices, %d local atoms\n",
2346 dd
->rank
, where
, ngl
, dd
->nat_tot
);
2348 for (a
= 0; a
< dd
->nat_tot
; a
++)
2353 "DD rank %d, %s: local atom %d, global %d has no global index\n",
2354 dd
->rank
, where
, a
+1, dd
->gatindex
[a
]+1);
2359 nerr
+= check_bLocalCG(dd
, ncg_sys
, dd
->comm
->bLocalCG
, where
);
2363 gmx_fatal(FARGS
, "DD rank %d, %s: %d atom/cg index inconsistencies",
2364 dd
->rank
, where
, nerr
);
2368 static void clear_dd_indices(gmx_domdec_t
*dd
, int cg_start
, int a_start
)
2375 /* Clear the whole list without searching */
2376 ga2la_clear(dd
->ga2la
);
2380 for (i
= a_start
; i
< dd
->nat_tot
; i
++)
2382 ga2la_del(dd
->ga2la
, dd
->gatindex
[i
]);
2386 bLocalCG
= dd
->comm
->bLocalCG
;
2389 for (i
= cg_start
; i
< dd
->ncg_tot
; i
++)
2391 bLocalCG
[dd
->index_gl
[i
]] = FALSE
;
2395 dd_clear_local_vsite_indices(dd
);
2397 if (dd
->constraints
)
2399 dd_clear_local_constraint_indices(dd
);
2403 /* This function should be used for moving the domain boudaries during DLB,
2404 * for obtaining the minimum cell size. It checks the initially set limit
2405 * comm->cellsize_min, for bonded and initial non-bonded cut-offs,
2406 * and, possibly, a longer cut-off limit set for PME load balancing.
2408 static real
cellsize_min_dlb(gmx_domdec_comm_t
*comm
, int dim_ind
, int dim
)
2412 cellsize_min
= comm
->cellsize_min
[dim
];
2414 if (!comm
->bVacDLBNoLimit
)
2416 /* The cut-off might have changed, e.g. by PME load balacning,
2417 * from the value used to set comm->cellsize_min, so check it.
2419 cellsize_min
= std::max(cellsize_min
, comm
->cutoff
/comm
->cd
[dim_ind
].np_dlb
);
2421 if (comm
->bPMELoadBalDLBLimits
)
2423 /* Check for the cut-off limit set by the PME load balancing */
2424 cellsize_min
= std::max(cellsize_min
, comm
->PMELoadBal_max_cutoff
/comm
->cd
[dim_ind
].np_dlb
);
2428 return cellsize_min
;
2431 static real
grid_jump_limit(gmx_domdec_comm_t
*comm
, real cutoff
,
2434 real grid_jump_limit
;
2436 /* The distance between the boundaries of cells at distance
2437 * x+-1,y+-1 or y+-1,z+-1 is limited by the cut-off restrictions
2438 * and by the fact that cells should not be shifted by more than
2439 * half their size, such that cg's only shift by one cell
2440 * at redecomposition.
2442 grid_jump_limit
= comm
->cellsize_limit
;
2443 if (!comm
->bVacDLBNoLimit
)
2445 if (comm
->bPMELoadBalDLBLimits
)
2447 cutoff
= std::max(cutoff
, comm
->PMELoadBal_max_cutoff
);
2449 grid_jump_limit
= std::max(grid_jump_limit
,
2450 cutoff
/comm
->cd
[dim_ind
].np
);
2453 return grid_jump_limit
;
2456 static gmx_bool
check_grid_jump(gmx_int64_t step
,
2462 gmx_domdec_comm_t
*comm
;
2471 for (d
= 1; d
< dd
->ndim
; d
++)
2474 limit
= grid_jump_limit(comm
, cutoff
, d
);
2475 bfac
= ddbox
->box_size
[dim
];
2476 if (ddbox
->tric_dir
[dim
])
2478 bfac
*= ddbox
->skew_fac
[dim
];
2480 if ((comm
->cell_f1
[d
] - comm
->cell_f_max0
[d
])*bfac
< limit
||
2481 (comm
->cell_f0
[d
] - comm
->cell_f_min1
[d
])*bfac
> -limit
)
2489 /* This error should never be triggered under normal
2490 * circumstances, but you never know ...
2492 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.",
2493 gmx_step_str(step
, buf
),
2494 dim2char(dim
), dd
->ci
[XX
], dd
->ci
[YY
], dd
->ci
[ZZ
]);
2502 static int dd_load_count(gmx_domdec_comm_t
*comm
)
2504 return (comm
->eFlop
? comm
->flop_n
: comm
->cycl_n
[ddCyclF
]);
2507 static float dd_force_load(gmx_domdec_comm_t
*comm
)
2514 if (comm
->eFlop
> 1)
2516 load
*= 1.0 + (comm
->eFlop
- 1)*(0.1*rand()/RAND_MAX
- 0.05);
2521 load
= comm
->cycl
[ddCyclF
];
2522 if (comm
->cycl_n
[ddCyclF
] > 1)
2524 /* Subtract the maximum of the last n cycle counts
2525 * to get rid of possible high counts due to other sources,
2526 * for instance system activity, that would otherwise
2527 * affect the dynamic load balancing.
2529 load
-= comm
->cycl_max
[ddCyclF
];
2533 if (comm
->cycl_n
[ddCyclWaitGPU
] && comm
->nrank_gpu_shared
> 1)
2535 float gpu_wait
, gpu_wait_sum
;
2537 gpu_wait
= comm
->cycl
[ddCyclWaitGPU
];
2538 if (comm
->cycl_n
[ddCyclF
] > 1)
2540 /* We should remove the WaitGPU time of the same MD step
2541 * as the one with the maximum F time, since the F time
2542 * and the wait time are not independent.
2543 * Furthermore, the step for the max F time should be chosen
2544 * the same on all ranks that share the same GPU.
2545 * But to keep the code simple, we remove the average instead.
2546 * The main reason for artificially long times at some steps
2547 * is spurious CPU activity or MPI time, so we don't expect
2548 * that changes in the GPU wait time matter a lot here.
2550 gpu_wait
*= (comm
->cycl_n
[ddCyclF
] - 1)/(float)comm
->cycl_n
[ddCyclF
];
2552 /* Sum the wait times over the ranks that share the same GPU */
2553 MPI_Allreduce(&gpu_wait
, &gpu_wait_sum
, 1, MPI_FLOAT
, MPI_SUM
,
2554 comm
->mpi_comm_gpu_shared
);
2555 /* Replace the wait time by the average over the ranks */
2556 load
+= -gpu_wait
+ gpu_wait_sum
/comm
->nrank_gpu_shared
;
2564 static void set_slb_pme_dim_f(gmx_domdec_t
*dd
, int dim
, real
**dim_f
)
2566 gmx_domdec_comm_t
*comm
;
2571 snew(*dim_f
, dd
->nc
[dim
]+1);
2573 for (i
= 1; i
< dd
->nc
[dim
]; i
++)
2575 if (comm
->slb_frac
[dim
])
2577 (*dim_f
)[i
] = (*dim_f
)[i
-1] + comm
->slb_frac
[dim
][i
-1];
2581 (*dim_f
)[i
] = (real
)i
/(real
)dd
->nc
[dim
];
2584 (*dim_f
)[dd
->nc
[dim
]] = 1;
2587 static void init_ddpme(gmx_domdec_t
*dd
, gmx_ddpme_t
*ddpme
, int dimind
)
2589 int pmeindex
, slab
, nso
, i
;
2592 if (dimind
== 0 && dd
->dim
[0] == YY
&& dd
->comm
->npmenodes_x
== 1)
2598 ddpme
->dim
= dimind
;
2600 ddpme
->dim_match
= (ddpme
->dim
== dd
->dim
[dimind
]);
2602 ddpme
->nslab
= (ddpme
->dim
== 0 ?
2603 dd
->comm
->npmenodes_x
:
2604 dd
->comm
->npmenodes_y
);
2606 if (ddpme
->nslab
<= 1)
2611 nso
= dd
->comm
->npmenodes
/ddpme
->nslab
;
2612 /* Determine for each PME slab the PP location range for dimension dim */
2613 snew(ddpme
->pp_min
, ddpme
->nslab
);
2614 snew(ddpme
->pp_max
, ddpme
->nslab
);
2615 for (slab
= 0; slab
< ddpme
->nslab
; slab
++)
2617 ddpme
->pp_min
[slab
] = dd
->nc
[dd
->dim
[dimind
]] - 1;
2618 ddpme
->pp_max
[slab
] = 0;
2620 for (i
= 0; i
< dd
->nnodes
; i
++)
2622 ddindex2xyz(dd
->nc
, i
, xyz
);
2623 /* For y only use our y/z slab.
2624 * This assumes that the PME x grid size matches the DD grid size.
2626 if (dimind
== 0 || xyz
[XX
] == dd
->ci
[XX
])
2628 pmeindex
= ddindex2pmeindex(dd
, i
);
2631 slab
= pmeindex
/nso
;
2635 slab
= pmeindex
% ddpme
->nslab
;
2637 ddpme
->pp_min
[slab
] = std::min(ddpme
->pp_min
[slab
], xyz
[dimind
]);
2638 ddpme
->pp_max
[slab
] = std::max(ddpme
->pp_max
[slab
], xyz
[dimind
]);
2642 set_slb_pme_dim_f(dd
, ddpme
->dim
, &ddpme
->slb_dim_f
);
2645 int dd_pme_maxshift_x(const gmx_domdec_t
*dd
)
2647 if (dd
->comm
->ddpme
[0].dim
== XX
)
2649 return dd
->comm
->ddpme
[0].maxshift
;
2657 int dd_pme_maxshift_y(const gmx_domdec_t
*dd
)
2659 if (dd
->comm
->ddpme
[0].dim
== YY
)
2661 return dd
->comm
->ddpme
[0].maxshift
;
2663 else if (dd
->comm
->npmedecompdim
>= 2 && dd
->comm
->ddpme
[1].dim
== YY
)
2665 return dd
->comm
->ddpme
[1].maxshift
;
2673 static void set_pme_maxshift(gmx_domdec_t
*dd
, gmx_ddpme_t
*ddpme
,
2674 gmx_bool bUniform
, const gmx_ddbox_t
*ddbox
,
2677 gmx_domdec_comm_t
*comm
;
2680 real range
, pme_boundary
;
2684 nc
= dd
->nc
[ddpme
->dim
];
2687 if (!ddpme
->dim_match
)
2689 /* PP decomposition is not along dim: the worst situation */
2692 else if (ns
<= 3 || (bUniform
&& ns
== nc
))
2694 /* The optimal situation */
2699 /* We need to check for all pme nodes which nodes they
2700 * could possibly need to communicate with.
2702 xmin
= ddpme
->pp_min
;
2703 xmax
= ddpme
->pp_max
;
2704 /* Allow for atoms to be maximally 2/3 times the cut-off
2705 * out of their DD cell. This is a reasonable balance between
2706 * between performance and support for most charge-group/cut-off
2709 range
= 2.0/3.0*comm
->cutoff
/ddbox
->box_size
[ddpme
->dim
];
2710 /* Avoid extra communication when we are exactly at a boundary */
2714 for (s
= 0; s
< ns
; s
++)
2716 /* PME slab s spreads atoms between box frac. s/ns and (s+1)/ns */
2717 pme_boundary
= (real
)s
/ns
;
2720 cell_f
[xmax
[s
-(sh
+1) ]+1] + range
> pme_boundary
) ||
2722 cell_f
[xmax
[s
-(sh
+1)+ns
]+1] - 1 + range
> pme_boundary
)))
2726 pme_boundary
= (real
)(s
+1)/ns
;
2729 cell_f
[xmin
[s
+(sh
+1) ] ] - range
< pme_boundary
) ||
2731 cell_f
[xmin
[s
+(sh
+1)-ns
] ] + 1 - range
< pme_boundary
)))
2738 ddpme
->maxshift
= sh
;
2742 fprintf(debug
, "PME slab communication range for dim %d is %d\n",
2743 ddpme
->dim
, ddpme
->maxshift
);
2747 static void check_box_size(gmx_domdec_t
*dd
, gmx_ddbox_t
*ddbox
)
2751 for (d
= 0; d
< dd
->ndim
; d
++)
2754 if (dim
< ddbox
->nboundeddim
&&
2755 ddbox
->box_size
[dim
]*ddbox
->skew_fac
[dim
] <
2756 dd
->nc
[dim
]*dd
->comm
->cellsize_limit
*DD_CELL_MARGIN
)
2758 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",
2759 dim2char(dim
), ddbox
->box_size
[dim
], ddbox
->skew_fac
[dim
],
2760 dd
->nc
[dim
], dd
->comm
->cellsize_limit
);
2766 setcellsizeslbLOCAL
, setcellsizeslbMASTER
, setcellsizeslbPULSE_ONLY
2769 /* Set the domain boundaries. Use for static (or no) load balancing,
2770 * and also for the starting state for dynamic load balancing.
2771 * setmode determine if and where the boundaries are stored, use enum above.
2772 * Returns the number communication pulses in npulse.
2774 static void set_dd_cell_sizes_slb(gmx_domdec_t
*dd
, const gmx_ddbox_t
*ddbox
,
2775 int setmode
, ivec npulse
)
2777 gmx_domdec_comm_t
*comm
;
2780 real
*cell_x
, cell_dx
, cellsize
;
2784 for (d
= 0; d
< DIM
; d
++)
2786 cellsize_min
[d
] = ddbox
->box_size
[d
]*ddbox
->skew_fac
[d
];
2788 if (dd
->nc
[d
] == 1 || comm
->slb_frac
[d
] == nullptr)
2791 cell_dx
= ddbox
->box_size
[d
]/dd
->nc
[d
];
2794 case setcellsizeslbMASTER
:
2795 for (j
= 0; j
< dd
->nc
[d
]+1; j
++)
2797 dd
->ma
->cell_x
[d
][j
] = ddbox
->box0
[d
] + j
*cell_dx
;
2800 case setcellsizeslbLOCAL
:
2801 comm
->cell_x0
[d
] = ddbox
->box0
[d
] + (dd
->ci
[d
] )*cell_dx
;
2802 comm
->cell_x1
[d
] = ddbox
->box0
[d
] + (dd
->ci
[d
]+1)*cell_dx
;
2807 cellsize
= cell_dx
*ddbox
->skew_fac
[d
];
2808 while (cellsize
*npulse
[d
] < comm
->cutoff
)
2812 cellsize_min
[d
] = cellsize
;
2816 /* Statically load balanced grid */
2817 /* Also when we are not doing a master distribution we determine
2818 * all cell borders in a loop to obtain identical values
2819 * to the master distribution case and to determine npulse.
2821 if (setmode
== setcellsizeslbMASTER
)
2823 cell_x
= dd
->ma
->cell_x
[d
];
2827 snew(cell_x
, dd
->nc
[d
]+1);
2829 cell_x
[0] = ddbox
->box0
[d
];
2830 for (j
= 0; j
< dd
->nc
[d
]; j
++)
2832 cell_dx
= ddbox
->box_size
[d
]*comm
->slb_frac
[d
][j
];
2833 cell_x
[j
+1] = cell_x
[j
] + cell_dx
;
2834 cellsize
= cell_dx
*ddbox
->skew_fac
[d
];
2835 while (cellsize
*npulse
[d
] < comm
->cutoff
&&
2836 npulse
[d
] < dd
->nc
[d
]-1)
2840 cellsize_min
[d
] = std::min(cellsize_min
[d
], cellsize
);
2842 if (setmode
== setcellsizeslbLOCAL
)
2844 comm
->cell_x0
[d
] = cell_x
[dd
->ci
[d
]];
2845 comm
->cell_x1
[d
] = cell_x
[dd
->ci
[d
]+1];
2847 if (setmode
!= setcellsizeslbMASTER
)
2852 /* The following limitation is to avoid that a cell would receive
2853 * some of its own home charge groups back over the periodic boundary.
2854 * Double charge groups cause trouble with the global indices.
2856 if (d
< ddbox
->npbcdim
&&
2857 dd
->nc
[d
] > 1 && npulse
[d
] >= dd
->nc
[d
])
2859 char error_string
[STRLEN
];
2861 sprintf(error_string
,
2862 "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",
2863 dim2char(d
), ddbox
->box_size
[d
], ddbox
->skew_fac
[d
],
2865 dd
->nc
[d
], dd
->nc
[d
],
2866 dd
->nnodes
> dd
->nc
[d
] ? "cells" : "ranks");
2868 if (setmode
== setcellsizeslbLOCAL
)
2870 gmx_fatal_collective(FARGS
, dd
->mpi_comm_all
, DDMASTER(dd
),
2875 gmx_fatal(FARGS
, error_string
);
2882 copy_rvec(cellsize_min
, comm
->cellsize_min
);
2885 for (d
= 0; d
< comm
->npmedecompdim
; d
++)
2887 set_pme_maxshift(dd
, &comm
->ddpme
[d
],
2888 comm
->slb_frac
[dd
->dim
[d
]] == nullptr, ddbox
,
2889 comm
->ddpme
[d
].slb_dim_f
);
2894 static void dd_cell_sizes_dlb_root_enforce_limits(gmx_domdec_t
*dd
,
2895 int d
, int dim
, domdec_root_t
*root
,
2896 const gmx_ddbox_t
*ddbox
,
2897 gmx_bool bUniform
, gmx_int64_t step
, real cellsize_limit_f
, int range
[])
2899 gmx_domdec_comm_t
*comm
;
2900 int ncd
, i
, j
, nmin
, nmin_old
;
2901 gmx_bool bLimLo
, bLimHi
;
2903 real fac
, halfway
, cellsize_limit_f_i
, region_size
;
2904 gmx_bool bPBC
, bLastHi
= FALSE
;
2905 int nrange
[] = {range
[0], range
[1]};
2907 region_size
= root
->cell_f
[range
[1]]-root
->cell_f
[range
[0]];
2913 bPBC
= (dim
< ddbox
->npbcdim
);
2915 cell_size
= root
->buf_ncd
;
2919 fprintf(debug
, "enforce_limits: %d %d\n", range
[0], range
[1]);
2922 /* First we need to check if the scaling does not make cells
2923 * smaller than the smallest allowed size.
2924 * We need to do this iteratively, since if a cell is too small,
2925 * it needs to be enlarged, which makes all the other cells smaller,
2926 * which could in turn make another cell smaller than allowed.
2928 for (i
= range
[0]; i
< range
[1]; i
++)
2930 root
->bCellMin
[i
] = FALSE
;
2936 /* We need the total for normalization */
2938 for (i
= range
[0]; i
< range
[1]; i
++)
2940 if (root
->bCellMin
[i
] == FALSE
)
2942 fac
+= cell_size
[i
];
2945 fac
= ( region_size
- nmin
*cellsize_limit_f
)/fac
; /* substracting cells already set to cellsize_limit_f */
2946 /* Determine the cell boundaries */
2947 for (i
= range
[0]; i
< range
[1]; i
++)
2949 if (root
->bCellMin
[i
] == FALSE
)
2951 cell_size
[i
] *= fac
;
2952 if (!bPBC
&& (i
== 0 || i
== dd
->nc
[dim
] -1))
2954 cellsize_limit_f_i
= 0;
2958 cellsize_limit_f_i
= cellsize_limit_f
;
2960 if (cell_size
[i
] < cellsize_limit_f_i
)
2962 root
->bCellMin
[i
] = TRUE
;
2963 cell_size
[i
] = cellsize_limit_f_i
;
2967 root
->cell_f
[i
+1] = root
->cell_f
[i
] + cell_size
[i
];
2970 while (nmin
> nmin_old
);
2973 cell_size
[i
] = root
->cell_f
[i
+1] - root
->cell_f
[i
];
2974 /* For this check we should not use DD_CELL_MARGIN,
2975 * but a slightly smaller factor,
2976 * since rounding could get use below the limit.
2978 if (bPBC
&& cell_size
[i
] < cellsize_limit_f
*DD_CELL_MARGIN2
/DD_CELL_MARGIN
)
2981 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",
2982 gmx_step_str(step
, buf
),
2983 dim2char(dim
), ddbox
->box_size
[dim
], ddbox
->skew_fac
[dim
],
2984 ncd
, comm
->cellsize_min
[dim
]);
2987 root
->bLimited
= (nmin
> 0) || (range
[0] > 0) || (range
[1] < ncd
);
2991 /* Check if the boundary did not displace more than halfway
2992 * each of the cells it bounds, as this could cause problems,
2993 * especially when the differences between cell sizes are large.
2994 * If changes are applied, they will not make cells smaller
2995 * than the cut-off, as we check all the boundaries which
2996 * might be affected by a change and if the old state was ok,
2997 * the cells will at most be shrunk back to their old size.
2999 for (i
= range
[0]+1; i
< range
[1]; i
++)
3001 halfway
= 0.5*(root
->old_cell_f
[i
] + root
->old_cell_f
[i
-1]);
3002 if (root
->cell_f
[i
] < halfway
)
3004 root
->cell_f
[i
] = halfway
;
3005 /* Check if the change also causes shifts of the next boundaries */
3006 for (j
= i
+1; j
< range
[1]; j
++)
3008 if (root
->cell_f
[j
] < root
->cell_f
[j
-1] + cellsize_limit_f
)
3010 root
->cell_f
[j
] = root
->cell_f
[j
-1] + cellsize_limit_f
;
3014 halfway
= 0.5*(root
->old_cell_f
[i
] + root
->old_cell_f
[i
+1]);
3015 if (root
->cell_f
[i
] > halfway
)
3017 root
->cell_f
[i
] = halfway
;
3018 /* Check if the change also causes shifts of the next boundaries */
3019 for (j
= i
-1; j
>= range
[0]+1; j
--)
3021 if (root
->cell_f
[j
] > root
->cell_f
[j
+1] - cellsize_limit_f
)
3023 root
->cell_f
[j
] = root
->cell_f
[j
+1] - cellsize_limit_f
;
3030 /* nrange is defined as [lower, upper) range for new call to enforce_limits */
3031 /* find highest violation of LimLo (a) and the following violation of LimHi (thus the lowest following) (b)
3032 * then call enforce_limits for (oldb,a), (a,b). In the next step: (b,nexta). oldb and nexta can be the boundaries.
3033 * for a and b nrange is used */
3036 /* Take care of the staggering of the cell boundaries */
3039 for (i
= range
[0]; i
< range
[1]; i
++)
3041 root
->cell_f_max0
[i
] = root
->cell_f
[i
];
3042 root
->cell_f_min1
[i
] = root
->cell_f
[i
+1];
3047 for (i
= range
[0]+1; i
< range
[1]; i
++)
3049 bLimLo
= (root
->cell_f
[i
] < root
->bound_min
[i
]);
3050 bLimHi
= (root
->cell_f
[i
] > root
->bound_max
[i
]);
3051 if (bLimLo
&& bLimHi
)
3053 /* Both limits violated, try the best we can */
3054 /* For this case we split the original range (range) in two parts and care about the other limitiations in the next iteration. */
3055 root
->cell_f
[i
] = 0.5*(root
->bound_min
[i
] + root
->bound_max
[i
]);
3056 nrange
[0] = range
[0];
3058 dd_cell_sizes_dlb_root_enforce_limits(dd
, d
, dim
, root
, ddbox
, bUniform
, step
, cellsize_limit_f
, nrange
);
3061 nrange
[1] = range
[1];
3062 dd_cell_sizes_dlb_root_enforce_limits(dd
, d
, dim
, root
, ddbox
, bUniform
, step
, cellsize_limit_f
, nrange
);
3068 /* root->cell_f[i] = root->bound_min[i]; */
3069 nrange
[1] = i
; /* only store violation location. There could be a LimLo violation following with an higher index */
3072 else if (bLimHi
&& !bLastHi
)
3075 if (nrange
[1] < range
[1]) /* found a LimLo before */
3077 root
->cell_f
[nrange
[1]] = root
->bound_min
[nrange
[1]];
3078 dd_cell_sizes_dlb_root_enforce_limits(dd
, d
, dim
, root
, ddbox
, bUniform
, step
, cellsize_limit_f
, nrange
);
3079 nrange
[0] = nrange
[1];
3081 root
->cell_f
[i
] = root
->bound_max
[i
];
3083 dd_cell_sizes_dlb_root_enforce_limits(dd
, d
, dim
, root
, ddbox
, bUniform
, step
, cellsize_limit_f
, nrange
);
3085 nrange
[1] = range
[1];
3088 if (nrange
[1] < range
[1]) /* found last a LimLo */
3090 root
->cell_f
[nrange
[1]] = root
->bound_min
[nrange
[1]];
3091 dd_cell_sizes_dlb_root_enforce_limits(dd
, d
, dim
, root
, ddbox
, bUniform
, step
, cellsize_limit_f
, nrange
);
3092 nrange
[0] = nrange
[1];
3093 nrange
[1] = range
[1];
3094 dd_cell_sizes_dlb_root_enforce_limits(dd
, d
, dim
, root
, ddbox
, bUniform
, step
, cellsize_limit_f
, nrange
);
3096 else if (nrange
[0] > range
[0]) /* found at least one LimHi */
3098 dd_cell_sizes_dlb_root_enforce_limits(dd
, d
, dim
, root
, ddbox
, bUniform
, step
, cellsize_limit_f
, nrange
);
3105 static void set_dd_cell_sizes_dlb_root(gmx_domdec_t
*dd
,
3106 int d
, int dim
, domdec_root_t
*root
,
3107 const gmx_ddbox_t
*ddbox
,
3108 gmx_bool bDynamicBox
,
3109 gmx_bool bUniform
, gmx_int64_t step
)
3111 gmx_domdec_comm_t
*comm
;
3112 int ncd
, d1
, i
, pos
;
3114 real load_aver
, load_i
, imbalance
, change
, change_max
, sc
;
3115 real cellsize_limit_f
, dist_min_f
, dist_min_f_hard
, space
;
3119 int range
[] = { 0, 0 };
3123 /* Convert the maximum change from the input percentage to a fraction */
3124 change_limit
= comm
->dlb_scale_lim
*0.01;
3128 bPBC
= (dim
< ddbox
->npbcdim
);
3130 cell_size
= root
->buf_ncd
;
3132 /* Store the original boundaries */
3133 for (i
= 0; i
< ncd
+1; i
++)
3135 root
->old_cell_f
[i
] = root
->cell_f
[i
];
3139 for (i
= 0; i
< ncd
; i
++)
3141 cell_size
[i
] = 1.0/ncd
;
3144 else if (dd_load_count(comm
) > 0)
3146 load_aver
= comm
->load
[d
].sum_m
/ncd
;
3148 for (i
= 0; i
< ncd
; i
++)
3150 /* Determine the relative imbalance of cell i */
3151 load_i
= comm
->load
[d
].load
[i
*comm
->load
[d
].nload
+2];
3152 imbalance
= (load_i
- load_aver
)/(load_aver
> 0 ? load_aver
: 1);
3153 /* Determine the change of the cell size using underrelaxation */
3154 change
= -relax
*imbalance
;
3155 change_max
= std::max(change_max
, std::max(change
, -change
));
3157 /* Limit the amount of scaling.
3158 * We need to use the same rescaling for all cells in one row,
3159 * otherwise the load balancing might not converge.
3162 if (change_max
> change_limit
)
3164 sc
*= change_limit
/change_max
;
3166 for (i
= 0; i
< ncd
; i
++)
3168 /* Determine the relative imbalance of cell i */
3169 load_i
= comm
->load
[d
].load
[i
*comm
->load
[d
].nload
+2];
3170 imbalance
= (load_i
- load_aver
)/(load_aver
> 0 ? load_aver
: 1);
3171 /* Determine the change of the cell size using underrelaxation */
3172 change
= -sc
*imbalance
;
3173 cell_size
[i
] = (root
->cell_f
[i
+1]-root
->cell_f
[i
])*(1 + change
);
3177 cellsize_limit_f
= cellsize_min_dlb(comm
, d
, dim
)/ddbox
->box_size
[dim
];
3178 cellsize_limit_f
*= DD_CELL_MARGIN
;
3179 dist_min_f_hard
= grid_jump_limit(comm
, comm
->cutoff
, d
)/ddbox
->box_size
[dim
];
3180 dist_min_f
= dist_min_f_hard
* DD_CELL_MARGIN
;
3181 if (ddbox
->tric_dir
[dim
])
3183 cellsize_limit_f
/= ddbox
->skew_fac
[dim
];
3184 dist_min_f
/= ddbox
->skew_fac
[dim
];
3186 if (bDynamicBox
&& d
> 0)
3188 dist_min_f
*= DD_PRES_SCALE_MARGIN
;
3190 if (d
> 0 && !bUniform
)
3192 /* Make sure that the grid is not shifted too much */
3193 for (i
= 1; i
< ncd
; i
++)
3195 if (root
->cell_f_min1
[i
] - root
->cell_f_max0
[i
-1] < 2 * dist_min_f_hard
)
3197 gmx_incons("Inconsistent DD boundary staggering limits!");
3199 root
->bound_min
[i
] = root
->cell_f_max0
[i
-1] + dist_min_f
;
3200 space
= root
->cell_f
[i
] - (root
->cell_f_max0
[i
-1] + dist_min_f
);
3203 root
->bound_min
[i
] += 0.5*space
;
3205 root
->bound_max
[i
] = root
->cell_f_min1
[i
] - dist_min_f
;
3206 space
= root
->cell_f
[i
] - (root
->cell_f_min1
[i
] - dist_min_f
);
3209 root
->bound_max
[i
] += 0.5*space
;
3214 "dim %d boundary %d %.3f < %.3f < %.3f < %.3f < %.3f\n",
3216 root
->cell_f_max0
[i
-1] + dist_min_f
,
3217 root
->bound_min
[i
], root
->cell_f
[i
], root
->bound_max
[i
],
3218 root
->cell_f_min1
[i
] - dist_min_f
);
3223 root
->cell_f
[0] = 0;
3224 root
->cell_f
[ncd
] = 1;
3225 dd_cell_sizes_dlb_root_enforce_limits(dd
, d
, dim
, root
, ddbox
, bUniform
, step
, cellsize_limit_f
, range
);
3228 /* After the checks above, the cells should obey the cut-off
3229 * restrictions, but it does not hurt to check.
3231 for (i
= 0; i
< ncd
; i
++)
3235 fprintf(debug
, "Relative bounds dim %d cell %d: %f %f\n",
3236 dim
, i
, root
->cell_f
[i
], root
->cell_f
[i
+1]);
3239 if ((bPBC
|| (i
!= 0 && i
!= dd
->nc
[dim
]-1)) &&
3240 root
->cell_f
[i
+1] - root
->cell_f
[i
] <
3241 cellsize_limit_f
/DD_CELL_MARGIN
)
3245 "\nWARNING step %s: direction %c, cell %d too small: %f\n",
3246 gmx_step_str(step
, buf
), dim2char(dim
), i
,
3247 (root
->cell_f
[i
+1] - root
->cell_f
[i
])
3248 *ddbox
->box_size
[dim
]*ddbox
->skew_fac
[dim
]);
3253 /* Store the cell boundaries of the lower dimensions at the end */
3254 for (d1
= 0; d1
< d
; d1
++)
3256 root
->cell_f
[pos
++] = comm
->cell_f0
[d1
];
3257 root
->cell_f
[pos
++] = comm
->cell_f1
[d1
];
3260 if (d
< comm
->npmedecompdim
)
3262 /* The master determines the maximum shift for
3263 * the coordinate communication between separate PME nodes.
3265 set_pme_maxshift(dd
, &comm
->ddpme
[d
], bUniform
, ddbox
, root
->cell_f
);
3267 root
->cell_f
[pos
++] = comm
->ddpme
[0].maxshift
;
3270 root
->cell_f
[pos
++] = comm
->ddpme
[1].maxshift
;
3274 static void relative_to_absolute_cell_bounds(gmx_domdec_t
*dd
,
3275 const gmx_ddbox_t
*ddbox
,
3278 gmx_domdec_comm_t
*comm
;
3283 /* Set the cell dimensions */
3284 dim
= dd
->dim
[dimind
];
3285 comm
->cell_x0
[dim
] = comm
->cell_f0
[dimind
]*ddbox
->box_size
[dim
];
3286 comm
->cell_x1
[dim
] = comm
->cell_f1
[dimind
]*ddbox
->box_size
[dim
];
3287 if (dim
>= ddbox
->nboundeddim
)
3289 comm
->cell_x0
[dim
] += ddbox
->box0
[dim
];
3290 comm
->cell_x1
[dim
] += ddbox
->box0
[dim
];
3294 static void distribute_dd_cell_sizes_dlb(gmx_domdec_t
*dd
,
3295 int d
, int dim
, real
*cell_f_row
,
3296 const gmx_ddbox_t
*ddbox
)
3298 gmx_domdec_comm_t
*comm
;
3304 /* Each node would only need to know two fractions,
3305 * but it is probably cheaper to broadcast the whole array.
3307 MPI_Bcast(cell_f_row
, DD_CELL_F_SIZE(dd
, d
)*sizeof(real
), MPI_BYTE
,
3308 0, comm
->mpi_comm_load
[d
]);
3310 /* Copy the fractions for this dimension from the buffer */
3311 comm
->cell_f0
[d
] = cell_f_row
[dd
->ci
[dim
] ];
3312 comm
->cell_f1
[d
] = cell_f_row
[dd
->ci
[dim
]+1];
3313 /* The whole array was communicated, so set the buffer position */
3314 pos
= dd
->nc
[dim
] + 1;
3315 for (d1
= 0; d1
<= d
; d1
++)
3319 /* Copy the cell fractions of the lower dimensions */
3320 comm
->cell_f0
[d1
] = cell_f_row
[pos
++];
3321 comm
->cell_f1
[d1
] = cell_f_row
[pos
++];
3323 relative_to_absolute_cell_bounds(dd
, ddbox
, d1
);
3325 /* Convert the communicated shift from float to int */
3326 comm
->ddpme
[0].maxshift
= (int)(cell_f_row
[pos
++] + 0.5);
3329 comm
->ddpme
[1].maxshift
= (int)(cell_f_row
[pos
++] + 0.5);
3333 static void set_dd_cell_sizes_dlb_change(gmx_domdec_t
*dd
,
3334 const gmx_ddbox_t
*ddbox
,
3335 gmx_bool bDynamicBox
,
3336 gmx_bool bUniform
, gmx_int64_t step
)
3338 gmx_domdec_comm_t
*comm
;
3340 gmx_bool bRowMember
, bRowRoot
;
3345 for (d
= 0; d
< dd
->ndim
; d
++)
3350 for (d1
= d
; d1
< dd
->ndim
; d1
++)
3352 if (dd
->ci
[dd
->dim
[d1
]] > 0)
3365 set_dd_cell_sizes_dlb_root(dd
, d
, dim
, comm
->root
[d
],
3366 ddbox
, bDynamicBox
, bUniform
, step
);
3367 cell_f_row
= comm
->root
[d
]->cell_f
;
3371 cell_f_row
= comm
->cell_f_row
;
3373 distribute_dd_cell_sizes_dlb(dd
, d
, dim
, cell_f_row
, ddbox
);
3378 static void set_dd_cell_sizes_dlb_nochange(gmx_domdec_t
*dd
,
3379 const gmx_ddbox_t
*ddbox
)
3383 /* This function assumes the box is static and should therefore
3384 * not be called when the box has changed since the last
3385 * call to dd_partition_system.
3387 for (d
= 0; d
< dd
->ndim
; d
++)
3389 relative_to_absolute_cell_bounds(dd
, ddbox
, d
);
3395 static void set_dd_cell_sizes_dlb(gmx_domdec_t
*dd
,
3396 const gmx_ddbox_t
*ddbox
, gmx_bool bDynamicBox
,
3397 gmx_bool bUniform
, gmx_bool bDoDLB
, gmx_int64_t step
,
3398 gmx_wallcycle_t wcycle
)
3400 gmx_domdec_comm_t
*comm
;
3407 wallcycle_start(wcycle
, ewcDDCOMMBOUND
);
3408 set_dd_cell_sizes_dlb_change(dd
, ddbox
, bDynamicBox
, bUniform
, step
);
3409 wallcycle_stop(wcycle
, ewcDDCOMMBOUND
);
3411 else if (bDynamicBox
)
3413 set_dd_cell_sizes_dlb_nochange(dd
, ddbox
);
3416 /* Set the dimensions for which no DD is used */
3417 for (dim
= 0; dim
< DIM
; dim
++)
3419 if (dd
->nc
[dim
] == 1)
3421 comm
->cell_x0
[dim
] = 0;
3422 comm
->cell_x1
[dim
] = ddbox
->box_size
[dim
];
3423 if (dim
>= ddbox
->nboundeddim
)
3425 comm
->cell_x0
[dim
] += ddbox
->box0
[dim
];
3426 comm
->cell_x1
[dim
] += ddbox
->box0
[dim
];
3432 static void realloc_comm_ind(gmx_domdec_t
*dd
, ivec npulse
)
3435 gmx_domdec_comm_dim_t
*cd
;
3437 for (d
= 0; d
< dd
->ndim
; d
++)
3439 cd
= &dd
->comm
->cd
[d
];
3440 np
= npulse
[dd
->dim
[d
]];
3441 if (np
> cd
->np_nalloc
)
3445 fprintf(debug
, "(Re)allocing cd for %c to %d pulses\n",
3446 dim2char(dd
->dim
[d
]), np
);
3448 if (DDMASTER(dd
) && cd
->np_nalloc
> 0)
3450 fprintf(stderr
, "\nIncreasing the number of cell to communicate in dimension %c to %d for the first time\n", dim2char(dd
->dim
[d
]), np
);
3452 srenew(cd
->ind
, np
);
3453 for (i
= cd
->np_nalloc
; i
< np
; i
++)
3455 cd
->ind
[i
].index
= nullptr;
3456 cd
->ind
[i
].nalloc
= 0;
3465 static void set_dd_cell_sizes(gmx_domdec_t
*dd
,
3466 gmx_ddbox_t
*ddbox
, gmx_bool bDynamicBox
,
3467 gmx_bool bUniform
, gmx_bool bDoDLB
, gmx_int64_t step
,
3468 gmx_wallcycle_t wcycle
)
3470 gmx_domdec_comm_t
*comm
;
3476 /* Copy the old cell boundaries for the cg displacement check */
3477 copy_rvec(comm
->cell_x0
, comm
->old_cell_x0
);
3478 copy_rvec(comm
->cell_x1
, comm
->old_cell_x1
);
3484 check_box_size(dd
, ddbox
);
3486 set_dd_cell_sizes_dlb(dd
, ddbox
, bDynamicBox
, bUniform
, bDoDLB
, step
, wcycle
);
3490 set_dd_cell_sizes_slb(dd
, ddbox
, setcellsizeslbLOCAL
, npulse
);
3491 realloc_comm_ind(dd
, npulse
);
3496 for (d
= 0; d
< DIM
; d
++)
3498 fprintf(debug
, "cell_x[%d] %f - %f skew_fac %f\n",
3499 d
, comm
->cell_x0
[d
], comm
->cell_x1
[d
], ddbox
->skew_fac
[d
]);
3504 static void comm_dd_ns_cell_sizes(gmx_domdec_t
*dd
,
3506 rvec cell_ns_x0
, rvec cell_ns_x1
,
3509 gmx_domdec_comm_t
*comm
;
3514 for (dim_ind
= 0; dim_ind
< dd
->ndim
; dim_ind
++)
3516 dim
= dd
->dim
[dim_ind
];
3518 /* Without PBC we don't have restrictions on the outer cells */
3519 if (!(dim
>= ddbox
->npbcdim
&&
3520 (dd
->ci
[dim
] == 0 || dd
->ci
[dim
] == dd
->nc
[dim
] - 1)) &&
3522 (comm
->cell_x1
[dim
] - comm
->cell_x0
[dim
])*ddbox
->skew_fac
[dim
] <
3523 comm
->cellsize_min
[dim
])
3526 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",
3527 gmx_step_str(step
, buf
), dim2char(dim
),
3528 comm
->cell_x1
[dim
] - comm
->cell_x0
[dim
],
3529 ddbox
->skew_fac
[dim
],
3530 dd
->comm
->cellsize_min
[dim
],
3531 dd
->ci
[XX
], dd
->ci
[YY
], dd
->ci
[ZZ
]);
3535 if ((isDlbOn(dd
->comm
) && dd
->ndim
> 1) || ddbox
->nboundeddim
< DIM
)
3537 /* Communicate the boundaries and update cell_ns_x0/1 */
3538 dd_move_cellx(dd
, ddbox
, cell_ns_x0
, cell_ns_x1
);
3539 if (isDlbOn(dd
->comm
) && dd
->ndim
> 1)
3541 check_grid_jump(step
, dd
, dd
->comm
->cutoff
, ddbox
, TRUE
);
3546 static void make_tric_corr_matrix(int npbcdim
, const matrix box
, matrix tcm
)
3550 tcm
[YY
][XX
] = -box
[YY
][XX
]/box
[YY
][YY
];
3558 tcm
[ZZ
][XX
] = -(box
[ZZ
][YY
]*tcm
[YY
][XX
] + box
[ZZ
][XX
])/box
[ZZ
][ZZ
];
3559 tcm
[ZZ
][YY
] = -box
[ZZ
][YY
]/box
[ZZ
][ZZ
];
3568 static void check_screw_box(const matrix box
)
3570 /* Mathematical limitation */
3571 if (box
[YY
][XX
] != 0 || box
[ZZ
][XX
] != 0)
3573 gmx_fatal(FARGS
, "With screw pbc the unit cell can not have non-zero off-diagonal x-components");
3576 /* Limitation due to the asymmetry of the eighth shell method */
3577 if (box
[ZZ
][YY
] != 0)
3579 gmx_fatal(FARGS
, "pbc=screw with non-zero box_zy is not supported");
3583 static void distribute_cg(FILE *fplog
,
3584 const matrix box
, ivec tric_dir
, t_block
*cgs
, rvec pos
[],
3587 gmx_domdec_master_t
*ma
;
3588 int **tmp_ind
= nullptr, *tmp_nalloc
= nullptr;
3589 int i
, icg
, j
, k
, k0
, k1
, d
;
3593 real nrcg
, inv_ncg
, pos_d
;
3599 snew(tmp_nalloc
, dd
->nnodes
);
3600 snew(tmp_ind
, dd
->nnodes
);
3601 for (i
= 0; i
< dd
->nnodes
; i
++)
3603 tmp_nalloc
[i
] = over_alloc_large(cgs
->nr
/dd
->nnodes
+1);
3604 snew(tmp_ind
[i
], tmp_nalloc
[i
]);
3607 /* Clear the count */
3608 for (i
= 0; i
< dd
->nnodes
; i
++)
3614 make_tric_corr_matrix(dd
->npbcdim
, box
, tcm
);
3616 cgindex
= cgs
->index
;
3618 /* Compute the center of geometry for all charge groups */
3619 for (icg
= 0; icg
< cgs
->nr
; icg
++)
3622 k1
= cgindex
[icg
+1];
3626 copy_rvec(pos
[k0
], cg_cm
);
3633 for (k
= k0
; (k
< k1
); k
++)
3635 rvec_inc(cg_cm
, pos
[k
]);
3637 for (d
= 0; (d
< DIM
); d
++)
3639 cg_cm
[d
] *= inv_ncg
;
3642 /* Put the charge group in the box and determine the cell index */
3643 for (d
= DIM
-1; d
>= 0; d
--)
3646 if (d
< dd
->npbcdim
)
3648 bScrew
= (dd
->bScrewPBC
&& d
== XX
);
3649 if (tric_dir
[d
] && dd
->nc
[d
] > 1)
3651 /* Use triclinic coordintates for this dimension */
3652 for (j
= d
+1; j
< DIM
; j
++)
3654 pos_d
+= cg_cm
[j
]*tcm
[j
][d
];
3657 while (pos_d
>= box
[d
][d
])
3660 rvec_dec(cg_cm
, box
[d
]);
3663 cg_cm
[YY
] = box
[YY
][YY
] - cg_cm
[YY
];
3664 cg_cm
[ZZ
] = box
[ZZ
][ZZ
] - cg_cm
[ZZ
];
3666 for (k
= k0
; (k
< k1
); k
++)
3668 rvec_dec(pos
[k
], box
[d
]);
3671 pos
[k
][YY
] = box
[YY
][YY
] - pos
[k
][YY
];
3672 pos
[k
][ZZ
] = box
[ZZ
][ZZ
] - pos
[k
][ZZ
];
3679 rvec_inc(cg_cm
, box
[d
]);
3682 cg_cm
[YY
] = box
[YY
][YY
] - cg_cm
[YY
];
3683 cg_cm
[ZZ
] = box
[ZZ
][ZZ
] - cg_cm
[ZZ
];
3685 for (k
= k0
; (k
< k1
); k
++)
3687 rvec_inc(pos
[k
], box
[d
]);
3690 pos
[k
][YY
] = box
[YY
][YY
] - pos
[k
][YY
];
3691 pos
[k
][ZZ
] = box
[ZZ
][ZZ
] - pos
[k
][ZZ
];
3696 /* This could be done more efficiently */
3698 while (ind
[d
]+1 < dd
->nc
[d
] && pos_d
>= ma
->cell_x
[d
][ind
[d
]+1])
3703 i
= dd_index(dd
->nc
, ind
);
3704 if (ma
->ncg
[i
] == tmp_nalloc
[i
])
3706 tmp_nalloc
[i
] = over_alloc_large(ma
->ncg
[i
]+1);
3707 srenew(tmp_ind
[i
], tmp_nalloc
[i
]);
3709 tmp_ind
[i
][ma
->ncg
[i
]] = icg
;
3711 ma
->nat
[i
] += cgindex
[icg
+1] - cgindex
[icg
];
3715 for (i
= 0; i
< dd
->nnodes
; i
++)
3718 for (k
= 0; k
< ma
->ncg
[i
]; k
++)
3720 ma
->cg
[k1
++] = tmp_ind
[i
][k
];
3723 ma
->index
[dd
->nnodes
] = k1
;
3725 for (i
= 0; i
< dd
->nnodes
; i
++)
3734 // Use double for the sums to avoid natoms^2 overflowing
3736 int nat_sum
, nat_min
, nat_max
;
3741 nat_min
= ma
->nat
[0];
3742 nat_max
= ma
->nat
[0];
3743 for (i
= 0; i
< dd
->nnodes
; i
++)
3745 nat_sum
+= ma
->nat
[i
];
3746 // cast to double to avoid integer overflows when squaring
3747 nat2_sum
+= gmx::square(static_cast<double>(ma
->nat
[i
]));
3748 nat_min
= std::min(nat_min
, ma
->nat
[i
]);
3749 nat_max
= std::max(nat_max
, ma
->nat
[i
]);
3751 nat_sum
/= dd
->nnodes
;
3752 nat2_sum
/= dd
->nnodes
;
3754 fprintf(fplog
, "Atom distribution over %d domains: av %d stddev %d min %d max %d\n",
3757 static_cast<int>(std::sqrt(nat2_sum
- gmx::square(static_cast<double>(nat_sum
)) + 0.5)),
3762 static void get_cg_distribution(FILE *fplog
, gmx_domdec_t
*dd
,
3763 t_block
*cgs
, const matrix box
, gmx_ddbox_t
*ddbox
,
3766 gmx_domdec_master_t
*ma
= nullptr;
3769 int *ibuf
, buf2
[2] = { 0, 0 };
3770 gmx_bool bMaster
= DDMASTER(dd
);
3778 check_screw_box(box
);
3781 set_dd_cell_sizes_slb(dd
, ddbox
, setcellsizeslbMASTER
, npulse
);
3783 distribute_cg(fplog
, box
, ddbox
->tric_dir
, cgs
, pos
, dd
);
3784 for (i
= 0; i
< dd
->nnodes
; i
++)
3786 ma
->ibuf
[2*i
] = ma
->ncg
[i
];
3787 ma
->ibuf
[2*i
+1] = ma
->nat
[i
];
3795 dd_scatter(dd
, 2*sizeof(int), ibuf
, buf2
);
3797 dd
->ncg_home
= buf2
[0];
3798 dd
->nat_home
= buf2
[1];
3799 dd
->ncg_tot
= dd
->ncg_home
;
3800 dd
->nat_tot
= dd
->nat_home
;
3801 if (dd
->ncg_home
> dd
->cg_nalloc
|| dd
->cg_nalloc
== 0)
3803 dd
->cg_nalloc
= over_alloc_dd(dd
->ncg_home
);
3804 srenew(dd
->index_gl
, dd
->cg_nalloc
);
3805 srenew(dd
->cgindex
, dd
->cg_nalloc
+1);
3809 for (i
= 0; i
< dd
->nnodes
; i
++)
3811 ma
->ibuf
[i
] = ma
->ncg
[i
]*sizeof(int);
3812 ma
->ibuf
[dd
->nnodes
+i
] = ma
->index
[i
]*sizeof(int);
3817 bMaster
? ma
->ibuf
: nullptr,
3818 bMaster
? ma
->ibuf
+dd
->nnodes
: nullptr,
3819 bMaster
? ma
->cg
: nullptr,
3820 dd
->ncg_home
*sizeof(int), dd
->index_gl
);
3822 /* Determine the home charge group sizes */
3824 for (i
= 0; i
< dd
->ncg_home
; i
++)
3826 cg_gl
= dd
->index_gl
[i
];
3828 dd
->cgindex
[i
] + cgs
->index
[cg_gl
+1] - cgs
->index
[cg_gl
];
3833 fprintf(debug
, "Home charge groups:\n");
3834 for (i
= 0; i
< dd
->ncg_home
; i
++)
3836 fprintf(debug
, " %d", dd
->index_gl
[i
]);
3839 fprintf(debug
, "\n");
3842 fprintf(debug
, "\n");
3846 static int compact_and_copy_vec_at(int ncg
, int *move
,
3849 rvec
*src
, gmx_domdec_comm_t
*comm
,
3852 int m
, icg
, i
, i0
, i1
, nrcg
;
3858 for (m
= 0; m
< DIM
*2; m
++)
3864 for (icg
= 0; icg
< ncg
; icg
++)
3866 i1
= cgindex
[icg
+1];
3872 /* Compact the home array in place */
3873 for (i
= i0
; i
< i1
; i
++)
3875 copy_rvec(src
[i
], src
[home_pos
++]);
3881 /* Copy to the communication buffer */
3883 pos_vec
[m
] += 1 + vec
*nrcg
;
3884 for (i
= i0
; i
< i1
; i
++)
3886 copy_rvec(src
[i
], comm
->cgcm_state
[m
][pos_vec
[m
]++]);
3888 pos_vec
[m
] += (nvec
- vec
- 1)*nrcg
;
3892 home_pos
+= i1
- i0
;
3900 static int compact_and_copy_vec_cg(int ncg
, int *move
,
3902 int nvec
, rvec
*src
, gmx_domdec_comm_t
*comm
,
3905 int m
, icg
, i0
, i1
, nrcg
;
3911 for (m
= 0; m
< DIM
*2; m
++)
3917 for (icg
= 0; icg
< ncg
; icg
++)
3919 i1
= cgindex
[icg
+1];
3925 /* Compact the home array in place */
3926 copy_rvec(src
[icg
], src
[home_pos
++]);
3932 /* Copy to the communication buffer */
3933 copy_rvec(src
[icg
], comm
->cgcm_state
[m
][pos_vec
[m
]]);
3934 pos_vec
[m
] += 1 + nrcg
*nvec
;
3946 static int compact_ind(int ncg
, int *move
,
3947 int *index_gl
, int *cgindex
,
3949 gmx_ga2la_t
*ga2la
, char *bLocalCG
,
3952 int cg
, nat
, a0
, a1
, a
, a_gl
;
3957 for (cg
= 0; cg
< ncg
; cg
++)
3963 /* Compact the home arrays in place.
3964 * Anything that can be done here avoids access to global arrays.
3966 cgindex
[home_pos
] = nat
;
3967 for (a
= a0
; a
< a1
; a
++)
3970 gatindex
[nat
] = a_gl
;
3971 /* The cell number stays 0, so we don't need to set it */
3972 ga2la_change_la(ga2la
, a_gl
, nat
);
3975 index_gl
[home_pos
] = index_gl
[cg
];
3976 cginfo
[home_pos
] = cginfo
[cg
];
3977 /* The charge group remains local, so bLocalCG does not change */
3982 /* Clear the global indices */
3983 for (a
= a0
; a
< a1
; a
++)
3985 ga2la_del(ga2la
, gatindex
[a
]);
3989 bLocalCG
[index_gl
[cg
]] = FALSE
;
3993 cgindex
[home_pos
] = nat
;
3998 static void clear_and_mark_ind(int ncg
, int *move
,
3999 int *index_gl
, int *cgindex
, int *gatindex
,
4000 gmx_ga2la_t
*ga2la
, char *bLocalCG
,
4005 for (cg
= 0; cg
< ncg
; cg
++)
4011 /* Clear the global indices */
4012 for (a
= a0
; a
< a1
; a
++)
4014 ga2la_del(ga2la
, gatindex
[a
]);
4018 bLocalCG
[index_gl
[cg
]] = FALSE
;
4020 /* Signal that this cg has moved using the ns cell index.
4021 * Here we set it to -1. fill_grid will change it
4022 * from -1 to NSGRID_SIGNAL_MOVED_FAC*grid->ncells.
4024 cell_index
[cg
] = -1;
4029 static void print_cg_move(FILE *fplog
,
4031 gmx_int64_t step
, int cg
, int dim
, int dir
,
4032 gmx_bool bHaveCgcmOld
, real limitd
,
4033 rvec cm_old
, rvec cm_new
, real pos_d
)
4035 gmx_domdec_comm_t
*comm
;
4040 fprintf(fplog
, "\nStep %s:\n", gmx_step_str(step
, buf
));
4043 fprintf(fplog
, "%s %d moved more than the distance allowed by the domain decomposition (%f) in direction %c\n",
4044 dd
->comm
->bCGs
? "The charge group starting at atom" : "Atom",
4045 ddglatnr(dd
, dd
->cgindex
[cg
]), limitd
, dim2char(dim
));
4049 /* We don't have a limiting distance available: don't print it */
4050 fprintf(fplog
, "%s %d moved more than the distance allowed by the domain decomposition in direction %c\n",
4051 dd
->comm
->bCGs
? "The charge group starting at atom" : "Atom",
4052 ddglatnr(dd
, dd
->cgindex
[cg
]), dim2char(dim
));
4054 fprintf(fplog
, "distance out of cell %f\n",
4055 dir
== 1 ? pos_d
- comm
->cell_x1
[dim
] : pos_d
- comm
->cell_x0
[dim
]);
4058 fprintf(fplog
, "Old coordinates: %8.3f %8.3f %8.3f\n",
4059 cm_old
[XX
], cm_old
[YY
], cm_old
[ZZ
]);
4061 fprintf(fplog
, "New coordinates: %8.3f %8.3f %8.3f\n",
4062 cm_new
[XX
], cm_new
[YY
], cm_new
[ZZ
]);
4063 fprintf(fplog
, "Old cell boundaries in direction %c: %8.3f %8.3f\n",
4065 comm
->old_cell_x0
[dim
], comm
->old_cell_x1
[dim
]);
4066 fprintf(fplog
, "New cell boundaries in direction %c: %8.3f %8.3f\n",
4068 comm
->cell_x0
[dim
], comm
->cell_x1
[dim
]);
4071 static void cg_move_error(FILE *fplog
,
4073 gmx_int64_t step
, int cg
, int dim
, int dir
,
4074 gmx_bool bHaveCgcmOld
, real limitd
,
4075 rvec cm_old
, rvec cm_new
, real pos_d
)
4079 print_cg_move(fplog
, dd
, step
, cg
, dim
, dir
,
4080 bHaveCgcmOld
, limitd
, cm_old
, cm_new
, pos_d
);
4082 print_cg_move(stderr
, dd
, step
, cg
, dim
, dir
,
4083 bHaveCgcmOld
, limitd
, cm_old
, cm_new
, pos_d
);
4085 "%s moved too far between two domain decomposition steps\n"
4086 "This usually means that your system is not well equilibrated",
4087 dd
->comm
->bCGs
? "A charge group" : "An atom");
4090 static void rotate_state_atom(t_state
*state
, int a
)
4092 if (state
->flags
& (1 << estX
))
4094 /* Rotate the complete state; for a rectangular box only */
4095 state
->x
[a
][YY
] = state
->box
[YY
][YY
] - state
->x
[a
][YY
];
4096 state
->x
[a
][ZZ
] = state
->box
[ZZ
][ZZ
] - state
->x
[a
][ZZ
];
4098 if (state
->flags
& (1 << estV
))
4100 state
->v
[a
][YY
] = -state
->v
[a
][YY
];
4101 state
->v
[a
][ZZ
] = -state
->v
[a
][ZZ
];
4103 if (state
->flags
& (1 << estCGP
))
4105 state
->cg_p
[a
][YY
] = -state
->cg_p
[a
][YY
];
4106 state
->cg_p
[a
][ZZ
] = -state
->cg_p
[a
][ZZ
];
4110 static int *get_moved(gmx_domdec_comm_t
*comm
, int natoms
)
4112 if (natoms
> comm
->moved_nalloc
)
4114 /* Contents should be preserved here */
4115 comm
->moved_nalloc
= over_alloc_dd(natoms
);
4116 srenew(comm
->moved
, comm
->moved_nalloc
);
4122 static void calc_cg_move(FILE *fplog
, gmx_int64_t step
,
4125 ivec tric_dir
, matrix tcm
,
4126 rvec cell_x0
, rvec cell_x1
,
4127 rvec limitd
, rvec limit0
, rvec limit1
,
4129 int cg_start
, int cg_end
,
4134 int cg
, k
, k0
, k1
, d
, dim
, d2
;
4139 real inv_ncg
, pos_d
;
4142 npbcdim
= dd
->npbcdim
;
4144 for (cg
= cg_start
; cg
< cg_end
; cg
++)
4151 copy_rvec(state
->x
[k0
], cm_new
);
4158 for (k
= k0
; (k
< k1
); k
++)
4160 rvec_inc(cm_new
, state
->x
[k
]);
4162 for (d
= 0; (d
< DIM
); d
++)
4164 cm_new
[d
] = inv_ncg
*cm_new
[d
];
4169 /* Do pbc and check DD cell boundary crossings */
4170 for (d
= DIM
-1; d
>= 0; d
--)
4174 bScrew
= (dd
->bScrewPBC
&& d
== XX
);
4175 /* Determine the location of this cg in lattice coordinates */
4179 for (d2
= d
+1; d2
< DIM
; d2
++)
4181 pos_d
+= cm_new
[d2
]*tcm
[d2
][d
];
4184 /* Put the charge group in the triclinic unit-cell */
4185 if (pos_d
>= cell_x1
[d
])
4187 if (pos_d
>= limit1
[d
])
4189 cg_move_error(fplog
, dd
, step
, cg
, d
, 1,
4190 cg_cm
!= as_rvec_array(state
->x
.data()), limitd
[d
],
4191 cg_cm
[cg
], cm_new
, pos_d
);
4194 if (dd
->ci
[d
] == dd
->nc
[d
] - 1)
4196 rvec_dec(cm_new
, state
->box
[d
]);
4199 cm_new
[YY
] = state
->box
[YY
][YY
] - cm_new
[YY
];
4200 cm_new
[ZZ
] = state
->box
[ZZ
][ZZ
] - cm_new
[ZZ
];
4202 for (k
= k0
; (k
< k1
); k
++)
4204 rvec_dec(state
->x
[k
], state
->box
[d
]);
4207 rotate_state_atom(state
, k
);
4212 else if (pos_d
< cell_x0
[d
])
4214 if (pos_d
< limit0
[d
])
4216 cg_move_error(fplog
, dd
, step
, cg
, d
, -1,
4217 cg_cm
!= as_rvec_array(state
->x
.data()), limitd
[d
],
4218 cg_cm
[cg
], cm_new
, pos_d
);
4223 rvec_inc(cm_new
, state
->box
[d
]);
4226 cm_new
[YY
] = state
->box
[YY
][YY
] - cm_new
[YY
];
4227 cm_new
[ZZ
] = state
->box
[ZZ
][ZZ
] - cm_new
[ZZ
];
4229 for (k
= k0
; (k
< k1
); k
++)
4231 rvec_inc(state
->x
[k
], state
->box
[d
]);
4234 rotate_state_atom(state
, k
);
4240 else if (d
< npbcdim
)
4242 /* Put the charge group in the rectangular unit-cell */
4243 while (cm_new
[d
] >= state
->box
[d
][d
])
4245 rvec_dec(cm_new
, state
->box
[d
]);
4246 for (k
= k0
; (k
< k1
); k
++)
4248 rvec_dec(state
->x
[k
], state
->box
[d
]);
4251 while (cm_new
[d
] < 0)
4253 rvec_inc(cm_new
, state
->box
[d
]);
4254 for (k
= k0
; (k
< k1
); k
++)
4256 rvec_inc(state
->x
[k
], state
->box
[d
]);
4262 copy_rvec(cm_new
, cg_cm
[cg
]);
4264 /* Determine where this cg should go */
4267 for (d
= 0; d
< dd
->ndim
; d
++)
4272 flag
|= DD_FLAG_FW(d
);
4278 else if (dev
[dim
] == -1)
4280 flag
|= DD_FLAG_BW(d
);
4283 if (dd
->nc
[dim
] > 2)
4294 /* Temporarily store the flag in move */
4295 move
[cg
] = mc
+ flag
;
4299 static void dd_redistribute_cg(FILE *fplog
, gmx_int64_t step
,
4300 gmx_domdec_t
*dd
, ivec tric_dir
,
4301 t_state
*state
, PaddedRVecVector
*f
,
4310 int ncg
[DIM
*2] = { 0 }, nat
[DIM
*2] = { 0 };
4311 int i
, cg
, k
, d
, dim
, dim2
, dir
, d2
, d3
;
4312 int mc
, cdd
, nrcg
, ncg_recv
, nvs
, nvr
, nvec
, vec
;
4313 int sbuf
[2], rbuf
[2];
4314 int home_pos_cg
, home_pos_at
, buf_pos
;
4318 rvec
*cg_cm
= nullptr, cell_x0
, cell_x1
, limitd
, limit0
, limit1
;
4320 cginfo_mb_t
*cginfo_mb
;
4321 gmx_domdec_comm_t
*comm
;
4323 int nthread
, thread
;
4327 check_screw_box(state
->box
);
4331 if (fr
->cutoff_scheme
== ecutsGROUP
)
4336 // Positions are always present, so there's nothing to flag
4337 bool bV
= state
->flags
& (1<<estV
);
4338 bool bCGP
= state
->flags
& (1<<estCGP
);
4340 if (dd
->ncg_tot
> comm
->nalloc_int
)
4342 comm
->nalloc_int
= over_alloc_dd(dd
->ncg_tot
);
4343 srenew(comm
->buf_int
, comm
->nalloc_int
);
4345 move
= comm
->buf_int
;
4347 npbcdim
= dd
->npbcdim
;
4349 for (d
= 0; (d
< DIM
); d
++)
4351 limitd
[d
] = dd
->comm
->cellsize_min
[d
];
4352 if (d
>= npbcdim
&& dd
->ci
[d
] == 0)
4354 cell_x0
[d
] = -GMX_FLOAT_MAX
;
4358 cell_x0
[d
] = comm
->cell_x0
[d
];
4360 if (d
>= npbcdim
&& dd
->ci
[d
] == dd
->nc
[d
] - 1)
4362 cell_x1
[d
] = GMX_FLOAT_MAX
;
4366 cell_x1
[d
] = comm
->cell_x1
[d
];
4370 limit0
[d
] = comm
->old_cell_x0
[d
] - limitd
[d
];
4371 limit1
[d
] = comm
->old_cell_x1
[d
] + limitd
[d
];
4375 /* We check after communication if a charge group moved
4376 * more than one cell. Set the pre-comm check limit to float_max.
4378 limit0
[d
] = -GMX_FLOAT_MAX
;
4379 limit1
[d
] = GMX_FLOAT_MAX
;
4383 make_tric_corr_matrix(npbcdim
, state
->box
, tcm
);
4385 cgindex
= dd
->cgindex
;
4387 nthread
= gmx_omp_nthreads_get(emntDomdec
);
4389 /* Compute the center of geometry for all home charge groups
4390 * and put them in the box and determine where they should go.
4392 #pragma omp parallel for num_threads(nthread) schedule(static)
4393 for (thread
= 0; thread
< nthread
; thread
++)
4397 calc_cg_move(fplog
, step
, dd
, state
, tric_dir
, tcm
,
4398 cell_x0
, cell_x1
, limitd
, limit0
, limit1
,
4400 ( thread
*dd
->ncg_home
)/nthread
,
4401 ((thread
+1)*dd
->ncg_home
)/nthread
,
4402 fr
->cutoff_scheme
== ecutsGROUP
? cg_cm
: as_rvec_array(state
->x
.data()),
4405 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
;
4408 for (cg
= 0; cg
< dd
->ncg_home
; cg
++)
4413 flag
= mc
& ~DD_FLAG_NRCG
;
4414 mc
= mc
& DD_FLAG_NRCG
;
4417 if (ncg
[mc
]+1 > comm
->cggl_flag_nalloc
[mc
])
4419 comm
->cggl_flag_nalloc
[mc
] = over_alloc_dd(ncg
[mc
]+1);
4420 srenew(comm
->cggl_flag
[mc
], comm
->cggl_flag_nalloc
[mc
]*DD_CGIBS
);
4422 comm
->cggl_flag
[mc
][ncg
[mc
]*DD_CGIBS
] = dd
->index_gl
[cg
];
4423 /* We store the cg size in the lower 16 bits
4424 * and the place where the charge group should go
4425 * in the next 6 bits. This saves some communication volume.
4427 nrcg
= cgindex
[cg
+1] - cgindex
[cg
];
4428 comm
->cggl_flag
[mc
][ncg
[mc
]*DD_CGIBS
+1] = nrcg
| flag
;
4434 inc_nrnb(nrnb
, eNR_CGCM
, dd
->nat_home
);
4435 inc_nrnb(nrnb
, eNR_RESETX
, dd
->ncg_home
);
4438 for (i
= 0; i
< dd
->ndim
*2; i
++)
4440 *ncg_moved
+= ncg
[i
];
4453 /* Make sure the communication buffers are large enough */
4454 for (mc
= 0; mc
< dd
->ndim
*2; mc
++)
4456 nvr
= ncg
[mc
] + nat
[mc
]*nvec
;
4457 if (nvr
> comm
->cgcm_state_nalloc
[mc
])
4459 comm
->cgcm_state_nalloc
[mc
] = over_alloc_dd(nvr
);
4460 srenew(comm
->cgcm_state
[mc
], comm
->cgcm_state_nalloc
[mc
]);
4464 switch (fr
->cutoff_scheme
)
4467 /* Recalculating cg_cm might be cheaper than communicating,
4468 * but that could give rise to rounding issues.
4471 compact_and_copy_vec_cg(dd
->ncg_home
, move
, cgindex
,
4472 nvec
, cg_cm
, comm
, bCompact
);
4475 /* Without charge groups we send the moved atom coordinates
4476 * over twice. This is so the code below can be used without
4477 * many conditionals for both for with and without charge groups.
4480 compact_and_copy_vec_cg(dd
->ncg_home
, move
, cgindex
,
4481 nvec
, as_rvec_array(state
->x
.data()), comm
, FALSE
);
4484 home_pos_cg
-= *ncg_moved
;
4488 gmx_incons("unimplemented");
4494 compact_and_copy_vec_at(dd
->ncg_home
, move
, cgindex
,
4495 nvec
, vec
++, as_rvec_array(state
->x
.data()),
4499 compact_and_copy_vec_at(dd
->ncg_home
, move
, cgindex
,
4500 nvec
, vec
++, as_rvec_array(state
->v
.data()),
4505 compact_and_copy_vec_at(dd
->ncg_home
, move
, cgindex
,
4506 nvec
, vec
++, as_rvec_array(state
->cg_p
.data()),
4512 compact_ind(dd
->ncg_home
, move
,
4513 dd
->index_gl
, dd
->cgindex
, dd
->gatindex
,
4514 dd
->ga2la
, comm
->bLocalCG
,
4519 if (fr
->cutoff_scheme
== ecutsVERLET
)
4521 moved
= get_moved(comm
, dd
->ncg_home
);
4523 for (k
= 0; k
< dd
->ncg_home
; k
++)
4530 moved
= fr
->ns
->grid
->cell_index
;
4533 clear_and_mark_ind(dd
->ncg_home
, move
,
4534 dd
->index_gl
, dd
->cgindex
, dd
->gatindex
,
4535 dd
->ga2la
, comm
->bLocalCG
,
4539 cginfo_mb
= fr
->cginfo_mb
;
4541 *ncg_stay_home
= home_pos_cg
;
4542 for (d
= 0; d
< dd
->ndim
; d
++)
4547 for (dir
= 0; dir
< (dd
->nc
[dim
] == 2 ? 1 : 2); dir
++)
4550 /* Communicate the cg and atom counts */
4555 fprintf(debug
, "Sending ddim %d dir %d: ncg %d nat %d\n",
4556 d
, dir
, sbuf
[0], sbuf
[1]);
4558 dd_sendrecv_int(dd
, d
, dir
, sbuf
, 2, rbuf
, 2);
4560 if ((ncg_recv
+rbuf
[0])*DD_CGIBS
> comm
->nalloc_int
)
4562 comm
->nalloc_int
= over_alloc_dd((ncg_recv
+rbuf
[0])*DD_CGIBS
);
4563 srenew(comm
->buf_int
, comm
->nalloc_int
);
4566 /* Communicate the charge group indices, sizes and flags */
4567 dd_sendrecv_int(dd
, d
, dir
,
4568 comm
->cggl_flag
[cdd
], sbuf
[0]*DD_CGIBS
,
4569 comm
->buf_int
+ncg_recv
*DD_CGIBS
, rbuf
[0]*DD_CGIBS
);
4571 nvs
= ncg
[cdd
] + nat
[cdd
]*nvec
;
4572 i
= rbuf
[0] + rbuf
[1] *nvec
;
4573 vec_rvec_check_alloc(&comm
->vbuf
, nvr
+i
);
4575 /* Communicate cgcm and state */
4576 dd_sendrecv_rvec(dd
, d
, dir
,
4577 comm
->cgcm_state
[cdd
], nvs
,
4578 comm
->vbuf
.v
+nvr
, i
);
4579 ncg_recv
+= rbuf
[0];
4583 dd_check_alloc_ncg(fr
, state
, f
, home_pos_cg
+ ncg_recv
);
4584 if (fr
->cutoff_scheme
== ecutsGROUP
)
4586 /* Here we resize to more than necessary and shrink later */
4587 dd_resize_state(state
, f
, home_pos_at
+ ncg_recv
*MAX_CGCGSIZE
);
4590 /* Process the received charge groups */
4592 for (cg
= 0; cg
< ncg_recv
; cg
++)
4594 flag
= comm
->buf_int
[cg
*DD_CGIBS
+1];
4596 if (dim
>= npbcdim
&& dd
->nc
[dim
] > 2)
4598 /* No pbc in this dim and more than one domain boundary.
4599 * We do a separate check if a charge group didn't move too far.
4601 if (((flag
& DD_FLAG_FW(d
)) &&
4602 comm
->vbuf
.v
[buf_pos
][dim
] > cell_x1
[dim
]) ||
4603 ((flag
& DD_FLAG_BW(d
)) &&
4604 comm
->vbuf
.v
[buf_pos
][dim
] < cell_x0
[dim
]))
4606 cg_move_error(fplog
, dd
, step
, cg
, dim
,
4607 (flag
& DD_FLAG_FW(d
)) ? 1 : 0,
4608 fr
->cutoff_scheme
== ecutsGROUP
, 0,
4609 comm
->vbuf
.v
[buf_pos
],
4610 comm
->vbuf
.v
[buf_pos
],
4611 comm
->vbuf
.v
[buf_pos
][dim
]);
4618 /* Check which direction this cg should go */
4619 for (d2
= d
+1; (d2
< dd
->ndim
&& mc
== -1); d2
++)
4621 if (isDlbOn(dd
->comm
))
4623 /* The cell boundaries for dimension d2 are not equal
4624 * for each cell row of the lower dimension(s),
4625 * therefore we might need to redetermine where
4626 * this cg should go.
4629 /* If this cg crosses the box boundary in dimension d2
4630 * we can use the communicated flag, so we do not
4631 * have to worry about pbc.
4633 if (!((dd
->ci
[dim2
] == dd
->nc
[dim2
]-1 &&
4634 (flag
& DD_FLAG_FW(d2
))) ||
4635 (dd
->ci
[dim2
] == 0 &&
4636 (flag
& DD_FLAG_BW(d2
)))))
4638 /* Clear the two flags for this dimension */
4639 flag
&= ~(DD_FLAG_FW(d2
) | DD_FLAG_BW(d2
));
4640 /* Determine the location of this cg
4641 * in lattice coordinates
4643 pos_d
= comm
->vbuf
.v
[buf_pos
][dim2
];
4646 for (d3
= dim2
+1; d3
< DIM
; d3
++)
4649 comm
->vbuf
.v
[buf_pos
][d3
]*tcm
[d3
][dim2
];
4652 /* Check of we are not at the box edge.
4653 * pbc is only handled in the first step above,
4654 * but this check could move over pbc while
4655 * the first step did not due to different rounding.
4657 if (pos_d
>= cell_x1
[dim2
] &&
4658 dd
->ci
[dim2
] != dd
->nc
[dim2
]-1)
4660 flag
|= DD_FLAG_FW(d2
);
4662 else if (pos_d
< cell_x0
[dim2
] &&
4665 flag
|= DD_FLAG_BW(d2
);
4667 comm
->buf_int
[cg
*DD_CGIBS
+1] = flag
;
4670 /* Set to which neighboring cell this cg should go */
4671 if (flag
& DD_FLAG_FW(d2
))
4675 else if (flag
& DD_FLAG_BW(d2
))
4677 if (dd
->nc
[dd
->dim
[d2
]] > 2)
4689 nrcg
= flag
& DD_FLAG_NRCG
;
4692 if (home_pos_cg
+1 > dd
->cg_nalloc
)
4694 dd
->cg_nalloc
= over_alloc_dd(home_pos_cg
+1);
4695 srenew(dd
->index_gl
, dd
->cg_nalloc
);
4696 srenew(dd
->cgindex
, dd
->cg_nalloc
+1);
4698 /* Set the global charge group index and size */
4699 dd
->index_gl
[home_pos_cg
] = comm
->buf_int
[cg
*DD_CGIBS
];
4700 dd
->cgindex
[home_pos_cg
+1] = dd
->cgindex
[home_pos_cg
] + nrcg
;
4701 /* Copy the state from the buffer */
4702 if (fr
->cutoff_scheme
== ecutsGROUP
)
4705 copy_rvec(comm
->vbuf
.v
[buf_pos
], cg_cm
[home_pos_cg
]);
4709 /* Set the cginfo */
4710 fr
->cginfo
[home_pos_cg
] = ddcginfo(cginfo_mb
,
4711 dd
->index_gl
[home_pos_cg
]);
4714 comm
->bLocalCG
[dd
->index_gl
[home_pos_cg
]] = TRUE
;
4717 for (i
= 0; i
< nrcg
; i
++)
4719 copy_rvec(comm
->vbuf
.v
[buf_pos
++],
4720 state
->x
[home_pos_at
+i
]);
4724 for (i
= 0; i
< nrcg
; i
++)
4726 copy_rvec(comm
->vbuf
.v
[buf_pos
++],
4727 state
->v
[home_pos_at
+i
]);
4732 for (i
= 0; i
< nrcg
; i
++)
4734 copy_rvec(comm
->vbuf
.v
[buf_pos
++],
4735 state
->cg_p
[home_pos_at
+i
]);
4739 home_pos_at
+= nrcg
;
4743 /* Reallocate the buffers if necessary */
4744 if (ncg
[mc
]+1 > comm
->cggl_flag_nalloc
[mc
])
4746 comm
->cggl_flag_nalloc
[mc
] = over_alloc_dd(ncg
[mc
]+1);
4747 srenew(comm
->cggl_flag
[mc
], comm
->cggl_flag_nalloc
[mc
]*DD_CGIBS
);
4749 nvr
= ncg
[mc
] + nat
[mc
]*nvec
;
4750 if (nvr
+ 1 + nrcg
*nvec
> comm
->cgcm_state_nalloc
[mc
])
4752 comm
->cgcm_state_nalloc
[mc
] = over_alloc_dd(nvr
+ 1 + nrcg
*nvec
);
4753 srenew(comm
->cgcm_state
[mc
], comm
->cgcm_state_nalloc
[mc
]);
4755 /* Copy from the receive to the send buffers */
4756 memcpy(comm
->cggl_flag
[mc
] + ncg
[mc
]*DD_CGIBS
,
4757 comm
->buf_int
+ cg
*DD_CGIBS
,
4758 DD_CGIBS
*sizeof(int));
4759 memcpy(comm
->cgcm_state
[mc
][nvr
],
4760 comm
->vbuf
.v
[buf_pos
],
4761 (1+nrcg
*nvec
)*sizeof(rvec
));
4762 buf_pos
+= 1 + nrcg
*nvec
;
4769 /* With sorting (!bCompact) the indices are now only partially up to date
4770 * and ncg_home and nat_home are not the real count, since there are
4771 * "holes" in the arrays for the charge groups that moved to neighbors.
4773 if (fr
->cutoff_scheme
== ecutsVERLET
)
4775 moved
= get_moved(comm
, home_pos_cg
);
4777 for (i
= dd
->ncg_home
; i
< home_pos_cg
; i
++)
4782 dd
->ncg_home
= home_pos_cg
;
4783 dd
->nat_home
= home_pos_at
;
4785 if (fr
->cutoff_scheme
== ecutsGROUP
&& !bCompact
)
4787 /* We overallocated before, we need to set the right size here */
4788 dd_resize_state(state
, f
, dd
->nat_home
);
4794 "Finished repartitioning: cgs moved out %d, new home %d\n",
4795 *ncg_moved
, dd
->ncg_home
-*ncg_moved
);
4800 void dd_cycles_add(const gmx_domdec_t
*dd
, float cycles
, int ddCycl
)
4802 /* Note that the cycles value can be incorrect, either 0 or some
4803 * extremely large value, when our thread migrated to another core
4804 * with an unsynchronized cycle counter. If this happens less often
4805 * that once per nstlist steps, this will not cause issues, since
4806 * we later subtract the maximum value from the sum over nstlist steps.
4807 * A zero count will slightly lower the total, but that's a small effect.
4808 * Note that the main purpose of the subtraction of the maximum value
4809 * is to avoid throwing off the load balancing when stalls occur due
4810 * e.g. system activity or network congestion.
4812 dd
->comm
->cycl
[ddCycl
] += cycles
;
4813 dd
->comm
->cycl_n
[ddCycl
]++;
4814 if (cycles
> dd
->comm
->cycl_max
[ddCycl
])
4816 dd
->comm
->cycl_max
[ddCycl
] = cycles
;
4820 static double force_flop_count(t_nrnb
*nrnb
)
4827 for (i
= 0; i
< eNR_NBKERNEL_FREE_ENERGY
; i
++)
4829 /* To get closer to the real timings, we half the count
4830 * for the normal loops and again half it for water loops.
4833 if (strstr(name
, "W3") != nullptr || strstr(name
, "W4") != nullptr)
4835 sum
+= nrnb
->n
[i
]*0.25*cost_nrnb(i
);
4839 sum
+= nrnb
->n
[i
]*0.50*cost_nrnb(i
);
4842 for (i
= eNR_NBKERNEL_FREE_ENERGY
; i
<= eNR_NB14
; i
++)
4845 if (strstr(name
, "W3") != nullptr || strstr(name
, "W4") != nullptr)
4847 sum
+= nrnb
->n
[i
]*cost_nrnb(i
);
4850 for (i
= eNR_BONDS
; i
<= eNR_WALLS
; i
++)
4852 sum
+= nrnb
->n
[i
]*cost_nrnb(i
);
4858 void dd_force_flop_start(gmx_domdec_t
*dd
, t_nrnb
*nrnb
)
4860 if (dd
->comm
->eFlop
)
4862 dd
->comm
->flop
-= force_flop_count(nrnb
);
4865 void dd_force_flop_stop(gmx_domdec_t
*dd
, t_nrnb
*nrnb
)
4867 if (dd
->comm
->eFlop
)
4869 dd
->comm
->flop
+= force_flop_count(nrnb
);
4874 static void clear_dd_cycle_counts(gmx_domdec_t
*dd
)
4878 for (i
= 0; i
< ddCyclNr
; i
++)
4880 dd
->comm
->cycl
[i
] = 0;
4881 dd
->comm
->cycl_n
[i
] = 0;
4882 dd
->comm
->cycl_max
[i
] = 0;
4885 dd
->comm
->flop_n
= 0;
4888 static void get_load_distribution(gmx_domdec_t
*dd
, gmx_wallcycle_t wcycle
)
4890 gmx_domdec_comm_t
*comm
;
4891 domdec_load_t
*load
;
4892 domdec_root_t
*root
= nullptr;
4894 float cell_frac
= 0, sbuf
[DD_NLOAD_MAX
];
4899 fprintf(debug
, "get_load_distribution start\n");
4902 wallcycle_start(wcycle
, ewcDDCOMMLOAD
);
4906 bSepPME
= (dd
->pme_nodeid
>= 0);
4908 if (dd
->ndim
== 0 && bSepPME
)
4910 /* Without decomposition, but with PME nodes, we need the load */
4911 comm
->load
[0].mdf
= comm
->cycl
[ddCyclPPduringPME
];
4912 comm
->load
[0].pme
= comm
->cycl
[ddCyclPME
];
4915 for (d
= dd
->ndim
-1; d
>= 0; d
--)
4918 /* Check if we participate in the communication in this dimension */
4919 if (d
== dd
->ndim
-1 ||
4920 (dd
->ci
[dd
->dim
[d
+1]] == 0 && dd
->ci
[dd
->dim
[dd
->ndim
-1]] == 0))
4922 load
= &comm
->load
[d
];
4923 if (isDlbOn(dd
->comm
))
4925 cell_frac
= comm
->cell_f1
[d
] - comm
->cell_f0
[d
];
4928 if (d
== dd
->ndim
-1)
4930 sbuf
[pos
++] = dd_force_load(comm
);
4931 sbuf
[pos
++] = sbuf
[0];
4932 if (isDlbOn(dd
->comm
))
4934 sbuf
[pos
++] = sbuf
[0];
4935 sbuf
[pos
++] = cell_frac
;
4938 sbuf
[pos
++] = comm
->cell_f_max0
[d
];
4939 sbuf
[pos
++] = comm
->cell_f_min1
[d
];
4944 sbuf
[pos
++] = comm
->cycl
[ddCyclPPduringPME
];
4945 sbuf
[pos
++] = comm
->cycl
[ddCyclPME
];
4950 sbuf
[pos
++] = comm
->load
[d
+1].sum
;
4951 sbuf
[pos
++] = comm
->load
[d
+1].max
;
4952 if (isDlbOn(dd
->comm
))
4954 sbuf
[pos
++] = comm
->load
[d
+1].sum_m
;
4955 sbuf
[pos
++] = comm
->load
[d
+1].cvol_min
*cell_frac
;
4956 sbuf
[pos
++] = comm
->load
[d
+1].flags
;
4959 sbuf
[pos
++] = comm
->cell_f_max0
[d
];
4960 sbuf
[pos
++] = comm
->cell_f_min1
[d
];
4965 sbuf
[pos
++] = comm
->load
[d
+1].mdf
;
4966 sbuf
[pos
++] = comm
->load
[d
+1].pme
;
4970 /* Communicate a row in DD direction d.
4971 * The communicators are setup such that the root always has rank 0.
4974 MPI_Gather(sbuf
, load
->nload
*sizeof(float), MPI_BYTE
,
4975 load
->load
, load
->nload
*sizeof(float), MPI_BYTE
,
4976 0, comm
->mpi_comm_load
[d
]);
4978 if (dd
->ci
[dim
] == dd
->master_ci
[dim
])
4980 /* We are the root, process this row */
4983 root
= comm
->root
[d
];
4993 for (i
= 0; i
< dd
->nc
[dim
]; i
++)
4995 load
->sum
+= load
->load
[pos
++];
4996 load
->max
= std::max(load
->max
, load
->load
[pos
]);
4998 if (isDlbOn(dd
->comm
))
5002 /* This direction could not be load balanced properly,
5003 * therefore we need to use the maximum iso the average load.
5005 load
->sum_m
= std::max(load
->sum_m
, load
->load
[pos
]);
5009 load
->sum_m
+= load
->load
[pos
];
5012 load
->cvol_min
= std::min(load
->cvol_min
, load
->load
[pos
]);
5016 load
->flags
= (int)(load
->load
[pos
++] + 0.5);
5020 root
->cell_f_max0
[i
] = load
->load
[pos
++];
5021 root
->cell_f_min1
[i
] = load
->load
[pos
++];
5026 load
->mdf
= std::max(load
->mdf
, load
->load
[pos
]);
5028 load
->pme
= std::max(load
->pme
, load
->load
[pos
]);
5032 if (isDlbOn(comm
) && root
->bLimited
)
5034 load
->sum_m
*= dd
->nc
[dim
];
5035 load
->flags
|= (1<<d
);
5043 comm
->nload
+= dd_load_count(comm
);
5044 comm
->load_step
+= comm
->cycl
[ddCyclStep
];
5045 comm
->load_sum
+= comm
->load
[0].sum
;
5046 comm
->load_max
+= comm
->load
[0].max
;
5049 for (d
= 0; d
< dd
->ndim
; d
++)
5051 if (comm
->load
[0].flags
& (1<<d
))
5053 comm
->load_lim
[d
]++;
5059 comm
->load_mdf
+= comm
->load
[0].mdf
;
5060 comm
->load_pme
+= comm
->load
[0].pme
;
5064 wallcycle_stop(wcycle
, ewcDDCOMMLOAD
);
5068 fprintf(debug
, "get_load_distribution finished\n");
5072 static float dd_force_load_fraction(gmx_domdec_t
*dd
)
5074 /* Return the relative performance loss on the total run time
5075 * due to the force calculation load imbalance.
5077 if (dd
->comm
->nload
> 0 && dd
->comm
->load_step
> 0)
5079 return dd
->comm
->load_sum
/(dd
->comm
->load_step
*dd
->nnodes
);
5087 static float dd_force_imb_perf_loss(gmx_domdec_t
*dd
)
5089 /* Return the relative performance loss on the total run time
5090 * due to the force calculation load imbalance.
5092 if (dd
->comm
->nload
> 0 && dd
->comm
->load_step
> 0)
5095 (dd
->comm
->load_max
*dd
->nnodes
- dd
->comm
->load_sum
)/
5096 (dd
->comm
->load_step
*dd
->nnodes
);
5104 static void print_dd_load_av(FILE *fplog
, gmx_domdec_t
*dd
)
5106 gmx_domdec_comm_t
*comm
= dd
->comm
;
5108 /* Only the master rank prints loads and only if we measured loads */
5109 if (!DDMASTER(dd
) || comm
->nload
== 0)
5115 int numPpRanks
= dd
->nnodes
;
5116 int numPmeRanks
= (dd
->pme_nodeid
>= 0) ? comm
->npmenodes
: 0;
5117 int numRanks
= numPpRanks
+ numPmeRanks
;
5118 float lossFraction
= 0;
5120 /* Print the average load imbalance and performance loss */
5121 if (dd
->nnodes
> 1 && comm
->load_sum
> 0)
5123 float imbalance
= comm
->load_max
*numPpRanks
/comm
->load_sum
- 1;
5124 lossFraction
= dd_force_imb_perf_loss(dd
);
5126 std::string msg
= "\n Dynamic load balancing report:\n";
5127 std::string dlbStateStr
= "";
5129 switch (dd
->comm
->dlbState
)
5132 dlbStateStr
= "DLB was off during the run per user request.";
5134 case edlbsOffForever
:
5135 /* Currectly this can happen due to performance loss observed, cell size
5136 * limitations or incompatibility with other settings observed during
5137 * determineInitialDlbState(). */
5138 dlbStateStr
= "DLB got disabled because it was unsuitable to use.";
5140 case edlbsOffCanTurnOn
:
5141 dlbStateStr
= "DLB was off during the run due to low measured imbalance.";
5143 case edlbsOffTemporarilyLocked
:
5144 dlbStateStr
= "DLB was locked at the end of the run due to unfinished PP-PME balancing.";
5146 case edlbsOnCanTurnOff
:
5147 dlbStateStr
= "DLB was turned on during the run due to measured imbalance.";
5150 dlbStateStr
= "DLB was permanently on during the run per user request.";
5153 GMX_ASSERT(false, "Undocumented DLB state");
5156 msg
+= " " + dlbStateStr
+ "\n";
5157 msg
+= gmx::formatString(" Average load imbalance: %.1f%%.\n", imbalance
*100);
5158 msg
+= gmx::formatString(" The balanceable part of the MD step is %d%%, load imbalance is computed from this.\n",
5159 static_cast<int>(dd_force_load_fraction(dd
)*100 + 0.5));
5160 msg
+= gmx::formatString(" Part of the total run time spent waiting due to load imbalance: %.1f%%.\n",
5162 fprintf(fplog
, "%s", msg
.c_str());
5163 fprintf(stderr
, "%s", msg
.c_str());
5166 /* Print during what percentage of steps the load balancing was limited */
5167 bool dlbWasLimited
= false;
5170 sprintf(buf
, " Steps where the load balancing was limited by -rdd, -rcon and/or -dds:");
5171 for (int d
= 0; d
< dd
->ndim
; d
++)
5173 int limitPercentage
= (200*comm
->load_lim
[d
] + 1)/(2*comm
->nload
);
5174 sprintf(buf
+strlen(buf
), " %c %d %%",
5175 dim2char(dd
->dim
[d
]), limitPercentage
);
5176 if (limitPercentage
>= 50)
5178 dlbWasLimited
= true;
5181 sprintf(buf
+ strlen(buf
), "\n");
5182 fprintf(fplog
, "%s", buf
);
5183 fprintf(stderr
, "%s", buf
);
5186 /* Print the performance loss due to separate PME - PP rank imbalance */
5187 float lossFractionPme
= 0;
5188 if (numPmeRanks
> 0 && comm
->load_mdf
> 0 && comm
->load_step
> 0)
5190 float pmeForceRatio
= comm
->load_pme
/comm
->load_mdf
;
5191 lossFractionPme
= (comm
->load_pme
- comm
->load_mdf
)/comm
->load_step
;
5192 if (lossFractionPme
<= 0)
5194 lossFractionPme
*= numPmeRanks
/static_cast<float>(numRanks
);
5198 lossFractionPme
*= numPpRanks
/static_cast<float>(numRanks
);
5200 sprintf(buf
, " Average PME mesh/force load: %5.3f\n", pmeForceRatio
);
5201 fprintf(fplog
, "%s", buf
);
5202 fprintf(stderr
, "%s", buf
);
5203 sprintf(buf
, " Part of the total run time spent waiting due to PP/PME imbalance: %.1f %%\n", fabs(lossFractionPme
)*100);
5204 fprintf(fplog
, "%s", buf
);
5205 fprintf(stderr
, "%s", buf
);
5207 fprintf(fplog
, "\n");
5208 fprintf(stderr
, "\n");
5210 if (lossFraction
>= DD_PERF_LOSS_WARN
)
5213 "NOTE: %.1f %% of the available CPU time was lost due to load imbalance\n"
5214 " in the domain decomposition.\n", lossFraction
*100);
5217 sprintf(buf
+strlen(buf
), " You might want to use dynamic load balancing (option -dlb.)\n");
5219 else if (dlbWasLimited
)
5221 sprintf(buf
+strlen(buf
), " You might want to decrease the cell size limit (options -rdd, -rcon and/or -dds).\n");
5223 fprintf(fplog
, "%s\n", buf
);
5224 fprintf(stderr
, "%s\n", buf
);
5226 if (numPmeRanks
> 0 && fabs(lossFractionPme
) >= DD_PERF_LOSS_WARN
)
5229 "NOTE: %.1f %% performance was lost because the PME ranks\n"
5230 " had %s work to do than the PP ranks.\n"
5231 " You might want to %s the number of PME ranks\n"
5232 " or %s the cut-off and the grid spacing.\n",
5233 fabs(lossFractionPme
*100),
5234 (lossFractionPme
< 0) ? "less" : "more",
5235 (lossFractionPme
< 0) ? "decrease" : "increase",
5236 (lossFractionPme
< 0) ? "decrease" : "increase");
5237 fprintf(fplog
, "%s\n", buf
);
5238 fprintf(stderr
, "%s\n", buf
);
5242 static float dd_vol_min(gmx_domdec_t
*dd
)
5244 return dd
->comm
->load
[0].cvol_min
*dd
->nnodes
;
5247 static gmx_bool
dd_load_flags(gmx_domdec_t
*dd
)
5249 return dd
->comm
->load
[0].flags
;
5252 static float dd_f_imbal(gmx_domdec_t
*dd
)
5254 if (dd
->comm
->load
[0].sum
> 0)
5256 return dd
->comm
->load
[0].max
*dd
->nnodes
/dd
->comm
->load
[0].sum
- 1.0f
;
5260 /* Something is wrong in the cycle counting, report no load imbalance */
5265 float dd_pme_f_ratio(gmx_domdec_t
*dd
)
5267 /* Should only be called on the DD master rank */
5268 assert(DDMASTER(dd
));
5270 if (dd
->comm
->load
[0].mdf
> 0 && dd
->comm
->cycl_n
[ddCyclPME
] > 0)
5272 return dd
->comm
->load
[0].pme
/dd
->comm
->load
[0].mdf
;
5280 static void dd_print_load(FILE *fplog
, gmx_domdec_t
*dd
, gmx_int64_t step
)
5285 flags
= dd_load_flags(dd
);
5289 "DD load balancing is limited by minimum cell size in dimension");
5290 for (d
= 0; d
< dd
->ndim
; d
++)
5294 fprintf(fplog
, " %c", dim2char(dd
->dim
[d
]));
5297 fprintf(fplog
, "\n");
5299 fprintf(fplog
, "DD step %s", gmx_step_str(step
, buf
));
5300 if (isDlbOn(dd
->comm
))
5302 fprintf(fplog
, " vol min/aver %5.3f%c",
5303 dd_vol_min(dd
), flags
? '!' : ' ');
5307 fprintf(fplog
, " load imb.: force %4.1f%%", dd_f_imbal(dd
)*100);
5309 if (dd
->comm
->cycl_n
[ddCyclPME
])
5311 fprintf(fplog
, " pme mesh/force %5.3f", dd_pme_f_ratio(dd
));
5313 fprintf(fplog
, "\n\n");
5316 static void dd_print_load_verbose(gmx_domdec_t
*dd
)
5318 if (isDlbOn(dd
->comm
))
5320 fprintf(stderr
, "vol %4.2f%c ",
5321 dd_vol_min(dd
), dd_load_flags(dd
) ? '!' : ' ');
5325 fprintf(stderr
, "imb F %2d%% ", (int)(dd_f_imbal(dd
)*100+0.5));
5327 if (dd
->comm
->cycl_n
[ddCyclPME
])
5329 fprintf(stderr
, "pme/F %4.2f ", dd_pme_f_ratio(dd
));
5334 static void make_load_communicator(gmx_domdec_t
*dd
, int dim_ind
, ivec loc
)
5339 domdec_root_t
*root
;
5340 gmx_bool bPartOfGroup
= FALSE
;
5342 dim
= dd
->dim
[dim_ind
];
5343 copy_ivec(loc
, loc_c
);
5344 for (i
= 0; i
< dd
->nc
[dim
]; i
++)
5347 rank
= dd_index(dd
->nc
, loc_c
);
5348 if (rank
== dd
->rank
)
5350 /* This process is part of the group */
5351 bPartOfGroup
= TRUE
;
5354 MPI_Comm_split(dd
->mpi_comm_all
, bPartOfGroup
? 0 : MPI_UNDEFINED
, dd
->rank
,
5358 dd
->comm
->mpi_comm_load
[dim_ind
] = c_row
;
5359 if (!isDlbDisabled(dd
->comm
))
5361 if (dd
->ci
[dim
] == dd
->master_ci
[dim
])
5363 /* This is the root process of this row */
5364 snew(dd
->comm
->root
[dim_ind
], 1);
5365 root
= dd
->comm
->root
[dim_ind
];
5366 snew(root
->cell_f
, DD_CELL_F_SIZE(dd
, dim_ind
));
5367 snew(root
->old_cell_f
, dd
->nc
[dim
]+1);
5368 snew(root
->bCellMin
, dd
->nc
[dim
]);
5371 snew(root
->cell_f_max0
, dd
->nc
[dim
]);
5372 snew(root
->cell_f_min1
, dd
->nc
[dim
]);
5373 snew(root
->bound_min
, dd
->nc
[dim
]);
5374 snew(root
->bound_max
, dd
->nc
[dim
]);
5376 snew(root
->buf_ncd
, dd
->nc
[dim
]);
5380 /* This is not a root process, we only need to receive cell_f */
5381 snew(dd
->comm
->cell_f_row
, DD_CELL_F_SIZE(dd
, dim_ind
));
5384 if (dd
->ci
[dim
] == dd
->master_ci
[dim
])
5386 snew(dd
->comm
->load
[dim_ind
].load
, dd
->nc
[dim
]*DD_NLOAD_MAX
);
5392 void dd_setup_dlb_resource_sharing(t_commrec
*cr
,
5396 int physicalnode_id_hash
;
5398 MPI_Comm mpi_comm_pp_physicalnode
;
5400 if (!thisRankHasDuty(cr
, DUTY_PP
) || gpu_id
< 0)
5402 /* Only ranks with short-ranged tasks (currently) use GPUs.
5403 * If we don't have GPUs assigned, there are no resources to share.
5408 physicalnode_id_hash
= gmx_physicalnode_id_hash();
5414 fprintf(debug
, "dd_setup_dd_dlb_gpu_sharing:\n");
5415 fprintf(debug
, "DD PP rank %d physical node hash %d gpu_id %d\n",
5416 dd
->rank
, physicalnode_id_hash
, gpu_id
);
5418 /* Split the PP communicator over the physical nodes */
5419 /* TODO: See if we should store this (before), as it's also used for
5420 * for the nodecomm summation.
5422 // TODO PhysicalNodeCommunicator could be extended/used to handle
5423 // the need for per-node per-group communicators.
5424 MPI_Comm_split(dd
->mpi_comm_all
, physicalnode_id_hash
, dd
->rank
,
5425 &mpi_comm_pp_physicalnode
);
5426 MPI_Comm_split(mpi_comm_pp_physicalnode
, gpu_id
, dd
->rank
,
5427 &dd
->comm
->mpi_comm_gpu_shared
);
5428 MPI_Comm_free(&mpi_comm_pp_physicalnode
);
5429 MPI_Comm_size(dd
->comm
->mpi_comm_gpu_shared
, &dd
->comm
->nrank_gpu_shared
);
5433 fprintf(debug
, "nrank_gpu_shared %d\n", dd
->comm
->nrank_gpu_shared
);
5436 /* Note that some ranks could share a GPU, while others don't */
5438 if (dd
->comm
->nrank_gpu_shared
== 1)
5440 MPI_Comm_free(&dd
->comm
->mpi_comm_gpu_shared
);
5443 GMX_UNUSED_VALUE(cr
);
5444 GMX_UNUSED_VALUE(gpu_id
);
5448 static void make_load_communicators(gmx_domdec_t gmx_unused
*dd
)
5451 int dim0
, dim1
, i
, j
;
5456 fprintf(debug
, "Making load communicators\n");
5459 snew(dd
->comm
->load
, std::max(dd
->ndim
, 1));
5460 snew(dd
->comm
->mpi_comm_load
, std::max(dd
->ndim
, 1));
5468 make_load_communicator(dd
, 0, loc
);
5472 for (i
= 0; i
< dd
->nc
[dim0
]; i
++)
5475 make_load_communicator(dd
, 1, loc
);
5481 for (i
= 0; i
< dd
->nc
[dim0
]; i
++)
5485 for (j
= 0; j
< dd
->nc
[dim1
]; j
++)
5488 make_load_communicator(dd
, 2, loc
);
5495 fprintf(debug
, "Finished making load communicators\n");
5500 /*! \brief Sets up the relation between neighboring domains and zones */
5501 static void setup_neighbor_relations(gmx_domdec_t
*dd
)
5503 int d
, dim
, i
, j
, m
;
5505 gmx_domdec_zones_t
*zones
;
5506 gmx_domdec_ns_ranges_t
*izone
;
5508 for (d
= 0; d
< dd
->ndim
; d
++)
5511 copy_ivec(dd
->ci
, tmp
);
5512 tmp
[dim
] = (tmp
[dim
] + 1) % dd
->nc
[dim
];
5513 dd
->neighbor
[d
][0] = ddcoord2ddnodeid(dd
, tmp
);
5514 copy_ivec(dd
->ci
, tmp
);
5515 tmp
[dim
] = (tmp
[dim
] - 1 + dd
->nc
[dim
]) % dd
->nc
[dim
];
5516 dd
->neighbor
[d
][1] = ddcoord2ddnodeid(dd
, tmp
);
5519 fprintf(debug
, "DD rank %d neighbor ranks in dir %d are + %d - %d\n",
5522 dd
->neighbor
[d
][1]);
5526 int nzone
= (1 << dd
->ndim
);
5527 int nizone
= (1 << std::max(dd
->ndim
- 1, 0));
5528 assert(nizone
>= 1 && nizone
<= DD_MAXIZONE
);
5530 zones
= &dd
->comm
->zones
;
5532 for (i
= 0; i
< nzone
; i
++)
5535 clear_ivec(zones
->shift
[i
]);
5536 for (d
= 0; d
< dd
->ndim
; d
++)
5538 zones
->shift
[i
][dd
->dim
[d
]] = dd_zo
[i
][m
++];
5543 for (i
= 0; i
< nzone
; i
++)
5545 for (d
= 0; d
< DIM
; d
++)
5547 s
[d
] = dd
->ci
[d
] - zones
->shift
[i
][d
];
5552 else if (s
[d
] >= dd
->nc
[d
])
5558 zones
->nizone
= nizone
;
5559 for (i
= 0; i
< zones
->nizone
; i
++)
5561 assert(ddNonbondedZonePairRanges
[i
][0] == i
);
5563 izone
= &zones
->izone
[i
];
5564 /* dd_zp3 is for 3D decomposition, for fewer dimensions use only
5565 * j-zones up to nzone.
5567 izone
->j0
= std::min(ddNonbondedZonePairRanges
[i
][1], nzone
);
5568 izone
->j1
= std::min(ddNonbondedZonePairRanges
[i
][2], nzone
);
5569 for (dim
= 0; dim
< DIM
; dim
++)
5571 if (dd
->nc
[dim
] == 1)
5573 /* All shifts should be allowed */
5574 izone
->shift0
[dim
] = -1;
5575 izone
->shift1
[dim
] = 1;
5579 /* Determine the min/max j-zone shift wrt the i-zone */
5580 izone
->shift0
[dim
] = 1;
5581 izone
->shift1
[dim
] = -1;
5582 for (j
= izone
->j0
; j
< izone
->j1
; j
++)
5584 int shift_diff
= zones
->shift
[j
][dim
] - zones
->shift
[i
][dim
];
5585 if (shift_diff
< izone
->shift0
[dim
])
5587 izone
->shift0
[dim
] = shift_diff
;
5589 if (shift_diff
> izone
->shift1
[dim
])
5591 izone
->shift1
[dim
] = shift_diff
;
5598 if (!isDlbDisabled(dd
->comm
))
5600 snew(dd
->comm
->root
, dd
->ndim
);
5603 if (dd
->comm
->bRecordLoad
)
5605 make_load_communicators(dd
);
5609 static void make_pp_communicator(FILE *fplog
,
5611 t_commrec gmx_unused
*cr
,
5612 int gmx_unused reorder
)
5615 gmx_domdec_comm_t
*comm
;
5622 if (comm
->bCartesianPP
)
5624 /* Set up cartesian communication for the particle-particle part */
5627 fprintf(fplog
, "Will use a Cartesian communicator: %d x %d x %d\n",
5628 dd
->nc
[XX
], dd
->nc
[YY
], dd
->nc
[ZZ
]);
5631 for (int i
= 0; i
< DIM
; i
++)
5635 MPI_Cart_create(cr
->mpi_comm_mygroup
, DIM
, dd
->nc
, periods
, reorder
,
5637 /* We overwrite the old communicator with the new cartesian one */
5638 cr
->mpi_comm_mygroup
= comm_cart
;
5641 dd
->mpi_comm_all
= cr
->mpi_comm_mygroup
;
5642 MPI_Comm_rank(dd
->mpi_comm_all
, &dd
->rank
);
5644 if (comm
->bCartesianPP_PME
)
5646 /* Since we want to use the original cartesian setup for sim,
5647 * and not the one after split, we need to make an index.
5649 snew(comm
->ddindex2ddnodeid
, dd
->nnodes
);
5650 comm
->ddindex2ddnodeid
[dd_index(dd
->nc
, dd
->ci
)] = dd
->rank
;
5651 gmx_sumi(dd
->nnodes
, comm
->ddindex2ddnodeid
, cr
);
5652 /* Get the rank of the DD master,
5653 * above we made sure that the master node is a PP node.
5663 MPI_Allreduce(&rank
, &dd
->masterrank
, 1, MPI_INT
, MPI_SUM
, dd
->mpi_comm_all
);
5665 else if (comm
->bCartesianPP
)
5667 if (cr
->npmenodes
== 0)
5669 /* The PP communicator is also
5670 * the communicator for this simulation
5672 cr
->mpi_comm_mysim
= cr
->mpi_comm_mygroup
;
5674 cr
->nodeid
= dd
->rank
;
5676 MPI_Cart_coords(dd
->mpi_comm_all
, dd
->rank
, DIM
, dd
->ci
);
5678 /* We need to make an index to go from the coordinates
5679 * to the nodeid of this simulation.
5681 snew(comm
->ddindex2simnodeid
, dd
->nnodes
);
5682 snew(buf
, dd
->nnodes
);
5683 if (thisRankHasDuty(cr
, DUTY_PP
))
5685 buf
[dd_index(dd
->nc
, dd
->ci
)] = cr
->sim_nodeid
;
5687 /* Communicate the ddindex to simulation nodeid index */
5688 MPI_Allreduce(buf
, comm
->ddindex2simnodeid
, dd
->nnodes
, MPI_INT
, MPI_SUM
,
5689 cr
->mpi_comm_mysim
);
5692 /* Determine the master coordinates and rank.
5693 * The DD master should be the same node as the master of this sim.
5695 for (int i
= 0; i
< dd
->nnodes
; i
++)
5697 if (comm
->ddindex2simnodeid
[i
] == 0)
5699 ddindex2xyz(dd
->nc
, i
, dd
->master_ci
);
5700 MPI_Cart_rank(dd
->mpi_comm_all
, dd
->master_ci
, &dd
->masterrank
);
5705 fprintf(debug
, "The master rank is %d\n", dd
->masterrank
);
5710 /* No Cartesian communicators */
5711 /* We use the rank in dd->comm->all as DD index */
5712 ddindex2xyz(dd
->nc
, dd
->rank
, dd
->ci
);
5713 /* The simulation master nodeid is 0, so the DD master rank is also 0 */
5715 clear_ivec(dd
->master_ci
);
5722 "Domain decomposition rank %d, coordinates %d %d %d\n\n",
5723 dd
->rank
, dd
->ci
[XX
], dd
->ci
[YY
], dd
->ci
[ZZ
]);
5728 "Domain decomposition rank %d, coordinates %d %d %d\n\n",
5729 dd
->rank
, dd
->ci
[XX
], dd
->ci
[YY
], dd
->ci
[ZZ
]);
5733 static void receive_ddindex2simnodeid(gmx_domdec_t
*dd
,
5737 gmx_domdec_comm_t
*comm
= dd
->comm
;
5739 if (!comm
->bCartesianPP_PME
&& comm
->bCartesianPP
)
5742 snew(comm
->ddindex2simnodeid
, dd
->nnodes
);
5743 snew(buf
, dd
->nnodes
);
5744 if (thisRankHasDuty(cr
, DUTY_PP
))
5746 buf
[dd_index(dd
->nc
, dd
->ci
)] = cr
->sim_nodeid
;
5748 /* Communicate the ddindex to simulation nodeid index */
5749 MPI_Allreduce(buf
, comm
->ddindex2simnodeid
, dd
->nnodes
, MPI_INT
, MPI_SUM
,
5750 cr
->mpi_comm_mysim
);
5754 GMX_UNUSED_VALUE(dd
);
5755 GMX_UNUSED_VALUE(cr
);
5759 static gmx_domdec_master_t
*init_gmx_domdec_master_t(gmx_domdec_t
*dd
,
5760 int ncg
, int natoms
)
5762 gmx_domdec_master_t
*ma
;
5767 snew(ma
->ncg
, dd
->nnodes
);
5768 snew(ma
->index
, dd
->nnodes
+1);
5770 snew(ma
->nat
, dd
->nnodes
);
5771 snew(ma
->ibuf
, dd
->nnodes
*2);
5772 snew(ma
->cell_x
, DIM
);
5773 for (i
= 0; i
< DIM
; i
++)
5775 snew(ma
->cell_x
[i
], dd
->nc
[i
]+1);
5778 if (dd
->nnodes
<= GMX_DD_NNODES_SENDRECV
)
5784 snew(ma
->vbuf
, natoms
);
5790 static void split_communicator(FILE *fplog
, t_commrec
*cr
, gmx_domdec_t
*dd
,
5791 DdRankOrder gmx_unused rankOrder
,
5792 int gmx_unused reorder
)
5794 gmx_domdec_comm_t
*comm
;
5803 if (comm
->bCartesianPP
)
5805 for (i
= 1; i
< DIM
; i
++)
5807 bDiv
[i
] = ((cr
->npmenodes
*dd
->nc
[i
]) % (dd
->nnodes
) == 0);
5809 if (bDiv
[YY
] || bDiv
[ZZ
])
5811 comm
->bCartesianPP_PME
= TRUE
;
5812 /* If we have 2D PME decomposition, which is always in x+y,
5813 * we stack the PME only nodes in z.
5814 * Otherwise we choose the direction that provides the thinnest slab
5815 * of PME only nodes as this will have the least effect
5816 * on the PP communication.
5817 * But for the PME communication the opposite might be better.
5819 if (bDiv
[ZZ
] && (comm
->npmenodes_y
> 1 ||
5821 dd
->nc
[YY
] > dd
->nc
[ZZ
]))
5823 comm
->cartpmedim
= ZZ
;
5827 comm
->cartpmedim
= YY
;
5829 comm
->ntot
[comm
->cartpmedim
]
5830 += (cr
->npmenodes
*dd
->nc
[comm
->cartpmedim
])/dd
->nnodes
;
5834 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
]);
5836 "Will not use a Cartesian communicator for PP <-> PME\n\n");
5840 if (comm
->bCartesianPP_PME
)
5848 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
]);
5851 for (i
= 0; i
< DIM
; i
++)
5855 MPI_Cart_create(cr
->mpi_comm_mysim
, DIM
, comm
->ntot
, periods
, reorder
,
5857 MPI_Comm_rank(comm_cart
, &rank
);
5858 if (MASTER(cr
) && rank
!= 0)
5860 gmx_fatal(FARGS
, "MPI rank 0 was renumbered by MPI_Cart_create, we do not allow this");
5863 /* With this assigment we loose the link to the original communicator
5864 * which will usually be MPI_COMM_WORLD, unless have multisim.
5866 cr
->mpi_comm_mysim
= comm_cart
;
5867 cr
->sim_nodeid
= rank
;
5869 MPI_Cart_coords(cr
->mpi_comm_mysim
, cr
->sim_nodeid
, DIM
, dd
->ci
);
5873 fprintf(fplog
, "Cartesian rank %d, coordinates %d %d %d\n\n",
5874 cr
->sim_nodeid
, dd
->ci
[XX
], dd
->ci
[YY
], dd
->ci
[ZZ
]);
5877 if (dd
->ci
[comm
->cartpmedim
] < dd
->nc
[comm
->cartpmedim
])
5881 if (cr
->npmenodes
== 0 ||
5882 dd
->ci
[comm
->cartpmedim
] >= dd
->nc
[comm
->cartpmedim
])
5884 cr
->duty
= DUTY_PME
;
5887 /* Split the sim communicator into PP and PME only nodes */
5888 MPI_Comm_split(cr
->mpi_comm_mysim
,
5889 getThisRankDuties(cr
),
5890 dd_index(comm
->ntot
, dd
->ci
),
5891 &cr
->mpi_comm_mygroup
);
5898 case DdRankOrder::pp_pme
:
5901 fprintf(fplog
, "Order of the ranks: PP first, PME last\n");
5904 case DdRankOrder::interleave
:
5905 /* Interleave the PP-only and PME-only ranks */
5908 fprintf(fplog
, "Interleaving PP and PME ranks\n");
5910 comm
->pmenodes
= dd_interleaved_pme_ranks(dd
);
5912 case DdRankOrder::cartesian
:
5915 gmx_fatal(FARGS
, "Invalid ddRankOrder=%d", static_cast<int>(rankOrder
));
5918 if (dd_simnode2pmenode(dd
, cr
, cr
->sim_nodeid
) == -1)
5920 cr
->duty
= DUTY_PME
;
5927 /* Split the sim communicator into PP and PME only nodes */
5928 MPI_Comm_split(cr
->mpi_comm_mysim
,
5929 getThisRankDuties(cr
),
5931 &cr
->mpi_comm_mygroup
);
5932 MPI_Comm_rank(cr
->mpi_comm_mygroup
, &cr
->nodeid
);
5938 fprintf(fplog
, "This rank does only %s work.\n\n",
5939 thisRankHasDuty(cr
, DUTY_PP
) ? "particle-particle" : "PME-mesh");
5943 /*! \brief Generates the MPI communicators for domain decomposition */
5944 static void make_dd_communicators(FILE *fplog
, t_commrec
*cr
,
5945 gmx_domdec_t
*dd
, DdRankOrder ddRankOrder
)
5947 gmx_domdec_comm_t
*comm
;
5952 copy_ivec(dd
->nc
, comm
->ntot
);
5954 comm
->bCartesianPP
= (ddRankOrder
== DdRankOrder::cartesian
);
5955 comm
->bCartesianPP_PME
= FALSE
;
5957 /* Reorder the nodes by default. This might change the MPI ranks.
5958 * Real reordering is only supported on very few architectures,
5959 * Blue Gene is one of them.
5961 CartReorder
= (getenv("GMX_NO_CART_REORDER") == nullptr);
5963 if (cr
->npmenodes
> 0)
5965 /* Split the communicator into a PP and PME part */
5966 split_communicator(fplog
, cr
, dd
, ddRankOrder
, CartReorder
);
5967 if (comm
->bCartesianPP_PME
)
5969 /* We (possibly) reordered the nodes in split_communicator,
5970 * so it is no longer required in make_pp_communicator.
5972 CartReorder
= FALSE
;
5977 /* All nodes do PP and PME */
5979 /* We do not require separate communicators */
5980 cr
->mpi_comm_mygroup
= cr
->mpi_comm_mysim
;
5984 if (thisRankHasDuty(cr
, DUTY_PP
))
5986 /* Copy or make a new PP communicator */
5987 make_pp_communicator(fplog
, dd
, cr
, CartReorder
);
5991 receive_ddindex2simnodeid(dd
, cr
);
5994 if (!thisRankHasDuty(cr
, DUTY_PME
))
5996 /* Set up the commnuication to our PME node */
5997 dd
->pme_nodeid
= dd_simnode2pmenode(dd
, cr
, cr
->sim_nodeid
);
5998 dd
->pme_receive_vir_ener
= receive_vir_ener(dd
, cr
);
6001 fprintf(debug
, "My pme_nodeid %d receive ener %d\n",
6002 dd
->pme_nodeid
, dd
->pme_receive_vir_ener
);
6007 dd
->pme_nodeid
= -1;
6012 dd
->ma
= init_gmx_domdec_master_t(dd
,
6014 comm
->cgs_gl
.index
[comm
->cgs_gl
.nr
]);
6018 static real
*get_slb_frac(FILE *fplog
, const char *dir
, int nc
, const char *size_string
)
6020 real
*slb_frac
, tot
;
6025 if (nc
> 1 && size_string
!= nullptr)
6029 fprintf(fplog
, "Using static load balancing for the %s direction\n",
6034 for (i
= 0; i
< nc
; i
++)
6037 sscanf(size_string
, "%20lf%n", &dbl
, &n
);
6040 gmx_fatal(FARGS
, "Incorrect or not enough DD cell size entries for direction %s: '%s'", dir
, size_string
);
6049 fprintf(fplog
, "Relative cell sizes:");
6051 for (i
= 0; i
< nc
; i
++)
6056 fprintf(fplog
, " %5.3f", slb_frac
[i
]);
6061 fprintf(fplog
, "\n");
6068 static int multi_body_bondeds_count(const gmx_mtop_t
*mtop
)
6071 gmx_mtop_ilistloop_t iloop
;
6075 iloop
= gmx_mtop_ilistloop_init(mtop
);
6076 while (gmx_mtop_ilistloop_next(iloop
, &il
, &nmol
))
6078 for (ftype
= 0; ftype
< F_NRE
; ftype
++)
6080 if ((interaction_function
[ftype
].flags
& IF_BOND
) &&
6083 n
+= nmol
*il
[ftype
].nr
/(1 + NRAL(ftype
));
6091 static int dd_getenv(FILE *fplog
, const char *env_var
, int def
)
6097 val
= getenv(env_var
);
6100 if (sscanf(val
, "%20d", &nst
) <= 0)
6106 fprintf(fplog
, "Found env.var. %s = %s, using value %d\n",
6114 static void dd_warning(const t_commrec
*cr
, FILE *fplog
, const char *warn_string
)
6118 fprintf(stderr
, "\n%s\n", warn_string
);
6122 fprintf(fplog
, "\n%s\n", warn_string
);
6126 static void check_dd_restrictions(t_commrec
*cr
, const gmx_domdec_t
*dd
,
6127 const t_inputrec
*ir
, FILE *fplog
)
6129 if (ir
->ePBC
== epbcSCREW
&&
6130 (dd
->nc
[XX
] == 1 || dd
->nc
[YY
] > 1 || dd
->nc
[ZZ
] > 1))
6132 gmx_fatal(FARGS
, "With pbc=%s can only do domain decomposition in the x-direction", epbc_names
[ir
->ePBC
]);
6135 if (ir
->ns_type
== ensSIMPLE
)
6137 gmx_fatal(FARGS
, "Domain decomposition does not support simple neighbor searching, use grid searching or run with one MPI rank");
6140 if (ir
->nstlist
== 0)
6142 gmx_fatal(FARGS
, "Domain decomposition does not work with nstlist=0");
6145 if (ir
->comm_mode
== ecmANGULAR
&& ir
->ePBC
!= epbcNONE
)
6147 dd_warning(cr
, fplog
, "comm-mode angular will give incorrect results when the comm group partially crosses a periodic boundary");
6151 static real
average_cellsize_min(gmx_domdec_t
*dd
, gmx_ddbox_t
*ddbox
)
6156 r
= ddbox
->box_size
[XX
];
6157 for (di
= 0; di
< dd
->ndim
; di
++)
6160 /* Check using the initial average cell size */
6161 r
= std::min(r
, ddbox
->box_size
[d
]*ddbox
->skew_fac
[d
]/dd
->nc
[d
]);
6167 /*! \brief Depending on the DLB initial value return the DLB switched off state or issue an error.
6169 static int forceDlbOffOrBail(int cmdlineDlbState
,
6170 const std::string
&reasonStr
,
6174 std::string dlbNotSupportedErr
= "Dynamic load balancing requested, but ";
6175 std::string dlbDisableNote
= "NOTE: disabling dynamic load balancing as ";
6177 if (cmdlineDlbState
== edlbsOnUser
)
6179 gmx_fatal(FARGS
, (dlbNotSupportedErr
+ reasonStr
).c_str());
6181 else if (cmdlineDlbState
== edlbsOffCanTurnOn
)
6183 dd_warning(cr
, fplog
, (dlbDisableNote
+ reasonStr
+ "\n").c_str());
6185 return edlbsOffForever
;
6188 /*! \brief Return the dynamic load balancer's initial state based on initial conditions and user inputs.
6190 * This function parses the parameters of "-dlb" command line option setting
6191 * corresponding state values. Then it checks the consistency of the determined
6192 * state with other run parameters and settings. As a result, the initial state
6193 * may be altered or an error may be thrown if incompatibility of options is detected.
6195 * \param [in] fplog Pointer to mdrun log file.
6196 * \param [in] cr Pointer to MPI communication object.
6197 * \param [in] dlbOption Enum value for the DLB option.
6198 * \param [in] bRecordLoad True if the load balancer is recording load information.
6199 * \param [in] mdrunOptions Options for mdrun.
6200 * \param [in] ir Pointer mdrun to input parameters.
6201 * \returns DLB initial/startup state.
6203 static int determineInitialDlbState(FILE *fplog
, t_commrec
*cr
,
6204 DlbOption dlbOption
, gmx_bool bRecordLoad
,
6205 const MdrunOptions
&mdrunOptions
,
6206 const t_inputrec
*ir
)
6208 int dlbState
= edlbsOffCanTurnOn
;
6212 case DlbOption::turnOnWhenUseful
: dlbState
= edlbsOffCanTurnOn
; break;
6213 case DlbOption::no
: dlbState
= edlbsOffUser
; break;
6214 case DlbOption::yes
: dlbState
= edlbsOnUser
; break;
6215 default: gmx_incons("Invalid dlbOption enum value");
6218 /* Reruns don't support DLB: bail or override auto mode */
6219 if (mdrunOptions
.rerun
)
6221 std::string reasonStr
= "it is not supported in reruns.";
6222 return forceDlbOffOrBail(dlbState
, reasonStr
, cr
, fplog
);
6225 /* Unsupported integrators */
6226 if (!EI_DYNAMICS(ir
->eI
))
6228 auto reasonStr
= gmx::formatString("it is only supported with dynamics, not with integrator '%s'.", EI(ir
->eI
));
6229 return forceDlbOffOrBail(dlbState
, reasonStr
, cr
, fplog
);
6232 /* Without cycle counters we can't time work to balance on */
6235 std::string reasonStr
= "cycle counters unsupported or not enabled in the operating system kernel.";
6236 return forceDlbOffOrBail(dlbState
, reasonStr
, cr
, fplog
);
6239 if (mdrunOptions
.reproducible
)
6241 std::string reasonStr
= "you started a reproducible run.";
6246 case edlbsOffForever
:
6247 GMX_RELEASE_ASSERT(false, "edlbsOffForever is not a valid initial state");
6249 case edlbsOffCanTurnOn
:
6250 return forceDlbOffOrBail(dlbState
, reasonStr
, cr
, fplog
);
6252 case edlbsOnCanTurnOff
:
6253 GMX_RELEASE_ASSERT(false, "edlbsOffCanTurnOff is not a valid initial state");
6256 return forceDlbOffOrBail(dlbState
, reasonStr
+ " In load balanced runs binary reproducibility cannot be ensured.", cr
, fplog
);
6259 gmx_fatal(FARGS
, "Death horror: undefined case (%d) for load balancing choice", dlbState
);
6267 static void set_dd_dim(FILE *fplog
, gmx_domdec_t
*dd
)
6272 if (getenv("GMX_DD_ORDER_ZYX") != nullptr)
6274 /* Decomposition order z,y,x */
6277 fprintf(fplog
, "Using domain decomposition order z, y, x\n");
6279 for (dim
= DIM
-1; dim
>= 0; dim
--)
6281 if (dd
->nc
[dim
] > 1)
6283 dd
->dim
[dd
->ndim
++] = dim
;
6289 /* Decomposition order x,y,z */
6290 for (dim
= 0; dim
< DIM
; dim
++)
6292 if (dd
->nc
[dim
] > 1)
6294 dd
->dim
[dd
->ndim
++] = dim
;
6300 static gmx_domdec_comm_t
*init_dd_comm()
6302 gmx_domdec_comm_t
*comm
;
6306 snew(comm
->cggl_flag
, DIM
*2);
6307 snew(comm
->cgcm_state
, DIM
*2);
6308 for (i
= 0; i
< DIM
*2; i
++)
6310 comm
->cggl_flag_nalloc
[i
] = 0;
6311 comm
->cgcm_state_nalloc
[i
] = 0;
6314 comm
->nalloc_int
= 0;
6315 comm
->buf_int
= nullptr;
6317 vec_rvec_init(&comm
->vbuf
);
6319 comm
->n_load_have
= 0;
6320 comm
->n_load_collect
= 0;
6322 for (i
= 0; i
< ddnatNR
-ddnatZONE
; i
++)
6324 comm
->sum_nat
[i
] = 0;
6328 comm
->load_step
= 0;
6331 clear_ivec(comm
->load_lim
);
6335 /* This should be replaced by a unique pointer */
6336 comm
->balanceRegion
= ddBalanceRegionAllocate();
6341 /*! \brief Set the cell size and interaction limits, as well as the DD grid */
6342 static void set_dd_limits_and_grid(FILE *fplog
, t_commrec
*cr
, gmx_domdec_t
*dd
,
6343 const DomdecOptions
&options
,
6344 const MdrunOptions
&mdrunOptions
,
6345 const gmx_mtop_t
*mtop
,
6346 const t_inputrec
*ir
,
6347 const matrix box
, const rvec
*xGlobal
,
6349 int *npme_x
, int *npme_y
)
6352 real r_bonded_limit
= -1;
6353 const real tenPercentMargin
= 1.1;
6354 gmx_domdec_comm_t
*comm
= dd
->comm
;
6356 snew(comm
->cggl_flag
, DIM
*2);
6357 snew(comm
->cgcm_state
, DIM
*2);
6359 dd
->npbcdim
= ePBC2npbcdim(ir
->ePBC
);
6360 dd
->bScrewPBC
= (ir
->ePBC
== epbcSCREW
);
6362 dd
->pme_recv_f_alloc
= 0;
6363 dd
->pme_recv_f_buf
= nullptr;
6365 /* Initialize to GPU share count to 0, might change later */
6366 comm
->nrank_gpu_shared
= 0;
6368 comm
->dlbState
= determineInitialDlbState(fplog
, cr
, options
.dlbOption
, comm
->bRecordLoad
, mdrunOptions
, ir
);
6369 dd_dlb_set_should_check_whether_to_turn_dlb_on(dd
, TRUE
);
6370 /* To consider turning DLB on after 2*nstlist steps we need to check
6371 * at partitioning count 3. Thus we need to increase the first count by 2.
6373 comm
->ddPartioningCountFirstDlbOff
+= 2;
6377 fprintf(fplog
, "Dynamic load balancing: %s\n",
6378 edlbs_names
[comm
->dlbState
]);
6380 comm
->bPMELoadBalDLBLimits
= FALSE
;
6382 /* Allocate the charge group/atom sorting struct */
6383 snew(comm
->sort
, 1);
6385 comm
->bCGs
= (ncg_mtop(mtop
) < mtop
->natoms
);
6387 comm
->bInterCGBondeds
= ((ncg_mtop(mtop
) > gmx_mtop_num_molecules(*mtop
)) ||
6388 mtop
->bIntermolecularInteractions
);
6389 if (comm
->bInterCGBondeds
)
6391 comm
->bInterCGMultiBody
= (multi_body_bondeds_count(mtop
) > 0);
6395 comm
->bInterCGMultiBody
= FALSE
;
6398 dd
->bInterCGcons
= inter_charge_group_constraints(mtop
);
6399 dd
->bInterCGsettles
= inter_charge_group_settles(mtop
);
6403 /* Set the cut-off to some very large value,
6404 * so we don't need if statements everywhere in the code.
6405 * We use sqrt, since the cut-off is squared in some places.
6407 comm
->cutoff
= GMX_CUTOFF_INF
;
6411 comm
->cutoff
= ir
->rlist
;
6413 comm
->cutoff_mbody
= 0;
6415 comm
->cellsize_limit
= 0;
6416 comm
->bBondComm
= FALSE
;
6418 /* Atoms should be able to move by up to half the list buffer size (if > 0)
6419 * within nstlist steps. Since boundaries are allowed to displace by half
6420 * a cell size, DD cells should be at least the size of the list buffer.
6422 comm
->cellsize_limit
= std::max(comm
->cellsize_limit
,
6423 ir
->rlist
- std::max(ir
->rvdw
, ir
->rcoulomb
));
6425 if (comm
->bInterCGBondeds
)
6427 if (options
.minimumCommunicationRange
> 0)
6429 comm
->cutoff_mbody
= options
.minimumCommunicationRange
;
6430 if (options
.useBondedCommunication
)
6432 comm
->bBondComm
= (comm
->cutoff_mbody
> comm
->cutoff
);
6436 comm
->cutoff
= std::max(comm
->cutoff
, comm
->cutoff_mbody
);
6438 r_bonded_limit
= comm
->cutoff_mbody
;
6440 else if (ir
->bPeriodicMols
)
6442 /* Can not easily determine the required cut-off */
6443 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");
6444 comm
->cutoff_mbody
= comm
->cutoff
/2;
6445 r_bonded_limit
= comm
->cutoff_mbody
;
6453 dd_bonded_cg_distance(fplog
, mtop
, ir
, xGlobal
, box
,
6454 options
.checkBondedInteractions
,
6457 gmx_bcast(sizeof(r_2b
), &r_2b
, cr
);
6458 gmx_bcast(sizeof(r_mb
), &r_mb
, cr
);
6460 /* We use an initial margin of 10% for the minimum cell size,
6461 * except when we are just below the non-bonded cut-off.
6463 if (options
.useBondedCommunication
)
6465 if (std::max(r_2b
, r_mb
) > comm
->cutoff
)
6467 r_bonded
= std::max(r_2b
, r_mb
);
6468 r_bonded_limit
= tenPercentMargin
*r_bonded
;
6469 comm
->bBondComm
= TRUE
;
6474 r_bonded_limit
= std::min(tenPercentMargin
*r_bonded
, comm
->cutoff
);
6476 /* We determine cutoff_mbody later */
6480 /* No special bonded communication,
6481 * simply increase the DD cut-off.
6483 r_bonded_limit
= tenPercentMargin
*std::max(r_2b
, r_mb
);
6484 comm
->cutoff_mbody
= r_bonded_limit
;
6485 comm
->cutoff
= std::max(comm
->cutoff
, comm
->cutoff_mbody
);
6491 "Minimum cell size due to bonded interactions: %.3f nm\n",
6494 comm
->cellsize_limit
= std::max(comm
->cellsize_limit
, r_bonded_limit
);
6498 if (dd
->bInterCGcons
&& options
.constraintCommunicationRange
<= 0)
6500 /* There is a cell size limit due to the constraints (P-LINCS) */
6501 rconstr
= constr_r_max(fplog
, mtop
, ir
);
6505 "Estimated maximum distance required for P-LINCS: %.3f nm\n",
6507 if (rconstr
> comm
->cellsize_limit
)
6509 fprintf(fplog
, "This distance will limit the DD cell size, you can override this with -rcon\n");
6513 else if (options
.constraintCommunicationRange
> 0 && fplog
)
6515 /* Here we do not check for dd->bInterCGcons,
6516 * because one can also set a cell size limit for virtual sites only
6517 * and at this point we don't know yet if there are intercg v-sites.
6520 "User supplied maximum distance required for P-LINCS: %.3f nm\n",
6521 options
.constraintCommunicationRange
);
6522 rconstr
= options
.constraintCommunicationRange
;
6524 comm
->cellsize_limit
= std::max(comm
->cellsize_limit
, rconstr
);
6526 comm
->cgs_gl
= gmx_mtop_global_cgs(mtop
);
6528 if (options
.numCells
[XX
] > 0)
6530 copy_ivec(options
.numCells
, dd
->nc
);
6531 set_dd_dim(fplog
, dd
);
6532 set_ddbox_cr(cr
, &dd
->nc
, ir
, box
, &comm
->cgs_gl
, xGlobal
, ddbox
);
6534 if (options
.numPmeRanks
>= 0)
6536 cr
->npmenodes
= options
.numPmeRanks
;
6540 /* When the DD grid is set explicitly and -npme is set to auto,
6541 * don't use PME ranks. We check later if the DD grid is
6542 * compatible with the total number of ranks.
6547 real acs
= average_cellsize_min(dd
, ddbox
);
6548 if (acs
< comm
->cellsize_limit
)
6552 fprintf(fplog
, "ERROR: The initial cell size (%f) is smaller than the cell size limit (%f)\n", acs
, comm
->cellsize_limit
);
6554 gmx_fatal_collective(FARGS
, cr
->mpi_comm_mysim
, MASTER(cr
),
6555 "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",
6556 acs
, comm
->cellsize_limit
);
6561 set_ddbox_cr(cr
, nullptr, ir
, box
, &comm
->cgs_gl
, xGlobal
, ddbox
);
6563 /* We need to choose the optimal DD grid and possibly PME nodes */
6565 dd_choose_grid(fplog
, cr
, dd
, ir
, mtop
, box
, ddbox
,
6566 options
.numPmeRanks
,
6567 !isDlbDisabled(comm
),
6569 comm
->cellsize_limit
, comm
->cutoff
,
6570 comm
->bInterCGBondeds
);
6572 if (dd
->nc
[XX
] == 0)
6575 gmx_bool bC
= (dd
->bInterCGcons
&& rconstr
> r_bonded_limit
);
6576 sprintf(buf
, "Change the number of ranks or mdrun option %s%s%s",
6577 !bC
? "-rdd" : "-rcon",
6578 comm
->dlbState
!= edlbsOffUser
? " or -dds" : "",
6579 bC
? " or your LINCS settings" : "");
6581 gmx_fatal_collective(FARGS
, cr
->mpi_comm_mysim
, MASTER(cr
),
6582 "There is no domain decomposition for %d ranks that is compatible with the given box and a minimum cell size of %g nm\n"
6584 "Look in the log file for details on the domain decomposition",
6585 cr
->nnodes
-cr
->npmenodes
, limit
, buf
);
6587 set_dd_dim(fplog
, dd
);
6593 "Domain decomposition grid %d x %d x %d, separate PME ranks %d\n",
6594 dd
->nc
[XX
], dd
->nc
[YY
], dd
->nc
[ZZ
], cr
->npmenodes
);
6597 dd
->nnodes
= dd
->nc
[XX
]*dd
->nc
[YY
]*dd
->nc
[ZZ
];
6598 if (cr
->nnodes
- dd
->nnodes
!= cr
->npmenodes
)
6600 gmx_fatal_collective(FARGS
, cr
->mpi_comm_mysim
, MASTER(cr
),
6601 "The size of the domain decomposition grid (%d) does not match the number of ranks (%d). The total number of ranks is %d",
6602 dd
->nnodes
, cr
->nnodes
- cr
->npmenodes
, cr
->nnodes
);
6604 if (cr
->npmenodes
> dd
->nnodes
)
6606 gmx_fatal_collective(FARGS
, cr
->mpi_comm_mysim
, MASTER(cr
),
6607 "The number of separate PME ranks (%d) is larger than the number of PP ranks (%d), this is not supported.", cr
->npmenodes
, dd
->nnodes
);
6609 if (cr
->npmenodes
> 0)
6611 comm
->npmenodes
= cr
->npmenodes
;
6615 comm
->npmenodes
= dd
->nnodes
;
6618 if (EEL_PME(ir
->coulombtype
) || EVDW_PME(ir
->vdwtype
))
6620 /* The following choices should match those
6621 * in comm_cost_est in domdec_setup.c.
6622 * Note that here the checks have to take into account
6623 * that the decomposition might occur in a different order than xyz
6624 * (for instance through the env.var. GMX_DD_ORDER_ZYX),
6625 * in which case they will not match those in comm_cost_est,
6626 * but since that is mainly for testing purposes that's fine.
6628 if (dd
->ndim
>= 2 && dd
->dim
[0] == XX
&& dd
->dim
[1] == YY
&&
6629 comm
->npmenodes
> dd
->nc
[XX
] && comm
->npmenodes
% dd
->nc
[XX
] == 0 &&
6630 getenv("GMX_PMEONEDD") == nullptr)
6632 comm
->npmedecompdim
= 2;
6633 comm
->npmenodes_x
= dd
->nc
[XX
];
6634 comm
->npmenodes_y
= comm
->npmenodes
/comm
->npmenodes_x
;
6638 /* In case nc is 1 in both x and y we could still choose to
6639 * decompose pme in y instead of x, but we use x for simplicity.
6641 comm
->npmedecompdim
= 1;
6642 if (dd
->dim
[0] == YY
)
6644 comm
->npmenodes_x
= 1;
6645 comm
->npmenodes_y
= comm
->npmenodes
;
6649 comm
->npmenodes_x
= comm
->npmenodes
;
6650 comm
->npmenodes_y
= 1;
6655 fprintf(fplog
, "PME domain decomposition: %d x %d x %d\n",
6656 comm
->npmenodes_x
, comm
->npmenodes_y
, 1);
6661 comm
->npmedecompdim
= 0;
6662 comm
->npmenodes_x
= 0;
6663 comm
->npmenodes_y
= 0;
6666 /* Technically we don't need both of these,
6667 * but it simplifies code not having to recalculate it.
6669 *npme_x
= comm
->npmenodes_x
;
6670 *npme_y
= comm
->npmenodes_y
;
6672 snew(comm
->slb_frac
, DIM
);
6673 if (isDlbDisabled(comm
))
6675 comm
->slb_frac
[XX
] = get_slb_frac(fplog
, "x", dd
->nc
[XX
], options
.cellSizeX
);
6676 comm
->slb_frac
[YY
] = get_slb_frac(fplog
, "y", dd
->nc
[YY
], options
.cellSizeY
);
6677 comm
->slb_frac
[ZZ
] = get_slb_frac(fplog
, "z", dd
->nc
[ZZ
], options
.cellSizeZ
);
6680 if (comm
->bInterCGBondeds
&& comm
->cutoff_mbody
== 0)
6682 if (comm
->bBondComm
|| !isDlbDisabled(comm
))
6684 /* Set the bonded communication distance to halfway
6685 * the minimum and the maximum,
6686 * since the extra communication cost is nearly zero.
6688 real acs
= average_cellsize_min(dd
, ddbox
);
6689 comm
->cutoff_mbody
= 0.5*(r_bonded
+ acs
);
6690 if (!isDlbDisabled(comm
))
6692 /* Check if this does not limit the scaling */
6693 comm
->cutoff_mbody
= std::min(comm
->cutoff_mbody
,
6694 options
.dlbScaling
*acs
);
6696 if (!comm
->bBondComm
)
6698 /* Without bBondComm do not go beyond the n.b. cut-off */
6699 comm
->cutoff_mbody
= std::min(comm
->cutoff_mbody
, comm
->cutoff
);
6700 if (comm
->cellsize_limit
>= comm
->cutoff
)
6702 /* We don't loose a lot of efficieny
6703 * when increasing it to the n.b. cut-off.
6704 * It can even be slightly faster, because we need
6705 * less checks for the communication setup.
6707 comm
->cutoff_mbody
= comm
->cutoff
;
6710 /* Check if we did not end up below our original limit */
6711 comm
->cutoff_mbody
= std::max(comm
->cutoff_mbody
, r_bonded_limit
);
6713 if (comm
->cutoff_mbody
> comm
->cellsize_limit
)
6715 comm
->cellsize_limit
= comm
->cutoff_mbody
;
6718 /* Without DLB and cutoff_mbody<cutoff, cutoff_mbody is dynamic */
6723 fprintf(debug
, "Bonded atom communication beyond the cut-off: %d\n"
6724 "cellsize limit %f\n",
6725 comm
->bBondComm
, comm
->cellsize_limit
);
6730 check_dd_restrictions(cr
, dd
, ir
, fplog
);
6734 static void set_dlb_limits(gmx_domdec_t
*dd
)
6739 for (d
= 0; d
< dd
->ndim
; d
++)
6741 dd
->comm
->cd
[d
].np
= dd
->comm
->cd
[d
].np_dlb
;
6742 dd
->comm
->cellsize_min
[dd
->dim
[d
]] =
6743 dd
->comm
->cellsize_min_dlb
[dd
->dim
[d
]];
6748 static void turn_on_dlb(FILE *fplog
, const t_commrec
*cr
, gmx_int64_t step
)
6751 gmx_domdec_comm_t
*comm
;
6758 cellsize_min
= comm
->cellsize_min
[dd
->dim
[0]];
6759 for (d
= 1; d
< dd
->ndim
; d
++)
6761 cellsize_min
= std::min(cellsize_min
, comm
->cellsize_min
[dd
->dim
[d
]]);
6764 /* Turn off DLB if we're too close to the cell size limit. */
6765 if (cellsize_min
< comm
->cellsize_limit
*1.05)
6767 auto str
= gmx::formatString("step %" GMX_PRId64
" Measured %.1f %% performance loss due to load imbalance, "
6768 "but the minimum cell size is smaller than 1.05 times the cell size limit."
6769 "Will no longer try dynamic load balancing.\n", step
, dd_force_imb_perf_loss(dd
)*100);
6770 dd_warning(cr
, fplog
, str
.c_str());
6772 comm
->dlbState
= edlbsOffForever
;
6777 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);
6778 dd_warning(cr
, fplog
, buf
);
6779 comm
->dlbState
= edlbsOnCanTurnOff
;
6781 /* Store the non-DLB performance, so we can check if DLB actually
6782 * improves performance.
6784 GMX_RELEASE_ASSERT(comm
->cycl_n
[ddCyclStep
] > 0, "When we turned on DLB, we should have measured cycles");
6785 comm
->cyclesPerStepBeforeDLB
= comm
->cycl
[ddCyclStep
]/comm
->cycl_n
[ddCyclStep
];
6789 /* We can set the required cell size info here,
6790 * so we do not need to communicate this.
6791 * The grid is completely uniform.
6793 for (d
= 0; d
< dd
->ndim
; d
++)
6797 comm
->load
[d
].sum_m
= comm
->load
[d
].sum
;
6799 nc
= dd
->nc
[dd
->dim
[d
]];
6800 for (i
= 0; i
< nc
; i
++)
6802 comm
->root
[d
]->cell_f
[i
] = i
/(real
)nc
;
6805 comm
->root
[d
]->cell_f_max0
[i
] = i
/(real
)nc
;
6806 comm
->root
[d
]->cell_f_min1
[i
] = (i
+1)/(real
)nc
;
6809 comm
->root
[d
]->cell_f
[nc
] = 1.0;
6814 static void turn_off_dlb(FILE *fplog
, const t_commrec
*cr
, gmx_int64_t step
)
6816 gmx_domdec_t
*dd
= cr
->dd
;
6819 sprintf(buf
, "step %" GMX_PRId64
" Turning off dynamic load balancing, because it is degrading performance.\n", step
);
6820 dd_warning(cr
, fplog
, buf
);
6821 dd
->comm
->dlbState
= edlbsOffCanTurnOn
;
6822 dd
->comm
->haveTurnedOffDlb
= true;
6823 dd
->comm
->ddPartioningCountFirstDlbOff
= dd
->ddp_count
;
6826 static void turn_off_dlb_forever(FILE *fplog
, const t_commrec
*cr
, gmx_int64_t step
)
6828 GMX_RELEASE_ASSERT(cr
->dd
->comm
->dlbState
== edlbsOffCanTurnOn
, "Can only turn off DLB forever when it was in the can-turn-on state");
6830 sprintf(buf
, "step %" GMX_PRId64
" Will no longer try dynamic load balancing, as it degraded performance.\n", step
);
6831 dd_warning(cr
, fplog
, buf
);
6832 cr
->dd
->comm
->dlbState
= edlbsOffForever
;
6835 static char *init_bLocalCG(const gmx_mtop_t
*mtop
)
6840 ncg
= ncg_mtop(mtop
);
6841 snew(bLocalCG
, ncg
);
6842 for (cg
= 0; cg
< ncg
; cg
++)
6844 bLocalCG
[cg
] = FALSE
;
6850 void dd_init_bondeds(FILE *fplog
,
6852 const gmx_mtop_t
*mtop
,
6853 const gmx_vsite_t
*vsite
,
6854 const t_inputrec
*ir
,
6855 gmx_bool bBCheck
, cginfo_mb_t
*cginfo_mb
)
6857 gmx_domdec_comm_t
*comm
;
6859 dd_make_reverse_top(fplog
, dd
, mtop
, vsite
, ir
, bBCheck
);
6863 if (comm
->bBondComm
)
6865 /* Communicate atoms beyond the cut-off for bonded interactions */
6868 comm
->cglink
= make_charge_group_links(mtop
, dd
, cginfo_mb
);
6870 comm
->bLocalCG
= init_bLocalCG(mtop
);
6874 /* Only communicate atoms based on cut-off */
6875 comm
->cglink
= nullptr;
6876 comm
->bLocalCG
= nullptr;
6880 static void print_dd_settings(FILE *fplog
, gmx_domdec_t
*dd
,
6881 const gmx_mtop_t
*mtop
, const t_inputrec
*ir
,
6882 gmx_bool bDynLoadBal
, real dlb_scale
,
6883 const gmx_ddbox_t
*ddbox
)
6885 gmx_domdec_comm_t
*comm
;
6891 if (fplog
== nullptr)
6900 fprintf(fplog
, "The maximum number of communication pulses is:");
6901 for (d
= 0; d
< dd
->ndim
; d
++)
6903 fprintf(fplog
, " %c %d", dim2char(dd
->dim
[d
]), comm
->cd
[d
].np_dlb
);
6905 fprintf(fplog
, "\n");
6906 fprintf(fplog
, "The minimum size for domain decomposition cells is %.3f nm\n", comm
->cellsize_limit
);
6907 fprintf(fplog
, "The requested allowed shrink of DD cells (option -dds) is: %.2f\n", dlb_scale
);
6908 fprintf(fplog
, "The allowed shrink of domain decomposition cells is:");
6909 for (d
= 0; d
< DIM
; d
++)
6913 if (d
>= ddbox
->npbcdim
&& dd
->nc
[d
] == 2)
6920 comm
->cellsize_min_dlb
[d
]/
6921 (ddbox
->box_size
[d
]*ddbox
->skew_fac
[d
]/dd
->nc
[d
]);
6923 fprintf(fplog
, " %c %.2f", dim2char(d
), shrink
);
6926 fprintf(fplog
, "\n");
6930 set_dd_cell_sizes_slb(dd
, ddbox
, setcellsizeslbPULSE_ONLY
, np
);
6931 fprintf(fplog
, "The initial number of communication pulses is:");
6932 for (d
= 0; d
< dd
->ndim
; d
++)
6934 fprintf(fplog
, " %c %d", dim2char(dd
->dim
[d
]), np
[dd
->dim
[d
]]);
6936 fprintf(fplog
, "\n");
6937 fprintf(fplog
, "The initial domain decomposition cell size is:");
6938 for (d
= 0; d
< DIM
; d
++)
6942 fprintf(fplog
, " %c %.2f nm",
6943 dim2char(d
), dd
->comm
->cellsize_min
[d
]);
6946 fprintf(fplog
, "\n\n");
6949 gmx_bool bInterCGVsites
= count_intercg_vsites(mtop
);
6951 if (comm
->bInterCGBondeds
||
6953 dd
->bInterCGcons
|| dd
->bInterCGsettles
)
6955 fprintf(fplog
, "The maximum allowed distance for charge groups involved in interactions is:\n");
6956 fprintf(fplog
, "%40s %-7s %6.3f nm\n",
6957 "non-bonded interactions", "", comm
->cutoff
);
6961 limit
= dd
->comm
->cellsize_limit
;
6965 if (dynamic_dd_box(ddbox
, ir
))
6967 fprintf(fplog
, "(the following are initial values, they could change due to box deformation)\n");
6969 limit
= dd
->comm
->cellsize_min
[XX
];
6970 for (d
= 1; d
< DIM
; d
++)
6972 limit
= std::min(limit
, dd
->comm
->cellsize_min
[d
]);
6976 if (comm
->bInterCGBondeds
)
6978 fprintf(fplog
, "%40s %-7s %6.3f nm\n",
6979 "two-body bonded interactions", "(-rdd)",
6980 std::max(comm
->cutoff
, comm
->cutoff_mbody
));
6981 fprintf(fplog
, "%40s %-7s %6.3f nm\n",
6982 "multi-body bonded interactions", "(-rdd)",
6983 (comm
->bBondComm
|| isDlbOn(dd
->comm
)) ? comm
->cutoff_mbody
: std::min(comm
->cutoff
, limit
));
6987 fprintf(fplog
, "%40s %-7s %6.3f nm\n",
6988 "virtual site constructions", "(-rcon)", limit
);
6990 if (dd
->bInterCGcons
|| dd
->bInterCGsettles
)
6992 sprintf(buf
, "atoms separated by up to %d constraints",
6994 fprintf(fplog
, "%40s %-7s %6.3f nm\n",
6995 buf
, "(-rcon)", limit
);
6997 fprintf(fplog
, "\n");
7003 static void set_cell_limits_dlb(gmx_domdec_t
*dd
,
7005 const t_inputrec
*ir
,
7006 const gmx_ddbox_t
*ddbox
)
7008 gmx_domdec_comm_t
*comm
;
7009 int d
, dim
, npulse
, npulse_d_max
, npulse_d
;
7014 bNoCutOff
= (ir
->rvdw
== 0 || ir
->rcoulomb
== 0);
7016 /* Determine the maximum number of comm. pulses in one dimension */
7018 comm
->cellsize_limit
= std::max(comm
->cellsize_limit
, comm
->cutoff_mbody
);
7020 /* Determine the maximum required number of grid pulses */
7021 if (comm
->cellsize_limit
>= comm
->cutoff
)
7023 /* Only a single pulse is required */
7026 else if (!bNoCutOff
&& comm
->cellsize_limit
> 0)
7028 /* We round down slightly here to avoid overhead due to the latency
7029 * of extra communication calls when the cut-off
7030 * would be only slightly longer than the cell size.
7031 * Later cellsize_limit is redetermined,
7032 * so we can not miss interactions due to this rounding.
7034 npulse
= (int)(0.96 + comm
->cutoff
/comm
->cellsize_limit
);
7038 /* There is no cell size limit */
7039 npulse
= std::max(dd
->nc
[XX
]-1, std::max(dd
->nc
[YY
]-1, dd
->nc
[ZZ
]-1));
7042 if (!bNoCutOff
&& npulse
> 1)
7044 /* See if we can do with less pulses, based on dlb_scale */
7046 for (d
= 0; d
< dd
->ndim
; d
++)
7049 npulse_d
= (int)(1 + dd
->nc
[dim
]*comm
->cutoff
7050 /(ddbox
->box_size
[dim
]*ddbox
->skew_fac
[dim
]*dlb_scale
));
7051 npulse_d_max
= std::max(npulse_d_max
, npulse_d
);
7053 npulse
= std::min(npulse
, npulse_d_max
);
7056 /* This env var can override npulse */
7057 d
= dd_getenv(debug
, "GMX_DD_NPULSE", 0);
7064 comm
->bVacDLBNoLimit
= (ir
->ePBC
== epbcNONE
);
7065 for (d
= 0; d
< dd
->ndim
; d
++)
7067 comm
->cd
[d
].np_dlb
= std::min(npulse
, dd
->nc
[dd
->dim
[d
]]-1);
7068 comm
->cd
[d
].np_nalloc
= comm
->cd
[d
].np_dlb
;
7069 snew(comm
->cd
[d
].ind
, comm
->cd
[d
].np_nalloc
);
7070 comm
->maxpulse
= std::max(comm
->maxpulse
, comm
->cd
[d
].np_dlb
);
7071 if (comm
->cd
[d
].np_dlb
< dd
->nc
[dd
->dim
[d
]]-1)
7073 comm
->bVacDLBNoLimit
= FALSE
;
7077 /* cellsize_limit is set for LINCS in init_domain_decomposition */
7078 if (!comm
->bVacDLBNoLimit
)
7080 comm
->cellsize_limit
= std::max(comm
->cellsize_limit
,
7081 comm
->cutoff
/comm
->maxpulse
);
7083 comm
->cellsize_limit
= std::max(comm
->cellsize_limit
, comm
->cutoff_mbody
);
7084 /* Set the minimum cell size for each DD dimension */
7085 for (d
= 0; d
< dd
->ndim
; d
++)
7087 if (comm
->bVacDLBNoLimit
||
7088 comm
->cd
[d
].np_dlb
*comm
->cellsize_limit
>= comm
->cutoff
)
7090 comm
->cellsize_min_dlb
[dd
->dim
[d
]] = comm
->cellsize_limit
;
7094 comm
->cellsize_min_dlb
[dd
->dim
[d
]] =
7095 comm
->cutoff
/comm
->cd
[d
].np_dlb
;
7098 if (comm
->cutoff_mbody
<= 0)
7100 comm
->cutoff_mbody
= std::min(comm
->cutoff
, comm
->cellsize_limit
);
7108 gmx_bool
dd_bonded_molpbc(const gmx_domdec_t
*dd
, int ePBC
)
7110 /* If each molecule is a single charge group
7111 * or we use domain decomposition for each periodic dimension,
7112 * we do not need to take pbc into account for the bonded interactions.
7114 return (ePBC
!= epbcNONE
&& dd
->comm
->bInterCGBondeds
&&
7117 (dd
->nc
[ZZ
] > 1 || ePBC
== epbcXY
)));
7120 /*! \brief Sets grid size limits and PP-PME setup, prints settings to log */
7121 static void set_ddgrid_parameters(FILE *fplog
, gmx_domdec_t
*dd
, real dlb_scale
,
7122 const gmx_mtop_t
*mtop
, const t_inputrec
*ir
,
7123 const gmx_ddbox_t
*ddbox
)
7125 gmx_domdec_comm_t
*comm
;
7131 if (EEL_PME(ir
->coulombtype
) || EVDW_PME(ir
->vdwtype
))
7133 init_ddpme(dd
, &comm
->ddpme
[0], 0);
7134 if (comm
->npmedecompdim
>= 2)
7136 init_ddpme(dd
, &comm
->ddpme
[1], 1);
7141 comm
->npmenodes
= 0;
7142 if (dd
->pme_nodeid
>= 0)
7144 gmx_fatal_collective(FARGS
, dd
->mpi_comm_all
, DDMASTER(dd
),
7145 "Can not have separate PME ranks without PME electrostatics");
7151 fprintf(debug
, "The DD cut-off is %f\n", comm
->cutoff
);
7153 if (!isDlbDisabled(comm
))
7155 set_cell_limits_dlb(dd
, dlb_scale
, ir
, ddbox
);
7158 print_dd_settings(fplog
, dd
, mtop
, ir
, isDlbOn(comm
), dlb_scale
, ddbox
);
7159 if (comm
->dlbState
== edlbsOffCanTurnOn
)
7163 fprintf(fplog
, "When dynamic load balancing gets turned on, these settings will change to:\n");
7165 print_dd_settings(fplog
, dd
, mtop
, ir
, TRUE
, dlb_scale
, ddbox
);
7168 if (ir
->ePBC
== epbcNONE
)
7170 vol_frac
= 1 - 1/(double)dd
->nnodes
;
7175 (1 + comm_box_frac(dd
->nc
, comm
->cutoff
, ddbox
))/(double)dd
->nnodes
;
7179 fprintf(debug
, "Volume fraction for all DD zones: %f\n", vol_frac
);
7181 natoms_tot
= comm
->cgs_gl
.index
[comm
->cgs_gl
.nr
];
7183 dd
->ga2la
= ga2la_init(natoms_tot
, static_cast<int>(vol_frac
*natoms_tot
));
7186 /*! \brief Set some important DD parameters that can be modified by env.vars */
7187 static void set_dd_envvar_options(FILE *fplog
, gmx_domdec_t
*dd
, int rank_mysim
)
7189 gmx_domdec_comm_t
*comm
= dd
->comm
;
7191 dd
->bSendRecv2
= dd_getenv(fplog
, "GMX_DD_USE_SENDRECV2", 0);
7192 comm
->dlb_scale_lim
= dd_getenv(fplog
, "GMX_DLB_MAX_BOX_SCALING", 10);
7193 comm
->eFlop
= dd_getenv(fplog
, "GMX_DLB_BASED_ON_FLOPS", 0);
7194 int recload
= dd_getenv(fplog
, "GMX_DD_RECORD_LOAD", 1);
7195 comm
->nstDDDump
= dd_getenv(fplog
, "GMX_DD_NST_DUMP", 0);
7196 comm
->nstDDDumpGrid
= dd_getenv(fplog
, "GMX_DD_NST_DUMP_GRID", 0);
7197 comm
->DD_debug
= dd_getenv(fplog
, "GMX_DD_DEBUG", 0);
7199 if (dd
->bSendRecv2
&& fplog
)
7201 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");
7208 fprintf(fplog
, "Will load balance based on FLOP count\n");
7210 if (comm
->eFlop
> 1)
7212 srand(1 + rank_mysim
);
7214 comm
->bRecordLoad
= TRUE
;
7218 comm
->bRecordLoad
= (wallcycle_have_counter() && recload
> 0);
7222 DomdecOptions::DomdecOptions() :
7223 checkBondedInteractions(TRUE
),
7224 useBondedCommunication(TRUE
),
7226 rankOrder(DdRankOrder::pp_pme
),
7227 minimumCommunicationRange(0),
7228 constraintCommunicationRange(0),
7229 dlbOption(DlbOption::turnOnWhenUseful
),
7235 clear_ivec(numCells
);
7238 gmx_domdec_t
*init_domain_decomposition(FILE *fplog
, t_commrec
*cr
,
7239 const DomdecOptions
&options
,
7240 const MdrunOptions
&mdrunOptions
,
7241 const gmx_mtop_t
*mtop
,
7242 const t_inputrec
*ir
,
7244 const rvec
*xGlobal
,
7246 int *npme_x
, int *npme_y
)
7253 "\nInitializing Domain Decomposition on %d ranks\n", cr
->nnodes
);
7258 dd
->comm
= init_dd_comm();
7260 set_dd_envvar_options(fplog
, dd
, cr
->nodeid
);
7262 set_dd_limits_and_grid(fplog
, cr
, dd
, options
, mdrunOptions
,
7268 make_dd_communicators(fplog
, cr
, dd
, options
.rankOrder
);
7270 if (thisRankHasDuty(cr
, DUTY_PP
))
7272 set_ddgrid_parameters(fplog
, dd
, options
.dlbScaling
, mtop
, ir
, ddbox
);
7274 setup_neighbor_relations(dd
);
7277 /* Set overallocation to avoid frequent reallocation of arrays */
7278 set_over_alloc_dd(TRUE
);
7280 /* Initialize DD paritioning counters */
7281 dd
->comm
->partition_step
= INT_MIN
;
7284 /* We currently don't know the number of threads yet, we set this later */
7287 clear_dd_cycle_counts(dd
);
7292 static gmx_bool
test_dd_cutoff(t_commrec
*cr
,
7293 t_state
*state
, const t_inputrec
*ir
,
7304 set_ddbox(dd
, FALSE
, cr
, ir
, state
->box
,
7305 TRUE
, &dd
->comm
->cgs_gl
, as_rvec_array(state
->x
.data()), &ddbox
);
7309 for (d
= 0; d
< dd
->ndim
; d
++)
7313 inv_cell_size
= DD_CELL_MARGIN
*dd
->nc
[dim
]/ddbox
.box_size
[dim
];
7314 if (dynamic_dd_box(&ddbox
, ir
))
7316 inv_cell_size
*= DD_PRES_SCALE_MARGIN
;
7319 np
= 1 + (int)(cutoff_req
*inv_cell_size
*ddbox
.skew_fac
[dim
]);
7321 if (!isDlbDisabled(dd
->comm
) && (dim
< ddbox
.npbcdim
) && (dd
->comm
->cd
[d
].np_dlb
> 0))
7323 if (np
> dd
->comm
->cd
[d
].np_dlb
)
7328 /* If a current local cell size is smaller than the requested
7329 * cut-off, we could still fix it, but this gets very complicated.
7330 * Without fixing here, we might actually need more checks.
7332 if ((dd
->comm
->cell_x1
[dim
] - dd
->comm
->cell_x0
[dim
])*ddbox
.skew_fac
[dim
]*dd
->comm
->cd
[d
].np_dlb
< cutoff_req
)
7339 if (!isDlbDisabled(dd
->comm
))
7341 /* If DLB is not active yet, we don't need to check the grid jumps.
7342 * Actually we shouldn't, because then the grid jump data is not set.
7344 if (isDlbOn(dd
->comm
) &&
7345 check_grid_jump(0, dd
, cutoff_req
, &ddbox
, FALSE
))
7350 gmx_sumi(1, &LocallyLimited
, cr
);
7352 if (LocallyLimited
> 0)
7361 gmx_bool
change_dd_cutoff(t_commrec
*cr
, t_state
*state
, const t_inputrec
*ir
,
7364 gmx_bool bCutoffAllowed
;
7366 bCutoffAllowed
= test_dd_cutoff(cr
, state
, ir
, cutoff_req
);
7370 cr
->dd
->comm
->cutoff
= cutoff_req
;
7373 return bCutoffAllowed
;
7376 void set_dd_dlb_max_cutoff(t_commrec
*cr
, real cutoff
)
7378 gmx_domdec_comm_t
*comm
;
7380 comm
= cr
->dd
->comm
;
7382 /* Turn on the DLB limiting (might have been on already) */
7383 comm
->bPMELoadBalDLBLimits
= TRUE
;
7385 /* Change the cut-off limit */
7386 comm
->PMELoadBal_max_cutoff
= cutoff
;
7390 fprintf(debug
, "PME load balancing set a limit to the DLB staggering such that a %f cut-off will continue to fit\n",
7391 comm
->PMELoadBal_max_cutoff
);
7395 /* Sets whether we should later check the load imbalance data, so that
7396 * we can trigger dynamic load balancing if enough imbalance has
7399 * Used after PME load balancing unlocks DLB, so that the check
7400 * whether DLB will be useful can happen immediately.
7402 static void dd_dlb_set_should_check_whether_to_turn_dlb_on(gmx_domdec_t
*dd
, gmx_bool bValue
)
7404 if (dd
->comm
->dlbState
== edlbsOffCanTurnOn
)
7406 dd
->comm
->bCheckWhetherToTurnDlbOn
= bValue
;
7410 /* Store the DD partitioning count, so we can ignore cycle counts
7411 * over the next nstlist steps, which are often slower.
7413 dd
->comm
->ddPartioningCountFirstDlbOff
= dd
->ddp_count
;
7418 /* Returns if we should check whether there has been enough load
7419 * imbalance to trigger dynamic load balancing.
7421 static gmx_bool
dd_dlb_get_should_check_whether_to_turn_dlb_on(gmx_domdec_t
*dd
)
7423 if (dd
->comm
->dlbState
!= edlbsOffCanTurnOn
)
7428 if (dd
->ddp_count
<= dd
->comm
->ddPartioningCountFirstDlbOff
)
7430 /* We ignore the first nstlist steps at the start of the run
7431 * or after PME load balancing or after turning DLB off, since
7432 * these often have extra allocation or cache miss overhead.
7437 if (dd
->comm
->cycl_n
[ddCyclStep
] == 0)
7439 /* We can have zero timed steps when dd_partition_system is called
7440 * more than once at the same step, e.g. with replica exchange.
7441 * Turning on DLB would trigger an assertion failure later, but is
7442 * also useless right after exchanging replicas.
7447 /* We should check whether we should use DLB directly after
7449 if (dd
->comm
->bCheckWhetherToTurnDlbOn
)
7451 /* This flag was set when the PME load-balancing routines
7452 unlocked DLB, and should now be cleared. */
7453 dd_dlb_set_should_check_whether_to_turn_dlb_on(dd
, FALSE
);
7456 /* We check whether we should use DLB every c_checkTurnDlbOnInterval
7457 * partitionings (we do not do this every partioning, so that we
7458 * avoid excessive communication). */
7459 if (dd
->comm
->n_load_have
% c_checkTurnDlbOnInterval
== c_checkTurnDlbOnInterval
- 1)
7467 gmx_bool
dd_dlb_is_on(const gmx_domdec_t
*dd
)
7469 return isDlbOn(dd
->comm
);
7472 gmx_bool
dd_dlb_is_locked(const gmx_domdec_t
*dd
)
7474 return (dd
->comm
->dlbState
== edlbsOffTemporarilyLocked
);
7477 void dd_dlb_lock(gmx_domdec_t
*dd
)
7479 /* We can only lock the DLB when it is set to auto, otherwise don't do anything */
7480 if (dd
->comm
->dlbState
== edlbsOffCanTurnOn
)
7482 dd
->comm
->dlbState
= edlbsOffTemporarilyLocked
;
7486 void dd_dlb_unlock(gmx_domdec_t
*dd
)
7488 /* We can only lock the DLB when it is set to auto, otherwise don't do anything */
7489 if (dd
->comm
->dlbState
== edlbsOffTemporarilyLocked
)
7491 dd
->comm
->dlbState
= edlbsOffCanTurnOn
;
7492 dd_dlb_set_should_check_whether_to_turn_dlb_on(dd
, TRUE
);
7496 static void merge_cg_buffers(int ncell
,
7497 gmx_domdec_comm_dim_t
*cd
, int pulse
,
7499 int *index_gl
, int *recv_i
,
7500 rvec
*cg_cm
, rvec
*recv_vr
,
7502 cginfo_mb_t
*cginfo_mb
, int *cginfo
)
7504 gmx_domdec_ind_t
*ind
, *ind_p
;
7505 int p
, cell
, c
, cg
, cg0
, cg1
, cg_gl
, nat
;
7506 int shift
, shift_at
;
7508 ind
= &cd
->ind
[pulse
];
7510 /* First correct the already stored data */
7511 shift
= ind
->nrecv
[ncell
];
7512 for (cell
= ncell
-1; cell
>= 0; cell
--)
7514 shift
-= ind
->nrecv
[cell
];
7517 /* Move the cg's present from previous grid pulses */
7518 cg0
= ncg_cell
[ncell
+cell
];
7519 cg1
= ncg_cell
[ncell
+cell
+1];
7520 cgindex
[cg1
+shift
] = cgindex
[cg1
];
7521 for (cg
= cg1
-1; cg
>= cg0
; cg
--)
7523 index_gl
[cg
+shift
] = index_gl
[cg
];
7524 copy_rvec(cg_cm
[cg
], cg_cm
[cg
+shift
]);
7525 cgindex
[cg
+shift
] = cgindex
[cg
];
7526 cginfo
[cg
+shift
] = cginfo
[cg
];
7528 /* Correct the already stored send indices for the shift */
7529 for (p
= 1; p
<= pulse
; p
++)
7531 ind_p
= &cd
->ind
[p
];
7533 for (c
= 0; c
< cell
; c
++)
7535 cg0
+= ind_p
->nsend
[c
];
7537 cg1
= cg0
+ ind_p
->nsend
[cell
];
7538 for (cg
= cg0
; cg
< cg1
; cg
++)
7540 ind_p
->index
[cg
] += shift
;
7546 /* Merge in the communicated buffers */
7550 for (cell
= 0; cell
< ncell
; cell
++)
7552 cg1
= ncg_cell
[ncell
+cell
+1] + shift
;
7555 /* Correct the old cg indices */
7556 for (cg
= ncg_cell
[ncell
+cell
]; cg
< cg1
; cg
++)
7558 cgindex
[cg
+1] += shift_at
;
7561 for (cg
= 0; cg
< ind
->nrecv
[cell
]; cg
++)
7563 /* Copy this charge group from the buffer */
7564 index_gl
[cg1
] = recv_i
[cg0
];
7565 copy_rvec(recv_vr
[cg0
], cg_cm
[cg1
]);
7566 /* Add it to the cgindex */
7567 cg_gl
= index_gl
[cg1
];
7568 cginfo
[cg1
] = ddcginfo(cginfo_mb
, cg_gl
);
7569 nat
= GET_CGINFO_NATOMS(cginfo
[cg1
]);
7570 cgindex
[cg1
+1] = cgindex
[cg1
] + nat
;
7575 shift
+= ind
->nrecv
[cell
];
7576 ncg_cell
[ncell
+cell
+1] = cg1
;
7580 static void make_cell2at_index(gmx_domdec_comm_dim_t
*cd
,
7581 int nzone
, int cg0
, const int *cgindex
)
7585 /* Store the atom block boundaries for easy copying of communication buffers
7588 for (zone
= 0; zone
< nzone
; zone
++)
7590 for (p
= 0; p
< cd
->np
; p
++)
7592 cd
->ind
[p
].cell2at0
[zone
] = cgindex
[cg
];
7593 cg
+= cd
->ind
[p
].nrecv
[zone
];
7594 cd
->ind
[p
].cell2at1
[zone
] = cgindex
[cg
];
7599 static gmx_bool
missing_link(t_blocka
*link
, int cg_gl
, char *bLocalCG
)
7605 for (i
= link
->index
[cg_gl
]; i
< link
->index
[cg_gl
+1]; i
++)
7607 if (!bLocalCG
[link
->a
[i
]])
7616 /* Domain corners for communication, a maximum of 4 i-zones see a j domain */
7618 real c
[DIM
][4]; /* the corners for the non-bonded communication */
7619 real cr0
; /* corner for rounding */
7620 real cr1
[4]; /* corners for rounding */
7621 real bc
[DIM
]; /* corners for bounded communication */
7622 real bcr1
; /* corner for rounding for bonded communication */
7625 /* Determine the corners of the domain(s) we are communicating with */
7627 set_dd_corners(const gmx_domdec_t
*dd
,
7628 int dim0
, int dim1
, int dim2
,
7632 const gmx_domdec_comm_t
*comm
;
7633 const gmx_domdec_zones_t
*zones
;
7638 zones
= &comm
->zones
;
7640 /* Keep the compiler happy */
7644 /* The first dimension is equal for all cells */
7645 c
->c
[0][0] = comm
->cell_x0
[dim0
];
7648 c
->bc
[0] = c
->c
[0][0];
7653 /* This cell row is only seen from the first row */
7654 c
->c
[1][0] = comm
->cell_x0
[dim1
];
7655 /* All rows can see this row */
7656 c
->c
[1][1] = comm
->cell_x0
[dim1
];
7657 if (isDlbOn(dd
->comm
))
7659 c
->c
[1][1] = std::max(comm
->cell_x0
[dim1
], comm
->zone_d1
[1].mch0
);
7662 /* For the multi-body distance we need the maximum */
7663 c
->bc
[1] = std::max(comm
->cell_x0
[dim1
], comm
->zone_d1
[1].p1_0
);
7666 /* Set the upper-right corner for rounding */
7667 c
->cr0
= comm
->cell_x1
[dim0
];
7672 for (j
= 0; j
< 4; j
++)
7674 c
->c
[2][j
] = comm
->cell_x0
[dim2
];
7676 if (isDlbOn(dd
->comm
))
7678 /* Use the maximum of the i-cells that see a j-cell */
7679 for (i
= 0; i
< zones
->nizone
; i
++)
7681 for (j
= zones
->izone
[i
].j0
; j
< zones
->izone
[i
].j1
; j
++)
7686 std::max(c
->c
[2][j
-4],
7687 comm
->zone_d2
[zones
->shift
[i
][dim0
]][zones
->shift
[i
][dim1
]].mch0
);
7693 /* For the multi-body distance we need the maximum */
7694 c
->bc
[2] = comm
->cell_x0
[dim2
];
7695 for (i
= 0; i
< 2; i
++)
7697 for (j
= 0; j
< 2; j
++)
7699 c
->bc
[2] = std::max(c
->bc
[2], comm
->zone_d2
[i
][j
].p1_0
);
7705 /* Set the upper-right corner for rounding */
7706 /* Cell (0,0,0) and cell (1,0,0) can see cell 4 (0,1,1)
7707 * Only cell (0,0,0) can see cell 7 (1,1,1)
7709 c
->cr1
[0] = comm
->cell_x1
[dim1
];
7710 c
->cr1
[3] = comm
->cell_x1
[dim1
];
7711 if (isDlbOn(dd
->comm
))
7713 c
->cr1
[0] = std::max(comm
->cell_x1
[dim1
], comm
->zone_d1
[1].mch1
);
7716 /* For the multi-body distance we need the maximum */
7717 c
->bcr1
= std::max(comm
->cell_x1
[dim1
], comm
->zone_d1
[1].p1_1
);
7724 /* Determine which cg's we need to send in this pulse from this zone */
7726 get_zone_pulse_cgs(gmx_domdec_t
*dd
,
7727 int zonei
, int zone
,
7729 const int *index_gl
,
7731 int dim
, int dim_ind
,
7732 int dim0
, int dim1
, int dim2
,
7733 real r_comm2
, real r_bcomm2
,
7737 real skew_fac2_d
, real skew_fac_01
,
7738 rvec
*v_d
, rvec
*v_0
, rvec
*v_1
,
7739 const dd_corners_t
*c
,
7741 gmx_bool bDistBonded
,
7747 gmx_domdec_ind_t
*ind
,
7748 int **ibuf
, int *ibuf_nalloc
,
7754 gmx_domdec_comm_t
*comm
;
7756 gmx_bool bDistMB_pulse
;
7758 real r2
, rb2
, r
, tric_sh
;
7761 int nsend_z
, nsend
, nat
;
7765 bScrew
= (dd
->bScrewPBC
&& dim
== XX
);
7767 bDistMB_pulse
= (bDistMB
&& bDistBonded
);
7773 for (cg
= cg0
; cg
< cg1
; cg
++)
7777 if (tric_dist
[dim_ind
] == 0)
7779 /* Rectangular direction, easy */
7780 r
= cg_cm
[cg
][dim
] - c
->c
[dim_ind
][zone
];
7787 r
= cg_cm
[cg
][dim
] - c
->bc
[dim_ind
];
7793 /* Rounding gives at most a 16% reduction
7794 * in communicated atoms
7796 if (dim_ind
>= 1 && (zonei
== 1 || zonei
== 2))
7798 r
= cg_cm
[cg
][dim0
] - c
->cr0
;
7799 /* This is the first dimension, so always r >= 0 */
7806 if (dim_ind
== 2 && (zonei
== 2 || zonei
== 3))
7808 r
= cg_cm
[cg
][dim1
] - c
->cr1
[zone
];
7815 r
= cg_cm
[cg
][dim1
] - c
->bcr1
;
7825 /* Triclinic direction, more complicated */
7828 /* Rounding, conservative as the skew_fac multiplication
7829 * will slightly underestimate the distance.
7831 if (dim_ind
>= 1 && (zonei
== 1 || zonei
== 2))
7833 rn
[dim0
] = cg_cm
[cg
][dim0
] - c
->cr0
;
7834 for (i
= dim0
+1; i
< DIM
; i
++)
7836 rn
[dim0
] -= cg_cm
[cg
][i
]*v_0
[i
][dim0
];
7838 r2
= rn
[dim0
]*rn
[dim0
]*sf2_round
[dim0
];
7841 rb
[dim0
] = rn
[dim0
];
7844 /* Take care that the cell planes along dim0 might not
7845 * be orthogonal to those along dim1 and dim2.
7847 for (i
= 1; i
<= dim_ind
; i
++)
7850 if (normal
[dim0
][dimd
] > 0)
7852 rn
[dimd
] -= rn
[dim0
]*normal
[dim0
][dimd
];
7855 rb
[dimd
] -= rb
[dim0
]*normal
[dim0
][dimd
];
7860 if (dim_ind
== 2 && (zonei
== 2 || zonei
== 3))
7862 rn
[dim1
] += cg_cm
[cg
][dim1
] - c
->cr1
[zone
];
7864 for (i
= dim1
+1; i
< DIM
; i
++)
7866 tric_sh
-= cg_cm
[cg
][i
]*v_1
[i
][dim1
];
7868 rn
[dim1
] += tric_sh
;
7871 r2
+= rn
[dim1
]*rn
[dim1
]*sf2_round
[dim1
];
7872 /* Take care of coupling of the distances
7873 * to the planes along dim0 and dim1 through dim2.
7875 r2
-= rn
[dim0
]*rn
[dim1
]*skew_fac_01
;
7876 /* Take care that the cell planes along dim1
7877 * might not be orthogonal to that along dim2.
7879 if (normal
[dim1
][dim2
] > 0)
7881 rn
[dim2
] -= rn
[dim1
]*normal
[dim1
][dim2
];
7887 cg_cm
[cg
][dim1
] - c
->bcr1
+ tric_sh
;
7890 rb2
+= rb
[dim1
]*rb
[dim1
]*sf2_round
[dim1
];
7891 /* Take care of coupling of the distances
7892 * to the planes along dim0 and dim1 through dim2.
7894 rb2
-= rb
[dim0
]*rb
[dim1
]*skew_fac_01
;
7895 /* Take care that the cell planes along dim1
7896 * might not be orthogonal to that along dim2.
7898 if (normal
[dim1
][dim2
] > 0)
7900 rb
[dim2
] -= rb
[dim1
]*normal
[dim1
][dim2
];
7905 /* The distance along the communication direction */
7906 rn
[dim
] += cg_cm
[cg
][dim
] - c
->c
[dim_ind
][zone
];
7908 for (i
= dim
+1; i
< DIM
; i
++)
7910 tric_sh
-= cg_cm
[cg
][i
]*v_d
[i
][dim
];
7915 r2
+= rn
[dim
]*rn
[dim
]*skew_fac2_d
;
7916 /* Take care of coupling of the distances
7917 * to the planes along dim0 and dim1 through dim2.
7919 if (dim_ind
== 1 && zonei
== 1)
7921 r2
-= rn
[dim0
]*rn
[dim
]*skew_fac_01
;
7927 rb
[dim
] += cg_cm
[cg
][dim
] - c
->bc
[dim_ind
] + tric_sh
;
7930 rb2
+= rb
[dim
]*rb
[dim
]*skew_fac2_d
;
7931 /* Take care of coupling of the distances
7932 * to the planes along dim0 and dim1 through dim2.
7934 if (dim_ind
== 1 && zonei
== 1)
7936 rb2
-= rb
[dim0
]*rb
[dim
]*skew_fac_01
;
7944 ((bDistMB
&& rb2
< r_bcomm2
) ||
7945 (bDist2B
&& r2
< r_bcomm2
)) &&
7947 (GET_CGINFO_BOND_INTER(cginfo
[cg
]) &&
7948 missing_link(comm
->cglink
, index_gl
[cg
],
7951 /* Make an index to the local charge groups */
7952 if (nsend
+1 > ind
->nalloc
)
7954 ind
->nalloc
= over_alloc_large(nsend
+1);
7955 srenew(ind
->index
, ind
->nalloc
);
7957 if (nsend
+1 > *ibuf_nalloc
)
7959 *ibuf_nalloc
= over_alloc_large(nsend
+1);
7960 srenew(*ibuf
, *ibuf_nalloc
);
7962 ind
->index
[nsend
] = cg
;
7963 (*ibuf
)[nsend
] = index_gl
[cg
];
7965 vec_rvec_check_alloc(vbuf
, nsend
+1);
7967 if (dd
->ci
[dim
] == 0)
7969 /* Correct cg_cm for pbc */
7970 rvec_add(cg_cm
[cg
], box
[dim
], vbuf
->v
[nsend
]);
7973 vbuf
->v
[nsend
][YY
] = box
[YY
][YY
] - vbuf
->v
[nsend
][YY
];
7974 vbuf
->v
[nsend
][ZZ
] = box
[ZZ
][ZZ
] - vbuf
->v
[nsend
][ZZ
];
7979 copy_rvec(cg_cm
[cg
], vbuf
->v
[nsend
]);
7982 nat
+= cgindex
[cg
+1] - cgindex
[cg
];
7988 *nsend_z_ptr
= nsend_z
;
7991 static void setup_dd_communication(gmx_domdec_t
*dd
,
7992 matrix box
, gmx_ddbox_t
*ddbox
,
7994 t_state
*state
, PaddedRVecVector
*f
)
7996 int dim_ind
, dim
, dim0
, dim1
, dim2
, dimd
, p
, nat_tot
;
7997 int nzone
, nzone_send
, zone
, zonei
, cg0
, cg1
;
7998 int c
, i
, cg
, cg_gl
, nrcg
;
7999 int *zone_cg_range
, pos_cg
, *index_gl
, *cgindex
, *recv_i
;
8000 gmx_domdec_comm_t
*comm
;
8001 gmx_domdec_zones_t
*zones
;
8002 gmx_domdec_comm_dim_t
*cd
;
8003 gmx_domdec_ind_t
*ind
;
8004 cginfo_mb_t
*cginfo_mb
;
8005 gmx_bool bBondComm
, bDist2B
, bDistMB
, bDistBonded
;
8006 real r_comm2
, r_bcomm2
;
8007 dd_corners_t corners
;
8009 rvec
*cg_cm
, *normal
, *v_d
, *v_0
= nullptr, *v_1
= nullptr, *recv_vr
;
8010 real skew_fac2_d
, skew_fac_01
;
8017 fprintf(debug
, "Setting up DD communication\n");
8024 /* Initialize the thread data.
8025 * This can not be done in init_domain_decomposition,
8026 * as the numbers of threads is determined later.
8028 comm
->nth
= gmx_omp_nthreads_get(emntDomdec
);
8031 snew(comm
->dth
, comm
->nth
);
8035 switch (fr
->cutoff_scheme
)
8041 cg_cm
= as_rvec_array(state
->x
.data());
8044 gmx_incons("unimplemented");
8048 for (dim_ind
= 0; dim_ind
< dd
->ndim
; dim_ind
++)
8050 /* Check if we need to use triclinic distances */
8051 tric_dist
[dim_ind
] = 0;
8052 for (i
= 0; i
<= dim_ind
; i
++)
8054 if (ddbox
->tric_dir
[dd
->dim
[i
]])
8056 tric_dist
[dim_ind
] = 1;
8061 bBondComm
= comm
->bBondComm
;
8063 /* Do we need to determine extra distances for multi-body bondeds? */
8064 bDistMB
= (comm
->bInterCGMultiBody
&& isDlbOn(dd
->comm
) && dd
->ndim
> 1);
8066 /* Do we need to determine extra distances for only two-body bondeds? */
8067 bDist2B
= (bBondComm
&& !bDistMB
);
8069 r_comm2
= gmx::square(comm
->cutoff
);
8070 r_bcomm2
= gmx::square(comm
->cutoff_mbody
);
8074 fprintf(debug
, "bBondComm %d, r_bc %f\n", bBondComm
, std::sqrt(r_bcomm2
));
8077 zones
= &comm
->zones
;
8080 dim1
= (dd
->ndim
>= 2 ? dd
->dim
[1] : -1);
8081 dim2
= (dd
->ndim
>= 3 ? dd
->dim
[2] : -1);
8083 set_dd_corners(dd
, dim0
, dim1
, dim2
, bDistMB
, &corners
);
8085 /* Triclinic stuff */
8086 normal
= ddbox
->normal
;
8090 v_0
= ddbox
->v
[dim0
];
8091 if (ddbox
->tric_dir
[dim0
] && ddbox
->tric_dir
[dim1
])
8093 /* Determine the coupling coefficient for the distances
8094 * to the cell planes along dim0 and dim1 through dim2.
8095 * This is required for correct rounding.
8098 ddbox
->v
[dim0
][dim1
+1][dim0
]*ddbox
->v
[dim1
][dim1
+1][dim1
];
8101 fprintf(debug
, "\nskew_fac_01 %f\n", skew_fac_01
);
8107 v_1
= ddbox
->v
[dim1
];
8110 zone_cg_range
= zones
->cg_range
;
8111 index_gl
= dd
->index_gl
;
8112 cgindex
= dd
->cgindex
;
8113 cginfo_mb
= fr
->cginfo_mb
;
8115 zone_cg_range
[0] = 0;
8116 zone_cg_range
[1] = dd
->ncg_home
;
8117 comm
->zone_ncg1
[0] = dd
->ncg_home
;
8118 pos_cg
= dd
->ncg_home
;
8120 nat_tot
= dd
->nat_home
;
8122 for (dim_ind
= 0; dim_ind
< dd
->ndim
; dim_ind
++)
8124 dim
= dd
->dim
[dim_ind
];
8125 cd
= &comm
->cd
[dim_ind
];
8127 if (dim
>= ddbox
->npbcdim
&& dd
->ci
[dim
] == 0)
8129 /* No pbc in this dimension, the first node should not comm. */
8137 v_d
= ddbox
->v
[dim
];
8138 skew_fac2_d
= gmx::square(ddbox
->skew_fac
[dim
]);
8140 cd
->bInPlace
= TRUE
;
8141 for (p
= 0; p
< cd
->np
; p
++)
8143 /* Only atoms communicated in the first pulse are used
8144 * for multi-body bonded interactions or for bBondComm.
8146 bDistBonded
= ((bDistMB
|| bDist2B
) && p
== 0);
8151 for (zone
= 0; zone
< nzone_send
; zone
++)
8153 if (tric_dist
[dim_ind
] && dim_ind
> 0)
8155 /* Determine slightly more optimized skew_fac's
8157 * This reduces the number of communicated atoms
8158 * by about 10% for 3D DD of rhombic dodecahedra.
8160 for (dimd
= 0; dimd
< dim
; dimd
++)
8162 sf2_round
[dimd
] = 1;
8163 if (ddbox
->tric_dir
[dimd
])
8165 for (i
= dd
->dim
[dimd
]+1; i
< DIM
; i
++)
8167 /* If we are shifted in dimension i
8168 * and the cell plane is tilted forward
8169 * in dimension i, skip this coupling.
8171 if (!(zones
->shift
[nzone
+zone
][i
] &&
8172 ddbox
->v
[dimd
][i
][dimd
] >= 0))
8175 gmx::square(ddbox
->v
[dimd
][i
][dimd
]);
8178 sf2_round
[dimd
] = 1/sf2_round
[dimd
];
8183 zonei
= zone_perm
[dim_ind
][zone
];
8186 /* Here we permutate the zones to obtain a convenient order
8187 * for neighbor searching
8189 cg0
= zone_cg_range
[zonei
];
8190 cg1
= zone_cg_range
[zonei
+1];
8194 /* Look only at the cg's received in the previous grid pulse
8196 cg1
= zone_cg_range
[nzone
+zone
+1];
8197 cg0
= cg1
- cd
->ind
[p
-1].nrecv
[zone
];
8200 #pragma omp parallel for num_threads(comm->nth) schedule(static)
8201 for (th
= 0; th
< comm
->nth
; th
++)
8205 gmx_domdec_ind_t
*ind_p
;
8206 int **ibuf_p
, *ibuf_nalloc_p
;
8208 int *nsend_p
, *nat_p
;
8214 /* Thread 0 writes in the comm buffers */
8216 ibuf_p
= &comm
->buf_int
;
8217 ibuf_nalloc_p
= &comm
->nalloc_int
;
8218 vbuf_p
= &comm
->vbuf
;
8221 nsend_zone_p
= &ind
->nsend
[zone
];
8225 /* Other threads write into temp buffers */
8226 ind_p
= &comm
->dth
[th
].ind
;
8227 ibuf_p
= &comm
->dth
[th
].ibuf
;
8228 ibuf_nalloc_p
= &comm
->dth
[th
].ibuf_nalloc
;
8229 vbuf_p
= &comm
->dth
[th
].vbuf
;
8230 nsend_p
= &comm
->dth
[th
].nsend
;
8231 nat_p
= &comm
->dth
[th
].nat
;
8232 nsend_zone_p
= &comm
->dth
[th
].nsend_zone
;
8234 comm
->dth
[th
].nsend
= 0;
8235 comm
->dth
[th
].nat
= 0;
8236 comm
->dth
[th
].nsend_zone
= 0;
8246 cg0_th
= cg0
+ ((cg1
- cg0
)* th
)/comm
->nth
;
8247 cg1_th
= cg0
+ ((cg1
- cg0
)*(th
+1))/comm
->nth
;
8250 /* Get the cg's for this pulse in this zone */
8251 get_zone_pulse_cgs(dd
, zonei
, zone
, cg0_th
, cg1_th
,
8253 dim
, dim_ind
, dim0
, dim1
, dim2
,
8256 normal
, skew_fac2_d
, skew_fac_01
,
8257 v_d
, v_0
, v_1
, &corners
, sf2_round
,
8258 bDistBonded
, bBondComm
,
8262 ibuf_p
, ibuf_nalloc_p
,
8267 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
;
8270 /* Append data of threads>=1 to the communication buffers */
8271 for (th
= 1; th
< comm
->nth
; th
++)
8273 dd_comm_setup_work_t
*dth
;
8276 dth
= &comm
->dth
[th
];
8278 ns1
= nsend
+ dth
->nsend_zone
;
8279 if (ns1
> ind
->nalloc
)
8281 ind
->nalloc
= over_alloc_dd(ns1
);
8282 srenew(ind
->index
, ind
->nalloc
);
8284 if (ns1
> comm
->nalloc_int
)
8286 comm
->nalloc_int
= over_alloc_dd(ns1
);
8287 srenew(comm
->buf_int
, comm
->nalloc_int
);
8289 if (ns1
> comm
->vbuf
.nalloc
)
8291 comm
->vbuf
.nalloc
= over_alloc_dd(ns1
);
8292 srenew(comm
->vbuf
.v
, comm
->vbuf
.nalloc
);
8295 for (i
= 0; i
< dth
->nsend_zone
; i
++)
8297 ind
->index
[nsend
] = dth
->ind
.index
[i
];
8298 comm
->buf_int
[nsend
] = dth
->ibuf
[i
];
8299 copy_rvec(dth
->vbuf
.v
[i
],
8300 comm
->vbuf
.v
[nsend
]);
8304 ind
->nsend
[zone
] += dth
->nsend_zone
;
8307 /* Clear the counts in case we do not have pbc */
8308 for (zone
= nzone_send
; zone
< nzone
; zone
++)
8310 ind
->nsend
[zone
] = 0;
8312 ind
->nsend
[nzone
] = nsend
;
8313 ind
->nsend
[nzone
+1] = nat
;
8314 /* Communicate the number of cg's and atoms to receive */
8315 dd_sendrecv_int(dd
, dim_ind
, dddirBackward
,
8316 ind
->nsend
, nzone
+2,
8317 ind
->nrecv
, nzone
+2);
8319 /* The rvec buffer is also required for atom buffers of size nsend
8320 * in dd_move_x and dd_move_f.
8322 vec_rvec_check_alloc(&comm
->vbuf
, ind
->nsend
[nzone
+1]);
8326 /* We can receive in place if only the last zone is not empty */
8327 for (zone
= 0; zone
< nzone
-1; zone
++)
8329 if (ind
->nrecv
[zone
] > 0)
8331 cd
->bInPlace
= FALSE
;
8336 /* The int buffer is only required here for the cg indices */
8337 if (ind
->nrecv
[nzone
] > comm
->nalloc_int2
)
8339 comm
->nalloc_int2
= over_alloc_dd(ind
->nrecv
[nzone
]);
8340 srenew(comm
->buf_int2
, comm
->nalloc_int2
);
8342 /* The rvec buffer is also required for atom buffers
8343 * of size nrecv in dd_move_x and dd_move_f.
8345 i
= std::max(cd
->ind
[0].nrecv
[nzone
+1], ind
->nrecv
[nzone
+1]);
8346 vec_rvec_check_alloc(&comm
->vbuf2
, i
);
8350 /* Make space for the global cg indices */
8351 if (pos_cg
+ ind
->nrecv
[nzone
] > dd
->cg_nalloc
8352 || dd
->cg_nalloc
== 0)
8354 dd
->cg_nalloc
= over_alloc_dd(pos_cg
+ ind
->nrecv
[nzone
]);
8355 srenew(index_gl
, dd
->cg_nalloc
);
8356 srenew(cgindex
, dd
->cg_nalloc
+1);
8358 /* Communicate the global cg indices */
8361 recv_i
= index_gl
+ pos_cg
;
8365 recv_i
= comm
->buf_int2
;
8367 dd_sendrecv_int(dd
, dim_ind
, dddirBackward
,
8368 comm
->buf_int
, nsend
,
8369 recv_i
, ind
->nrecv
[nzone
]);
8371 /* Make space for cg_cm */
8372 dd_check_alloc_ncg(fr
, state
, f
, pos_cg
+ ind
->nrecv
[nzone
]);
8373 if (fr
->cutoff_scheme
== ecutsGROUP
)
8379 cg_cm
= as_rvec_array(state
->x
.data());
8381 /* Communicate cg_cm */
8384 recv_vr
= cg_cm
+ pos_cg
;
8388 recv_vr
= comm
->vbuf2
.v
;
8390 dd_sendrecv_rvec(dd
, dim_ind
, dddirBackward
,
8391 comm
->vbuf
.v
, nsend
,
8392 recv_vr
, ind
->nrecv
[nzone
]);
8394 /* Make the charge group index */
8397 zone
= (p
== 0 ? 0 : nzone
- 1);
8398 while (zone
< nzone
)
8400 for (cg
= 0; cg
< ind
->nrecv
[zone
]; cg
++)
8402 cg_gl
= index_gl
[pos_cg
];
8403 fr
->cginfo
[pos_cg
] = ddcginfo(cginfo_mb
, cg_gl
);
8404 nrcg
= GET_CGINFO_NATOMS(fr
->cginfo
[pos_cg
]);
8405 cgindex
[pos_cg
+1] = cgindex
[pos_cg
] + nrcg
;
8408 /* Update the charge group presence,
8409 * so we can use it in the next pass of the loop.
8411 comm
->bLocalCG
[cg_gl
] = TRUE
;
8417 comm
->zone_ncg1
[nzone
+zone
] = ind
->nrecv
[zone
];
8420 zone_cg_range
[nzone
+zone
] = pos_cg
;
8425 /* This part of the code is never executed with bBondComm. */
8426 merge_cg_buffers(nzone
, cd
, p
, zone_cg_range
,
8427 index_gl
, recv_i
, cg_cm
, recv_vr
,
8428 cgindex
, fr
->cginfo_mb
, fr
->cginfo
);
8429 pos_cg
+= ind
->nrecv
[nzone
];
8431 nat_tot
+= ind
->nrecv
[nzone
+1];
8435 /* Store the atom block for easy copying of communication buffers */
8436 make_cell2at_index(cd
, nzone
, zone_cg_range
[nzone
], cgindex
);
8440 dd
->index_gl
= index_gl
;
8441 dd
->cgindex
= cgindex
;
8443 dd
->ncg_tot
= zone_cg_range
[zones
->n
];
8444 dd
->nat_tot
= nat_tot
;
8445 comm
->nat
[ddnatHOME
] = dd
->nat_home
;
8446 for (i
= ddnatZONE
; i
< ddnatNR
; i
++)
8448 comm
->nat
[i
] = dd
->nat_tot
;
8453 /* We don't need to update cginfo, since that was alrady done above.
8454 * So we pass NULL for the forcerec.
8456 dd_set_cginfo(dd
->index_gl
, dd
->ncg_home
, dd
->ncg_tot
,
8457 nullptr, comm
->bLocalCG
);
8462 fprintf(debug
, "Finished setting up DD communication, zones:");
8463 for (c
= 0; c
< zones
->n
; c
++)
8465 fprintf(debug
, " %d", zones
->cg_range
[c
+1]-zones
->cg_range
[c
]);
8467 fprintf(debug
, "\n");
8471 static void set_cg_boundaries(gmx_domdec_zones_t
*zones
)
8475 for (c
= 0; c
< zones
->nizone
; c
++)
8477 zones
->izone
[c
].cg1
= zones
->cg_range
[c
+1];
8478 zones
->izone
[c
].jcg0
= zones
->cg_range
[zones
->izone
[c
].j0
];
8479 zones
->izone
[c
].jcg1
= zones
->cg_range
[zones
->izone
[c
].j1
];
8483 /* \brief Set zone dimensions for zones \p zone_start to \p zone_end-1
8485 * Also sets the atom density for the home zone when \p zone_start=0.
8486 * For this \p numMovedChargeGroupsInHomeZone needs to be passed to tell
8487 * how many charge groups will move but are still part of the current range.
8488 * \todo When converting domdec to use proper classes, all these variables
8489 * should be private and a method should return the correct count
8490 * depending on an internal state.
8492 * \param[in,out] dd The domain decomposition struct
8493 * \param[in] box The box
8494 * \param[in] ddbox The domain decomposition box struct
8495 * \param[in] zone_start The start of the zone range to set sizes for
8496 * \param[in] zone_end The end of the zone range to set sizes for
8497 * \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
8499 static void set_zones_size(gmx_domdec_t
*dd
,
8500 matrix box
, const gmx_ddbox_t
*ddbox
,
8501 int zone_start
, int zone_end
,
8502 int numMovedChargeGroupsInHomeZone
)
8504 gmx_domdec_comm_t
*comm
;
8505 gmx_domdec_zones_t
*zones
;
8514 zones
= &comm
->zones
;
8516 /* Do we need to determine extra distances for multi-body bondeds? */
8517 bDistMB
= (comm
->bInterCGMultiBody
&& isDlbOn(dd
->comm
) && dd
->ndim
> 1);
8519 for (z
= zone_start
; z
< zone_end
; z
++)
8521 /* Copy cell limits to zone limits.
8522 * Valid for non-DD dims and non-shifted dims.
8524 copy_rvec(comm
->cell_x0
, zones
->size
[z
].x0
);
8525 copy_rvec(comm
->cell_x1
, zones
->size
[z
].x1
);
8528 for (d
= 0; d
< dd
->ndim
; d
++)
8532 for (z
= 0; z
< zones
->n
; z
++)
8534 /* With a staggered grid we have different sizes
8535 * for non-shifted dimensions.
8537 if (isDlbOn(dd
->comm
) && zones
->shift
[z
][dim
] == 0)
8541 zones
->size
[z
].x0
[dim
] = comm
->zone_d1
[zones
->shift
[z
][dd
->dim
[d
-1]]].min0
;
8542 zones
->size
[z
].x1
[dim
] = comm
->zone_d1
[zones
->shift
[z
][dd
->dim
[d
-1]]].max1
;
8546 zones
->size
[z
].x0
[dim
] = comm
->zone_d2
[zones
->shift
[z
][dd
->dim
[d
-2]]][zones
->shift
[z
][dd
->dim
[d
-1]]].min0
;
8547 zones
->size
[z
].x1
[dim
] = comm
->zone_d2
[zones
->shift
[z
][dd
->dim
[d
-2]]][zones
->shift
[z
][dd
->dim
[d
-1]]].max1
;
8553 rcmbs
= comm
->cutoff_mbody
;
8554 if (ddbox
->tric_dir
[dim
])
8556 rcs
/= ddbox
->skew_fac
[dim
];
8557 rcmbs
/= ddbox
->skew_fac
[dim
];
8560 /* Set the lower limit for the shifted zone dimensions */
8561 for (z
= zone_start
; z
< zone_end
; z
++)
8563 if (zones
->shift
[z
][dim
] > 0)
8566 if (!isDlbOn(dd
->comm
) || d
== 0)
8568 zones
->size
[z
].x0
[dim
] = comm
->cell_x1
[dim
];
8569 zones
->size
[z
].x1
[dim
] = comm
->cell_x1
[dim
] + rcs
;
8573 /* Here we take the lower limit of the zone from
8574 * the lowest domain of the zone below.
8578 zones
->size
[z
].x0
[dim
] =
8579 comm
->zone_d1
[zones
->shift
[z
][dd
->dim
[d
-1]]].min1
;
8585 zones
->size
[z
].x0
[dim
] =
8586 zones
->size
[zone_perm
[2][z
-4]].x0
[dim
];
8590 zones
->size
[z
].x0
[dim
] =
8591 comm
->zone_d2
[zones
->shift
[z
][dd
->dim
[d
-2]]][zones
->shift
[z
][dd
->dim
[d
-1]]].min1
;
8594 /* A temporary limit, is updated below */
8595 zones
->size
[z
].x1
[dim
] = zones
->size
[z
].x0
[dim
];
8599 for (zi
= 0; zi
< zones
->nizone
; zi
++)
8601 if (zones
->shift
[zi
][dim
] == 0)
8603 /* This takes the whole zone into account.
8604 * With multiple pulses this will lead
8605 * to a larger zone then strictly necessary.
8607 zones
->size
[z
].x1
[dim
] = std::max(zones
->size
[z
].x1
[dim
],
8608 zones
->size
[zi
].x1
[dim
]+rcmbs
);
8616 /* Loop over the i-zones to set the upper limit of each
8619 for (zi
= 0; zi
< zones
->nizone
; zi
++)
8621 if (zones
->shift
[zi
][dim
] == 0)
8623 for (z
= zones
->izone
[zi
].j0
; z
< zones
->izone
[zi
].j1
; z
++)
8625 if (zones
->shift
[z
][dim
] > 0)
8627 zones
->size
[z
].x1
[dim
] = std::max(zones
->size
[z
].x1
[dim
],
8628 zones
->size
[zi
].x1
[dim
]+rcs
);
8635 for (z
= zone_start
; z
< zone_end
; z
++)
8637 /* Initialization only required to keep the compiler happy */
8638 rvec corner_min
= {0, 0, 0}, corner_max
= {0, 0, 0}, corner
;
8641 /* To determine the bounding box for a zone we need to find
8642 * the extreme corners of 4, 2 or 1 corners.
8644 nc
= 1 << (ddbox
->nboundeddim
- 1);
8646 for (c
= 0; c
< nc
; c
++)
8648 /* Set up a zone corner at x=0, ignoring trilinic couplings */
8652 corner
[YY
] = zones
->size
[z
].x0
[YY
];
8656 corner
[YY
] = zones
->size
[z
].x1
[YY
];
8660 corner
[ZZ
] = zones
->size
[z
].x0
[ZZ
];
8664 corner
[ZZ
] = zones
->size
[z
].x1
[ZZ
];
8666 if (dd
->ndim
== 1 && dd
->dim
[0] < ZZ
&& ZZ
< dd
->npbcdim
&&
8667 box
[ZZ
][1 - dd
->dim
[0]] != 0)
8669 /* With 1D domain decomposition the cg's are not in
8670 * the triclinic box, but triclinic x-y and rectangular y/x-z.
8671 * Shift the corner of the z-vector back to along the box
8672 * vector of dimension d, so it will later end up at 0 along d.
8673 * This can affect the location of this corner along dd->dim[0]
8674 * through the matrix operation below if box[d][dd->dim[0]]!=0.
8676 int d
= 1 - dd
->dim
[0];
8678 corner
[d
] -= corner
[ZZ
]*box
[ZZ
][d
]/box
[ZZ
][ZZ
];
8680 /* Apply the triclinic couplings */
8681 assert(ddbox
->npbcdim
<= DIM
);
8682 for (i
= YY
; i
< ddbox
->npbcdim
; i
++)
8684 for (j
= XX
; j
< i
; j
++)
8686 corner
[j
] += corner
[i
]*box
[i
][j
]/box
[i
][i
];
8691 copy_rvec(corner
, corner_min
);
8692 copy_rvec(corner
, corner_max
);
8696 for (i
= 0; i
< DIM
; i
++)
8698 corner_min
[i
] = std::min(corner_min
[i
], corner
[i
]);
8699 corner_max
[i
] = std::max(corner_max
[i
], corner
[i
]);
8703 /* Copy the extreme cornes without offset along x */
8704 for (i
= 0; i
< DIM
; i
++)
8706 zones
->size
[z
].bb_x0
[i
] = corner_min
[i
];
8707 zones
->size
[z
].bb_x1
[i
] = corner_max
[i
];
8709 /* Add the offset along x */
8710 zones
->size
[z
].bb_x0
[XX
] += zones
->size
[z
].x0
[XX
];
8711 zones
->size
[z
].bb_x1
[XX
] += zones
->size
[z
].x1
[XX
];
8714 if (zone_start
== 0)
8717 for (dim
= 0; dim
< DIM
; dim
++)
8719 vol
*= zones
->size
[0].x1
[dim
] - zones
->size
[0].x0
[dim
];
8721 zones
->dens_zone0
= (zones
->cg_range
[1] - zones
->cg_range
[0] - numMovedChargeGroupsInHomeZone
)/vol
;
8726 for (z
= zone_start
; z
< zone_end
; z
++)
8728 fprintf(debug
, "zone %d %6.3f - %6.3f %6.3f - %6.3f %6.3f - %6.3f\n",
8730 zones
->size
[z
].x0
[XX
], zones
->size
[z
].x1
[XX
],
8731 zones
->size
[z
].x0
[YY
], zones
->size
[z
].x1
[YY
],
8732 zones
->size
[z
].x0
[ZZ
], zones
->size
[z
].x1
[ZZ
]);
8733 fprintf(debug
, "zone %d bb %6.3f - %6.3f %6.3f - %6.3f %6.3f - %6.3f\n",
8735 zones
->size
[z
].bb_x0
[XX
], zones
->size
[z
].bb_x1
[XX
],
8736 zones
->size
[z
].bb_x0
[YY
], zones
->size
[z
].bb_x1
[YY
],
8737 zones
->size
[z
].bb_x0
[ZZ
], zones
->size
[z
].bb_x1
[ZZ
]);
8742 static int comp_cgsort(const void *a
, const void *b
)
8746 gmx_cgsort_t
*cga
, *cgb
;
8747 cga
= (gmx_cgsort_t
*)a
;
8748 cgb
= (gmx_cgsort_t
*)b
;
8750 comp
= cga
->nsc
- cgb
->nsc
;
8753 comp
= cga
->ind_gl
- cgb
->ind_gl
;
8759 static void order_int_cg(int n
, const gmx_cgsort_t
*sort
,
8764 /* Order the data */
8765 for (i
= 0; i
< n
; i
++)
8767 buf
[i
] = a
[sort
[i
].ind
];
8770 /* Copy back to the original array */
8771 for (i
= 0; i
< n
; i
++)
8777 static void order_vec_cg(int n
, const gmx_cgsort_t
*sort
,
8782 /* Order the data */
8783 for (i
= 0; i
< n
; i
++)
8785 copy_rvec(v
[sort
[i
].ind
], buf
[i
]);
8788 /* Copy back to the original array */
8789 for (i
= 0; i
< n
; i
++)
8791 copy_rvec(buf
[i
], v
[i
]);
8795 static void order_vec_atom(int ncg
, const int *cgindex
, const gmx_cgsort_t
*sort
,
8798 int a
, atot
, cg
, cg0
, cg1
, i
;
8800 if (cgindex
== nullptr)
8802 /* Avoid the useless loop of the atoms within a cg */
8803 order_vec_cg(ncg
, sort
, v
, buf
);
8808 /* Order the data */
8810 for (cg
= 0; cg
< ncg
; cg
++)
8812 cg0
= cgindex
[sort
[cg
].ind
];
8813 cg1
= cgindex
[sort
[cg
].ind
+1];
8814 for (i
= cg0
; i
< cg1
; i
++)
8816 copy_rvec(v
[i
], buf
[a
]);
8822 /* Copy back to the original array */
8823 for (a
= 0; a
< atot
; a
++)
8825 copy_rvec(buf
[a
], v
[a
]);
8829 static void ordered_sort(int nsort2
, gmx_cgsort_t
*sort2
,
8830 int nsort_new
, gmx_cgsort_t
*sort_new
,
8831 gmx_cgsort_t
*sort1
)
8835 /* The new indices are not very ordered, so we qsort them */
8836 gmx_qsort_threadsafe(sort_new
, nsort_new
, sizeof(sort_new
[0]), comp_cgsort
);
8838 /* sort2 is already ordered, so now we can merge the two arrays */
8842 while (i2
< nsort2
|| i_new
< nsort_new
)
8846 sort1
[i1
++] = sort_new
[i_new
++];
8848 else if (i_new
== nsort_new
)
8850 sort1
[i1
++] = sort2
[i2
++];
8852 else if (sort2
[i2
].nsc
< sort_new
[i_new
].nsc
||
8853 (sort2
[i2
].nsc
== sort_new
[i_new
].nsc
&&
8854 sort2
[i2
].ind_gl
< sort_new
[i_new
].ind_gl
))
8856 sort1
[i1
++] = sort2
[i2
++];
8860 sort1
[i1
++] = sort_new
[i_new
++];
8865 static int dd_sort_order(gmx_domdec_t
*dd
, t_forcerec
*fr
, int ncg_home_old
)
8867 gmx_domdec_sort_t
*sort
;
8868 gmx_cgsort_t
*cgsort
, *sort_i
;
8869 int ncg_new
, nsort2
, nsort_new
, i
, *a
, moved
;
8871 sort
= dd
->comm
->sort
;
8873 a
= fr
->ns
->grid
->cell_index
;
8875 moved
= NSGRID_SIGNAL_MOVED_FAC
*fr
->ns
->grid
->ncells
;
8877 if (ncg_home_old
>= 0)
8879 /* The charge groups that remained in the same ns grid cell
8880 * are completely ordered. So we can sort efficiently by sorting
8881 * the charge groups that did move into the stationary list.
8886 for (i
= 0; i
< dd
->ncg_home
; i
++)
8888 /* Check if this cg did not move to another node */
8891 if (i
>= ncg_home_old
|| a
[i
] != sort
->sort
[i
].nsc
)
8893 /* This cg is new on this node or moved ns grid cell */
8894 if (nsort_new
>= sort
->sort_new_nalloc
)
8896 sort
->sort_new_nalloc
= over_alloc_dd(nsort_new
+1);
8897 srenew(sort
->sort_new
, sort
->sort_new_nalloc
);
8899 sort_i
= &(sort
->sort_new
[nsort_new
++]);
8903 /* This cg did not move */
8904 sort_i
= &(sort
->sort2
[nsort2
++]);
8906 /* Sort on the ns grid cell indices
8907 * and the global topology index.
8908 * index_gl is irrelevant with cell ns,
8909 * but we set it here anyhow to avoid a conditional.
8912 sort_i
->ind_gl
= dd
->index_gl
[i
];
8919 fprintf(debug
, "ordered sort cgs: stationary %d moved %d\n",
8922 /* Sort efficiently */
8923 ordered_sort(nsort2
, sort
->sort2
, nsort_new
, sort
->sort_new
,
8928 cgsort
= sort
->sort
;
8930 for (i
= 0; i
< dd
->ncg_home
; i
++)
8932 /* Sort on the ns grid cell indices
8933 * and the global topology index
8935 cgsort
[i
].nsc
= a
[i
];
8936 cgsort
[i
].ind_gl
= dd
->index_gl
[i
];
8938 if (cgsort
[i
].nsc
< moved
)
8945 fprintf(debug
, "qsort cgs: %d new home %d\n", dd
->ncg_home
, ncg_new
);
8947 /* Determine the order of the charge groups using qsort */
8948 gmx_qsort_threadsafe(cgsort
, dd
->ncg_home
, sizeof(cgsort
[0]), comp_cgsort
);
8954 static int dd_sort_order_nbnxn(gmx_domdec_t
*dd
, t_forcerec
*fr
)
8960 sort
= dd
->comm
->sort
->sort
;
8962 nbnxn_get_atomorder(fr
->nbv
->nbs
, &a
, &na
);
8965 for (i
= 0; i
< na
; i
++)
8969 sort
[ncg_new
].ind
= a
[i
];
8977 static void dd_sort_state(gmx_domdec_t
*dd
, rvec
*cgcm
, t_forcerec
*fr
, t_state
*state
,
8980 gmx_domdec_sort_t
*sort
;
8981 gmx_cgsort_t
*cgsort
;
8983 int ncg_new
, i
, *ibuf
, cgsize
;
8986 sort
= dd
->comm
->sort
;
8988 if (dd
->ncg_home
> sort
->sort_nalloc
)
8990 sort
->sort_nalloc
= over_alloc_dd(dd
->ncg_home
);
8991 srenew(sort
->sort
, sort
->sort_nalloc
);
8992 srenew(sort
->sort2
, sort
->sort_nalloc
);
8994 cgsort
= sort
->sort
;
8996 switch (fr
->cutoff_scheme
)
8999 ncg_new
= dd_sort_order(dd
, fr
, ncg_home_old
);
9002 ncg_new
= dd_sort_order_nbnxn(dd
, fr
);
9005 gmx_incons("unimplemented");
9009 /* We alloc with the old size, since cgindex is still old */
9010 vec_rvec_check_alloc(&dd
->comm
->vbuf
, dd
->cgindex
[dd
->ncg_home
]);
9011 vbuf
= dd
->comm
->vbuf
.v
;
9015 cgindex
= dd
->cgindex
;
9022 /* Remove the charge groups which are no longer at home here */
9023 dd
->ncg_home
= ncg_new
;
9026 fprintf(debug
, "Set the new home charge group count to %d\n",
9030 /* Reorder the state */
9031 if (state
->flags
& (1 << estX
))
9033 order_vec_atom(dd
->ncg_home
, cgindex
, cgsort
, as_rvec_array(state
->x
.data()), vbuf
);
9035 if (state
->flags
& (1 << estV
))
9037 order_vec_atom(dd
->ncg_home
, cgindex
, cgsort
, as_rvec_array(state
->v
.data()), vbuf
);
9039 if (state
->flags
& (1 << estCGP
))
9041 order_vec_atom(dd
->ncg_home
, cgindex
, cgsort
, as_rvec_array(state
->cg_p
.data()), vbuf
);
9044 if (fr
->cutoff_scheme
== ecutsGROUP
)
9047 order_vec_cg(dd
->ncg_home
, cgsort
, cgcm
, vbuf
);
9050 if (dd
->ncg_home
+1 > sort
->ibuf_nalloc
)
9052 sort
->ibuf_nalloc
= over_alloc_dd(dd
->ncg_home
+1);
9053 srenew(sort
->ibuf
, sort
->ibuf_nalloc
);
9056 /* Reorder the global cg index */
9057 order_int_cg(dd
->ncg_home
, cgsort
, dd
->index_gl
, ibuf
);
9058 /* Reorder the cginfo */
9059 order_int_cg(dd
->ncg_home
, cgsort
, fr
->cginfo
, ibuf
);
9060 /* Rebuild the local cg index */
9064 for (i
= 0; i
< dd
->ncg_home
; i
++)
9066 cgsize
= dd
->cgindex
[cgsort
[i
].ind
+1] - dd
->cgindex
[cgsort
[i
].ind
];
9067 ibuf
[i
+1] = ibuf
[i
] + cgsize
;
9069 for (i
= 0; i
< dd
->ncg_home
+1; i
++)
9071 dd
->cgindex
[i
] = ibuf
[i
];
9076 for (i
= 0; i
< dd
->ncg_home
+1; i
++)
9081 /* Set the home atom number */
9082 dd
->nat_home
= dd
->cgindex
[dd
->ncg_home
];
9084 if (fr
->cutoff_scheme
== ecutsVERLET
)
9086 /* The atoms are now exactly in grid order, update the grid order */
9087 nbnxn_set_atomorder(fr
->nbv
->nbs
);
9091 /* Copy the sorted ns cell indices back to the ns grid struct */
9092 for (i
= 0; i
< dd
->ncg_home
; i
++)
9094 fr
->ns
->grid
->cell_index
[i
] = cgsort
[i
].nsc
;
9096 fr
->ns
->grid
->nr
= dd
->ncg_home
;
9100 static void add_dd_statistics(gmx_domdec_t
*dd
)
9102 gmx_domdec_comm_t
*comm
;
9107 for (ddnat
= ddnatZONE
; ddnat
< ddnatNR
; ddnat
++)
9109 comm
->sum_nat
[ddnat
-ddnatZONE
] +=
9110 comm
->nat
[ddnat
] - comm
->nat
[ddnat
-1];
9115 void reset_dd_statistics_counters(gmx_domdec_t
*dd
)
9117 gmx_domdec_comm_t
*comm
;
9122 /* Reset all the statistics and counters for total run counting */
9123 for (ddnat
= ddnatZONE
; ddnat
< ddnatNR
; ddnat
++)
9125 comm
->sum_nat
[ddnat
-ddnatZONE
] = 0;
9129 comm
->load_step
= 0;
9132 clear_ivec(comm
->load_lim
);
9137 void print_dd_statistics(const t_commrec
*cr
, const t_inputrec
*ir
, FILE *fplog
)
9139 gmx_domdec_comm_t
*comm
;
9143 comm
= cr
->dd
->comm
;
9145 gmx_sumd(ddnatNR
-ddnatZONE
, comm
->sum_nat
, cr
);
9147 if (fplog
== nullptr)
9152 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");
9154 for (ddnat
= ddnatZONE
; ddnat
< ddnatNR
; ddnat
++)
9156 av
= comm
->sum_nat
[ddnat
-ddnatZONE
]/comm
->ndecomp
;
9161 " av. #atoms communicated per step for force: %d x %.1f\n",
9165 if (cr
->dd
->vsite_comm
)
9168 " av. #atoms communicated per step for vsites: %d x %.1f\n",
9169 (EEL_PME(ir
->coulombtype
) || ir
->coulombtype
== eelEWALD
) ? 3 : 2,
9174 if (cr
->dd
->constraint_comm
)
9177 " av. #atoms communicated per step for LINCS: %d x %.1f\n",
9178 1 + ir
->nLincsIter
, av
);
9182 gmx_incons(" Unknown type for DD statistics");
9185 fprintf(fplog
, "\n");
9187 if (comm
->bRecordLoad
&& EI_DYNAMICS(ir
->eI
))
9189 print_dd_load_av(fplog
, cr
->dd
);
9193 void dd_partition_system(FILE *fplog
,
9195 const t_commrec
*cr
,
9196 gmx_bool bMasterState
,
9198 t_state
*state_global
,
9199 const gmx_mtop_t
*top_global
,
9200 const t_inputrec
*ir
,
9201 t_state
*state_local
,
9202 PaddedRVecVector
*f
,
9203 gmx::MDAtoms
*mdAtoms
,
9204 gmx_localtop_t
*top_local
,
9207 gmx_constr_t constr
,
9209 gmx_wallcycle
*wcycle
,
9213 gmx_domdec_comm_t
*comm
;
9214 gmx_ddbox_t ddbox
= {0};
9216 gmx_int64_t step_pcoupl
;
9217 rvec cell_ns_x0
, cell_ns_x1
;
9218 int i
, n
, ncgindex_set
, ncg_home_old
= -1, ncg_moved
, nat_f_novirsum
;
9219 gmx_bool bBoxChanged
, bNStGlobalComm
, bDoDLB
, bCheckWhetherToTurnDlbOn
, bLogLoad
;
9220 gmx_bool bRedist
, bSortCG
, bResortAll
;
9221 ivec ncells_old
= {0, 0, 0}, ncells_new
= {0, 0, 0}, np
;
9225 wallcycle_start(wcycle
, ewcDOMDEC
);
9230 bBoxChanged
= (bMasterState
|| inputrecDeform(ir
));
9231 if (ir
->epc
!= epcNO
)
9233 /* With nstpcouple > 1 pressure coupling happens.
9234 * one step after calculating the pressure.
9235 * Box scaling happens at the end of the MD step,
9236 * after the DD partitioning.
9237 * We therefore have to do DLB in the first partitioning
9238 * after an MD step where P-coupling occurred.
9239 * We need to determine the last step in which p-coupling occurred.
9240 * MRS -- need to validate this for vv?
9245 step_pcoupl
= step
- 1;
9249 step_pcoupl
= ((step
- 1)/n
)*n
+ 1;
9251 if (step_pcoupl
>= comm
->partition_step
)
9257 bNStGlobalComm
= (step
% nstglobalcomm
== 0);
9265 /* Should we do dynamic load balacing this step?
9266 * Since it requires (possibly expensive) global communication,
9267 * we might want to do DLB less frequently.
9269 if (bBoxChanged
|| ir
->epc
!= epcNO
)
9271 bDoDLB
= bBoxChanged
;
9275 bDoDLB
= bNStGlobalComm
;
9279 /* Check if we have recorded loads on the nodes */
9280 if (comm
->bRecordLoad
&& dd_load_count(comm
) > 0)
9282 bCheckWhetherToTurnDlbOn
= dd_dlb_get_should_check_whether_to_turn_dlb_on(dd
);
9284 /* Print load every nstlog, first and last step to the log file */
9285 bLogLoad
= ((ir
->nstlog
> 0 && step
% ir
->nstlog
== 0) ||
9286 comm
->n_load_collect
== 0 ||
9288 (step
+ ir
->nstlist
> ir
->init_step
+ ir
->nsteps
)));
9290 /* Avoid extra communication due to verbose screen output
9291 * when nstglobalcomm is set.
9293 if (bDoDLB
|| bLogLoad
|| bCheckWhetherToTurnDlbOn
||
9294 (bVerbose
&& (ir
->nstlist
== 0 || nstglobalcomm
<= ir
->nstlist
)))
9296 get_load_distribution(dd
, wcycle
);
9301 dd_print_load(fplog
, dd
, step
-1);
9305 dd_print_load_verbose(dd
);
9308 comm
->n_load_collect
++;
9314 /* Add the measured cycles to the running average */
9315 const float averageFactor
= 0.1f
;
9316 comm
->cyclesPerStepDlbExpAverage
=
9317 (1 - averageFactor
)*comm
->cyclesPerStepDlbExpAverage
+
9318 averageFactor
*comm
->cycl
[ddCyclStep
]/comm
->cycl_n
[ddCyclStep
];
9320 if (comm
->dlbState
== edlbsOnCanTurnOff
&&
9321 dd
->comm
->n_load_have
% c_checkTurnDlbOffInterval
== c_checkTurnDlbOffInterval
- 1)
9323 gmx_bool turnOffDlb
;
9326 /* If the running averaged cycles with DLB are more
9327 * than before we turned on DLB, turn off DLB.
9328 * We will again run and check the cycles without DLB
9329 * and we can then decide if to turn off DLB forever.
9331 turnOffDlb
= (comm
->cyclesPerStepDlbExpAverage
>
9332 comm
->cyclesPerStepBeforeDLB
);
9334 dd_bcast(dd
, sizeof(turnOffDlb
), &turnOffDlb
);
9337 /* To turn off DLB, we need to redistribute the atoms */
9338 dd_collect_state(dd
, state_local
, state_global
);
9339 bMasterState
= TRUE
;
9340 turn_off_dlb(fplog
, cr
, step
);
9344 else if (bCheckWhetherToTurnDlbOn
)
9346 gmx_bool turnOffDlbForever
= FALSE
;
9347 gmx_bool turnOnDlb
= FALSE
;
9349 /* Since the timings are node dependent, the master decides */
9352 /* If we recently turned off DLB, we want to check if
9353 * performance is better without DLB. We want to do this
9354 * ASAP to minimize the chance that external factors
9355 * slowed down the DLB step are gone here and we
9356 * incorrectly conclude that DLB was causing the slowdown.
9357 * So we measure one nstlist block, no running average.
9359 if (comm
->haveTurnedOffDlb
&&
9360 comm
->cycl
[ddCyclStep
]/comm
->cycl_n
[ddCyclStep
] <
9361 comm
->cyclesPerStepDlbExpAverage
)
9363 /* After turning off DLB we ran nstlist steps in fewer
9364 * cycles than with DLB. This likely means that DLB
9365 * in not benefical, but this could be due to a one
9366 * time unlucky fluctuation, so we require two such
9367 * observations in close succession to turn off DLB
9370 if (comm
->dlbSlowerPartitioningCount
> 0 &&
9371 dd
->ddp_count
< comm
->dlbSlowerPartitioningCount
+ 10*c_checkTurnDlbOnInterval
)
9373 turnOffDlbForever
= TRUE
;
9375 comm
->haveTurnedOffDlb
= false;
9376 /* Register when we last measured DLB slowdown */
9377 comm
->dlbSlowerPartitioningCount
= dd
->ddp_count
;
9381 /* Here we check if the max PME rank load is more than 0.98
9382 * the max PP force load. If so, PP DLB will not help,
9383 * since we are (almost) limited by PME. Furthermore,
9384 * DLB will cause a significant extra x/f redistribution
9385 * cost on the PME ranks, which will then surely result
9386 * in lower total performance.
9388 if (cr
->npmenodes
> 0 &&
9389 dd_pme_f_ratio(dd
) > 1 - DD_PERF_LOSS_DLB_ON
)
9395 turnOnDlb
= (dd_force_imb_perf_loss(dd
) >= DD_PERF_LOSS_DLB_ON
);
9401 gmx_bool turnOffDlbForever
;
9405 turnOffDlbForever
, turnOnDlb
9407 dd_bcast(dd
, sizeof(bools
), &bools
);
9408 if (bools
.turnOffDlbForever
)
9410 turn_off_dlb_forever(fplog
, cr
, step
);
9412 else if (bools
.turnOnDlb
)
9414 turn_on_dlb(fplog
, cr
, step
);
9419 comm
->n_load_have
++;
9422 cgs_gl
= &comm
->cgs_gl
;
9427 /* Clear the old state */
9428 clear_dd_indices(dd
, 0, 0);
9431 rvec
*xGlobal
= (SIMMASTER(cr
) ? as_rvec_array(state_global
->x
.data()) : nullptr);
9433 set_ddbox(dd
, bMasterState
, cr
, ir
,
9434 SIMMASTER(cr
) ? state_global
->box
: nullptr,
9435 TRUE
, cgs_gl
, xGlobal
,
9438 get_cg_distribution(fplog
, dd
, cgs_gl
,
9439 SIMMASTER(cr
) ? state_global
->box
: nullptr,
9442 dd_distribute_state(dd
, cgs_gl
,
9443 state_global
, state_local
, f
);
9445 dd_make_local_cgs(dd
, &top_local
->cgs
);
9447 /* Ensure that we have space for the new distribution */
9448 dd_check_alloc_ncg(fr
, state_local
, f
, dd
->ncg_home
);
9450 if (fr
->cutoff_scheme
== ecutsGROUP
)
9452 calc_cgcm(fplog
, 0, dd
->ncg_home
,
9453 &top_local
->cgs
, as_rvec_array(state_local
->x
.data()), fr
->cg_cm
);
9456 inc_nrnb(nrnb
, eNR_CGCM
, dd
->nat_home
);
9458 dd_set_cginfo(dd
->index_gl
, 0, dd
->ncg_home
, fr
, comm
->bLocalCG
);
9460 else if (state_local
->ddp_count
!= dd
->ddp_count
)
9462 if (state_local
->ddp_count
> dd
->ddp_count
)
9464 gmx_fatal(FARGS
, "Internal inconsistency state_local->ddp_count (%d) > dd->ddp_count (%d)", state_local
->ddp_count
, dd
->ddp_count
);
9467 if (state_local
->ddp_count_cg_gl
!= state_local
->ddp_count
)
9469 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
);
9472 /* Clear the old state */
9473 clear_dd_indices(dd
, 0, 0);
9475 /* Build the new indices */
9476 rebuild_cgindex(dd
, cgs_gl
->index
, state_local
);
9477 make_dd_indices(dd
, cgs_gl
->index
, 0);
9478 ncgindex_set
= dd
->ncg_home
;
9480 if (fr
->cutoff_scheme
== ecutsGROUP
)
9482 /* Redetermine the cg COMs */
9483 calc_cgcm(fplog
, 0, dd
->ncg_home
,
9484 &top_local
->cgs
, as_rvec_array(state_local
->x
.data()), fr
->cg_cm
);
9487 inc_nrnb(nrnb
, eNR_CGCM
, dd
->nat_home
);
9489 dd_set_cginfo(dd
->index_gl
, 0, dd
->ncg_home
, fr
, comm
->bLocalCG
);
9491 set_ddbox(dd
, bMasterState
, cr
, ir
, state_local
->box
,
9492 TRUE
, &top_local
->cgs
, as_rvec_array(state_local
->x
.data()), &ddbox
);
9494 bRedist
= isDlbOn(comm
);
9498 /* We have the full state, only redistribute the cgs */
9500 /* Clear the non-home indices */
9501 clear_dd_indices(dd
, dd
->ncg_home
, dd
->nat_home
);
9504 /* Avoid global communication for dim's without pbc and -gcom */
9505 if (!bNStGlobalComm
)
9507 copy_rvec(comm
->box0
, ddbox
.box0
);
9508 copy_rvec(comm
->box_size
, ddbox
.box_size
);
9510 set_ddbox(dd
, bMasterState
, cr
, ir
, state_local
->box
,
9511 bNStGlobalComm
, &top_local
->cgs
, as_rvec_array(state_local
->x
.data()), &ddbox
);
9516 /* For dim's without pbc and -gcom */
9517 copy_rvec(ddbox
.box0
, comm
->box0
);
9518 copy_rvec(ddbox
.box_size
, comm
->box_size
);
9520 set_dd_cell_sizes(dd
, &ddbox
, dynamic_dd_box(&ddbox
, ir
), bMasterState
, bDoDLB
,
9523 if (comm
->nstDDDumpGrid
> 0 && step
% comm
->nstDDDumpGrid
== 0)
9525 write_dd_grid_pdb("dd_grid", step
, dd
, state_local
->box
, &ddbox
);
9528 /* Check if we should sort the charge groups */
9529 bSortCG
= (bMasterState
|| bRedist
);
9531 ncg_home_old
= dd
->ncg_home
;
9533 /* When repartitioning we mark charge groups that will move to neighboring
9534 * DD cells, but we do not move them right away for performance reasons.
9535 * Thus we need to keep track of how many charge groups will move for
9536 * obtaining correct local charge group / atom counts.
9541 wallcycle_sub_start(wcycle
, ewcsDD_REDIST
);
9543 dd_redistribute_cg(fplog
, step
, dd
, ddbox
.tric_dir
,
9545 !bSortCG
, nrnb
, &ncgindex_set
, &ncg_moved
);
9547 wallcycle_sub_stop(wcycle
, ewcsDD_REDIST
);
9550 get_nsgrid_boundaries(ddbox
.nboundeddim
, state_local
->box
,
9552 &comm
->cell_x0
, &comm
->cell_x1
,
9553 dd
->ncg_home
, fr
->cg_cm
,
9554 cell_ns_x0
, cell_ns_x1
, &grid_density
);
9558 comm_dd_ns_cell_sizes(dd
, &ddbox
, cell_ns_x0
, cell_ns_x1
, step
);
9561 switch (fr
->cutoff_scheme
)
9564 copy_ivec(fr
->ns
->grid
->n
, ncells_old
);
9565 grid_first(fplog
, fr
->ns
->grid
, dd
, &ddbox
,
9566 state_local
->box
, cell_ns_x0
, cell_ns_x1
,
9567 fr
->rlist
, grid_density
);
9570 nbnxn_get_ncells(fr
->nbv
->nbs
, &ncells_old
[XX
], &ncells_old
[YY
]);
9573 gmx_incons("unimplemented");
9575 /* We need to store tric_dir for dd_get_ns_ranges called from ns.c */
9576 copy_ivec(ddbox
.tric_dir
, comm
->tric_dir
);
9580 wallcycle_sub_start(wcycle
, ewcsDD_GRID
);
9582 /* Sort the state on charge group position.
9583 * This enables exact restarts from this step.
9584 * It also improves performance by about 15% with larger numbers
9585 * of atoms per node.
9588 /* Fill the ns grid with the home cell,
9589 * so we can sort with the indices.
9591 set_zones_ncg_home(dd
);
9593 switch (fr
->cutoff_scheme
)
9596 set_zones_size(dd
, state_local
->box
, &ddbox
, 0, 1, ncg_moved
);
9598 nbnxn_put_on_grid(fr
->nbv
->nbs
, fr
->ePBC
, state_local
->box
,
9600 comm
->zones
.size
[0].bb_x0
,
9601 comm
->zones
.size
[0].bb_x1
,
9603 comm
->zones
.dens_zone0
,
9605 as_rvec_array(state_local
->x
.data()),
9606 ncg_moved
, bRedist
? comm
->moved
: nullptr,
9607 fr
->nbv
->grp
[eintLocal
].kernel_type
,
9610 nbnxn_get_ncells(fr
->nbv
->nbs
, &ncells_new
[XX
], &ncells_new
[YY
]);
9613 fill_grid(&comm
->zones
, fr
->ns
->grid
, dd
->ncg_home
,
9614 0, dd
->ncg_home
, fr
->cg_cm
);
9616 copy_ivec(fr
->ns
->grid
->n
, ncells_new
);
9619 gmx_incons("unimplemented");
9622 bResortAll
= bMasterState
;
9624 /* Check if we can user the old order and ns grid cell indices
9625 * of the charge groups to sort the charge groups efficiently.
9627 if (ncells_new
[XX
] != ncells_old
[XX
] ||
9628 ncells_new
[YY
] != ncells_old
[YY
] ||
9629 ncells_new
[ZZ
] != ncells_old
[ZZ
])
9636 fprintf(debug
, "Step %s, sorting the %d home charge groups\n",
9637 gmx_step_str(step
, sbuf
), dd
->ncg_home
);
9639 dd_sort_state(dd
, fr
->cg_cm
, fr
, state_local
,
9640 bResortAll
? -1 : ncg_home_old
);
9642 /* After sorting and compacting we set the correct size */
9643 dd_resize_state(state_local
, f
, dd
->nat_home
);
9645 /* Rebuild all the indices */
9646 ga2la_clear(dd
->ga2la
);
9649 wallcycle_sub_stop(wcycle
, ewcsDD_GRID
);
9652 wallcycle_sub_start(wcycle
, ewcsDD_SETUPCOMM
);
9654 /* Setup up the communication and communicate the coordinates */
9655 setup_dd_communication(dd
, state_local
->box
, &ddbox
, fr
, state_local
, f
);
9657 /* Set the indices */
9658 make_dd_indices(dd
, cgs_gl
->index
, ncgindex_set
);
9660 /* Set the charge group boundaries for neighbor searching */
9661 set_cg_boundaries(&comm
->zones
);
9663 if (fr
->cutoff_scheme
== ecutsVERLET
)
9665 set_zones_size(dd
, state_local
->box
, &ddbox
,
9666 bSortCG
? 1 : 0, comm
->zones
.n
,
9670 wallcycle_sub_stop(wcycle
, ewcsDD_SETUPCOMM
);
9673 write_dd_pdb("dd_home",step,"dump",top_global,cr,
9674 -1,as_rvec_array(state_local->x.data()),state_local->box);
9677 wallcycle_sub_start(wcycle
, ewcsDD_MAKETOP
);
9679 /* Extract a local topology from the global topology */
9680 for (i
= 0; i
< dd
->ndim
; i
++)
9682 np
[dd
->dim
[i
]] = comm
->cd
[i
].np
;
9684 dd_make_local_top(dd
, &comm
->zones
, dd
->npbcdim
, state_local
->box
,
9685 comm
->cellsize_min
, np
,
9687 fr
->cutoff_scheme
== ecutsGROUP
? fr
->cg_cm
: as_rvec_array(state_local
->x
.data()),
9688 vsite
, top_global
, top_local
);
9690 wallcycle_sub_stop(wcycle
, ewcsDD_MAKETOP
);
9692 wallcycle_sub_start(wcycle
, ewcsDD_MAKECONSTR
);
9694 /* Set up the special atom communication */
9695 n
= comm
->nat
[ddnatZONE
];
9696 for (i
= ddnatZONE
+1; i
< ddnatNR
; i
++)
9701 if (vsite
&& vsite
->n_intercg_vsite
)
9703 n
= dd_make_local_vsites(dd
, n
, top_local
->idef
.il
);
9707 if (dd
->bInterCGcons
|| dd
->bInterCGsettles
)
9709 /* Only for inter-cg constraints we need special code */
9710 n
= dd_make_local_constraints(dd
, n
, top_global
, fr
->cginfo
,
9711 constr
, ir
->nProjOrder
,
9712 top_local
->idef
.il
);
9716 gmx_incons("Unknown special atom type setup");
9721 wallcycle_sub_stop(wcycle
, ewcsDD_MAKECONSTR
);
9723 wallcycle_sub_start(wcycle
, ewcsDD_TOPOTHER
);
9725 /* Make space for the extra coordinates for virtual site
9726 * or constraint communication.
9728 state_local
->natoms
= comm
->nat
[ddnatNR
-1];
9730 dd_resize_state(state_local
, f
, state_local
->natoms
);
9732 if (fr
->haveDirectVirialContributions
)
9734 if (vsite
&& vsite
->n_intercg_vsite
)
9736 nat_f_novirsum
= comm
->nat
[ddnatVSITE
];
9740 if (EEL_FULL(ir
->coulombtype
) && dd
->n_intercg_excl
> 0)
9742 nat_f_novirsum
= dd
->nat_tot
;
9746 nat_f_novirsum
= dd
->nat_home
;
9755 /* Set the number of atoms required for the force calculation.
9756 * Forces need to be constrained when doing energy
9757 * minimization. For simple simulations we could avoid some
9758 * allocation, zeroing and copying, but this is probably not worth
9759 * the complications and checking.
9761 forcerec_set_ranges(fr
, dd
->ncg_home
, dd
->ncg_tot
,
9762 dd
->nat_tot
, comm
->nat
[ddnatCON
], nat_f_novirsum
);
9764 /* Update atom data for mdatoms and several algorithms */
9765 mdAlgorithmsSetupAtomData(cr
, ir
, top_global
, top_local
, fr
,
9766 nullptr, mdAtoms
, vsite
, nullptr);
9768 auto mdatoms
= mdAtoms
->mdatoms();
9769 if (!thisRankHasDuty(cr
, DUTY_PME
))
9771 /* Send the charges and/or c6/sigmas to our PME only node */
9772 gmx_pme_send_parameters(cr
,
9774 mdatoms
->nChargePerturbed
, mdatoms
->nTypePerturbed
,
9775 mdatoms
->chargeA
, mdatoms
->chargeB
,
9776 mdatoms
->sqrt_c6A
, mdatoms
->sqrt_c6B
,
9777 mdatoms
->sigmaA
, mdatoms
->sigmaB
,
9778 dd_pme_maxshift_x(dd
), dd_pme_maxshift_y(dd
));
9783 set_constraints(constr
, top_local
, ir
, mdatoms
, cr
);
9788 /* Update the local pull groups */
9789 dd_make_local_pull_groups(cr
, ir
->pull_work
, mdatoms
);
9794 /* Update the local rotation groups */
9795 dd_make_local_rotation_groups(dd
, ir
->rot
);
9798 if (ir
->eSwapCoords
!= eswapNO
)
9800 /* Update the local groups needed for ion swapping */
9801 dd_make_local_swap_groups(dd
, ir
->swap
);
9804 /* Update the local atoms to be communicated via the IMD protocol if bIMD is TRUE. */
9805 dd_make_local_IMD_atoms(ir
->bIMD
, dd
, ir
->imd
);
9807 add_dd_statistics(dd
);
9809 /* Make sure we only count the cycles for this DD partitioning */
9810 clear_dd_cycle_counts(dd
);
9812 /* Because the order of the atoms might have changed since
9813 * the last vsite construction, we need to communicate the constructing
9814 * atom coordinates again (for spreading the forces this MD step).
9816 dd_move_x_vsites(dd
, state_local
->box
, as_rvec_array(state_local
->x
.data()));
9818 wallcycle_sub_stop(wcycle
, ewcsDD_TOPOTHER
);
9820 if (comm
->nstDDDump
> 0 && step
% comm
->nstDDDump
== 0)
9822 dd_move_x(dd
, state_local
->box
, as_rvec_array(state_local
->x
.data()), nullWallcycle
);
9823 write_dd_pdb("dd_dump", step
, "dump", top_global
, cr
,
9824 -1, as_rvec_array(state_local
->x
.data()), state_local
->box
);
9827 /* Store the partitioning step */
9828 comm
->partition_step
= step
;
9830 /* Increase the DD partitioning counter */
9832 /* The state currently matches this DD partitioning count, store it */
9833 state_local
->ddp_count
= dd
->ddp_count
;
9836 /* The DD master node knows the complete cg distribution,
9837 * store the count so we can possibly skip the cg info communication.
9839 comm
->master_cg_ddp_count
= (bSortCG
? 0 : dd
->ddp_count
);
9842 if (comm
->DD_debug
> 0)
9844 /* Set the env var GMX_DD_DEBUG if you suspect corrupted indices */
9845 check_index_consistency(dd
, top_global
->natoms
, ncg_mtop(top_global
),
9846 "after partitioning");
9849 wallcycle_stop(wcycle
, ewcDOMDEC
);