2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 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.
37 * \brief Implements atom distribution functions.
39 * \author Berk Hess <hess@kth.se>
40 * \ingroup module_domdec
45 #include "distribute.h"
51 #include "gromacs/domdec/domdec_network.h"
52 #include "gromacs/math/vec.h"
53 #include "gromacs/mdtypes/commrec.h"
54 #include "gromacs/mdtypes/df_history.h"
55 #include "gromacs/mdtypes/state.h"
56 #include "gromacs/utility/fatalerror.h"
57 #include "gromacs/utility/smalloc.h"
59 #include "atomdistribution.h"
60 #include "cellsizes.h"
61 #include "domdec_internal.h"
64 static void dd_distribute_vec_sendrecv(gmx_domdec_t
*dd
, const t_block
*cgs
,
65 const rvec
*v
, rvec
*lv
)
75 for (int rank
= 0; rank
< dd
->nnodes
; rank
++)
79 const auto &domainGroups
= ma
->domainGroups
[rank
];
81 if (domainGroups
.numAtoms
> nalloc
)
83 nalloc
= over_alloc_dd(domainGroups
.numAtoms
);
86 /* Use lv as a temporary buffer */
88 for (const int &cg
: domainGroups
.atomGroups
)
90 for (int globalAtom
= cgs
->index
[cg
]; globalAtom
< cgs
->index
[cg
+ 1]; globalAtom
++)
92 copy_rvec(v
[globalAtom
], buf
[localAtom
++]);
95 GMX_RELEASE_ASSERT(localAtom
== domainGroups
.numAtoms
, "The index count and number of indices should match");
98 MPI_Send(buf
, domainGroups
.numAtoms
*sizeof(rvec
), MPI_BYTE
,
99 rank
, rank
, dd
->mpi_comm_all
);
105 const auto &domainGroups
= ma
->domainGroups
[dd
->masterrank
];
107 for (const int &cg
: domainGroups
.atomGroups
)
109 for (int globalAtom
= cgs
->index
[cg
]; globalAtom
< cgs
->index
[cg
+ 1]; globalAtom
++)
111 copy_rvec(v
[globalAtom
], lv
[localAtom
++]);
118 MPI_Recv(lv
, dd
->nat_home
*sizeof(rvec
), MPI_BYTE
, dd
->masterrank
,
119 MPI_ANY_TAG
, dd
->mpi_comm_all
, MPI_STATUS_IGNORE
);
124 static void dd_distribute_vec_scatterv(gmx_domdec_t
*dd
, const t_block
*cgs
,
125 const rvec
*v
, rvec
*lv
)
127 int *sendCounts
= nullptr;
128 int *displacements
= nullptr;
132 AtomDistribution
*ma
= dd
->ma
;
134 get_commbuffer_counts(ma
, &sendCounts
, &displacements
);
136 gmx::ArrayRef
<gmx::RVec
> buffer
= ma
->rvecBuffer
;
138 for (int rank
= 0; rank
< dd
->nnodes
; rank
++)
140 const auto &domainGroups
= ma
->domainGroups
[rank
];
141 for (const int &cg
: domainGroups
.atomGroups
)
143 for (int globalAtom
= cgs
->index
[cg
]; globalAtom
< cgs
->index
[cg
+ 1]; globalAtom
++)
145 copy_rvec(v
[globalAtom
], buffer
[localAtom
++]);
151 dd_scatterv(dd
, sendCounts
, displacements
,
152 DDMASTER(dd
) ? dd
->ma
->rvecBuffer
.data() : nullptr,
153 dd
->nat_home
*sizeof(rvec
), lv
);
156 static void dd_distribute_vec(gmx_domdec_t
*dd
, const t_block
*cgs
,
157 const rvec
*v
, rvec
*lv
)
159 if (dd
->nnodes
<= c_maxNumRanksUseSendRecvForScatterAndGather
)
161 dd_distribute_vec_sendrecv(dd
, cgs
, v
, lv
);
165 dd_distribute_vec_scatterv(dd
, cgs
, v
, lv
);
169 static void dd_distribute_dfhist(gmx_domdec_t
*dd
, df_history_t
*dfhist
)
171 if (dfhist
== nullptr)
176 dd_bcast(dd
, sizeof(int), &dfhist
->bEquil
);
177 dd_bcast(dd
, sizeof(int), &dfhist
->nlambda
);
178 dd_bcast(dd
, sizeof(real
), &dfhist
->wl_delta
);
180 if (dfhist
->nlambda
> 0)
182 int nlam
= dfhist
->nlambda
;
183 dd_bcast(dd
, sizeof(int)*nlam
, dfhist
->n_at_lam
);
184 dd_bcast(dd
, sizeof(real
)*nlam
, dfhist
->wl_histo
);
185 dd_bcast(dd
, sizeof(real
)*nlam
, dfhist
->sum_weights
);
186 dd_bcast(dd
, sizeof(real
)*nlam
, dfhist
->sum_dg
);
187 dd_bcast(dd
, sizeof(real
)*nlam
, dfhist
->sum_minvar
);
188 dd_bcast(dd
, sizeof(real
)*nlam
, dfhist
->sum_variance
);
190 for (int i
= 0; i
< nlam
; i
++)
192 dd_bcast(dd
, sizeof(real
)*nlam
, dfhist
->accum_p
[i
]);
193 dd_bcast(dd
, sizeof(real
)*nlam
, dfhist
->accum_m
[i
]);
194 dd_bcast(dd
, sizeof(real
)*nlam
, dfhist
->accum_p2
[i
]);
195 dd_bcast(dd
, sizeof(real
)*nlam
, dfhist
->accum_m2
[i
]);
196 dd_bcast(dd
, sizeof(real
)*nlam
, dfhist
->Tij
[i
]);
197 dd_bcast(dd
, sizeof(real
)*nlam
, dfhist
->Tij_empirical
[i
]);
202 static void dd_distribute_state(gmx_domdec_t
*dd
, const t_block
*cgs
,
203 const t_state
*state
, t_state
*state_local
,
206 int nh
= state_local
->nhchainlength
;
210 GMX_RELEASE_ASSERT(state
->nhchainlength
== nh
, "The global and local Nose-Hoover chain lengths should match");
212 for (int i
= 0; i
< efptNR
; i
++)
214 state_local
->lambda
[i
] = state
->lambda
[i
];
216 state_local
->fep_state
= state
->fep_state
;
217 state_local
->veta
= state
->veta
;
218 state_local
->vol0
= state
->vol0
;
219 copy_mat(state
->box
, state_local
->box
);
220 copy_mat(state
->box_rel
, state_local
->box_rel
);
221 copy_mat(state
->boxv
, state_local
->boxv
);
222 copy_mat(state
->svir_prev
, state_local
->svir_prev
);
223 copy_mat(state
->fvir_prev
, state_local
->fvir_prev
);
224 if (state
->dfhist
!= nullptr)
226 copy_df_history(state_local
->dfhist
, state
->dfhist
);
228 for (int i
= 0; i
< state_local
->ngtc
; i
++)
230 for (int j
= 0; j
< nh
; j
++)
232 state_local
->nosehoover_xi
[i
*nh
+j
] = state
->nosehoover_xi
[i
*nh
+j
];
233 state_local
->nosehoover_vxi
[i
*nh
+j
] = state
->nosehoover_vxi
[i
*nh
+j
];
235 state_local
->therm_integral
[i
] = state
->therm_integral
[i
];
237 for (int i
= 0; i
< state_local
->nnhpres
; i
++)
239 for (int j
= 0; j
< nh
; j
++)
241 state_local
->nhpres_xi
[i
*nh
+j
] = state
->nhpres_xi
[i
*nh
+j
];
242 state_local
->nhpres_vxi
[i
*nh
+j
] = state
->nhpres_vxi
[i
*nh
+j
];
245 state_local
->baros_integral
= state
->baros_integral
;
247 dd_bcast(dd
, ((efptNR
)*sizeof(real
)), state_local
->lambda
.data());
248 dd_bcast(dd
, sizeof(int), &state_local
->fep_state
);
249 dd_bcast(dd
, sizeof(real
), &state_local
->veta
);
250 dd_bcast(dd
, sizeof(real
), &state_local
->vol0
);
251 dd_bcast(dd
, sizeof(state_local
->box
), state_local
->box
);
252 dd_bcast(dd
, sizeof(state_local
->box_rel
), state_local
->box_rel
);
253 dd_bcast(dd
, sizeof(state_local
->boxv
), state_local
->boxv
);
254 dd_bcast(dd
, sizeof(state_local
->svir_prev
), state_local
->svir_prev
);
255 dd_bcast(dd
, sizeof(state_local
->fvir_prev
), state_local
->fvir_prev
);
256 dd_bcast(dd
, ((state_local
->ngtc
*nh
)*sizeof(double)), state_local
->nosehoover_xi
.data());
257 dd_bcast(dd
, ((state_local
->ngtc
*nh
)*sizeof(double)), state_local
->nosehoover_vxi
.data());
258 dd_bcast(dd
, state_local
->ngtc
*sizeof(double), state_local
->therm_integral
.data());
259 dd_bcast(dd
, ((state_local
->nnhpres
*nh
)*sizeof(double)), state_local
->nhpres_xi
.data());
260 dd_bcast(dd
, ((state_local
->nnhpres
*nh
)*sizeof(double)), state_local
->nhpres_vxi
.data());
262 /* communicate df_history -- required for restarting from checkpoint */
263 dd_distribute_dfhist(dd
, state_local
->dfhist
);
265 dd_resize_state(state_local
, f
, dd
->nat_home
);
267 if (state_local
->flags
& (1 << estX
))
269 const rvec
*xGlobal
= (DDMASTER(dd
) ? as_rvec_array(state
->x
.data()) : nullptr);
270 dd_distribute_vec(dd
, cgs
, xGlobal
, as_rvec_array(state_local
->x
.data()));
272 if (state_local
->flags
& (1 << estV
))
274 const rvec
*vGlobal
= (DDMASTER(dd
) ? as_rvec_array(state
->v
.data()) : nullptr);
275 dd_distribute_vec(dd
, cgs
, vGlobal
, as_rvec_array(state_local
->v
.data()));
277 if (state_local
->flags
& (1 << estCGP
))
279 const rvec
*cgpGlobal
= (DDMASTER(dd
) ? as_rvec_array(state
->cg_p
.data()) : nullptr);
280 dd_distribute_vec(dd
, cgs
, cgpGlobal
, as_rvec_array(state_local
->cg_p
.data()));
284 static std::vector
< std::vector
< int>>
285 getAtomGroupDistribution(FILE *fplog
,
286 const matrix box
, const gmx_ddbox_t
&ddbox
,
287 const t_block
*cgs
, rvec pos
[],
290 AtomDistribution
*ma
= dd
->ma
;
292 /* Clear the count */
293 for (int rank
= 0; rank
< dd
->nnodes
; rank
++)
295 ma
->domainGroups
[rank
].numAtoms
= 0;
299 make_tric_corr_matrix(dd
->npbcdim
, box
, tcm
);
302 const auto cellBoundaries
=
303 set_dd_cell_sizes_slb(dd
, &ddbox
, setcellsizeslbMASTER
, npulse
);
305 const int *cgindex
= cgs
->index
;
307 std::vector
< std::vector
< int>> indices(dd
->nnodes
);
309 /* Compute the center of geometry for all charge groups */
310 for (int icg
= 0; icg
< cgs
->nr
; icg
++)
312 /* Set the reference location cg_cm for assigning the group */
314 int k0
= cgindex
[icg
];
315 int k1
= cgindex
[icg
+ 1];
319 copy_rvec(pos
[k0
], cg_cm
);
323 real inv_ncg
= 1/static_cast<real
>(nrcg
);
326 for (int k
= k0
; k
< k1
; k
++)
328 rvec_inc(cg_cm
, pos
[k
]);
330 for (int d
= 0; d
< DIM
; d
++)
335 /* Put the charge group in the box and determine the cell index ind */
337 for (int d
= DIM
- 1; d
>= 0; d
--)
339 real pos_d
= cg_cm
[d
];
342 bool bScrew
= (dd
->bScrewPBC
&& d
== XX
);
343 if (ddbox
.tric_dir
[d
] && dd
->nc
[d
] > 1)
345 /* Use triclinic coordinates for this dimension */
346 for (int j
= d
+ 1; j
< DIM
; j
++)
348 pos_d
+= cg_cm
[j
]*tcm
[j
][d
];
351 while (pos_d
>= box
[d
][d
])
354 rvec_dec(cg_cm
, box
[d
]);
357 cg_cm
[YY
] = box
[YY
][YY
] - cg_cm
[YY
];
358 cg_cm
[ZZ
] = box
[ZZ
][ZZ
] - cg_cm
[ZZ
];
360 for (int k
= k0
; k
< k1
; k
++)
362 rvec_dec(pos
[k
], box
[d
]);
365 pos
[k
][YY
] = box
[YY
][YY
] - pos
[k
][YY
];
366 pos
[k
][ZZ
] = box
[ZZ
][ZZ
] - pos
[k
][ZZ
];
373 rvec_inc(cg_cm
, box
[d
]);
376 cg_cm
[YY
] = box
[YY
][YY
] - cg_cm
[YY
];
377 cg_cm
[ZZ
] = box
[ZZ
][ZZ
] - cg_cm
[ZZ
];
379 for (int k
= k0
; k
< k1
; k
++)
381 rvec_inc(pos
[k
], box
[d
]);
384 pos
[k
][YY
] = box
[YY
][YY
] - pos
[k
][YY
];
385 pos
[k
][ZZ
] = box
[ZZ
][ZZ
] - pos
[k
][ZZ
];
390 /* This could be done more efficiently */
392 while (ind
[d
]+1 < dd
->nc
[d
] && pos_d
>= cellBoundaries
[d
][ind
[d
] + 1])
397 int domainIndex
= dd_index(dd
->nc
, ind
);
398 indices
[domainIndex
].push_back(icg
);
399 ma
->domainGroups
[domainIndex
].numAtoms
+= cgindex
[icg
+ 1] - cgindex
[icg
];
404 // Use double for the sums to avoid natoms^2 overflowing
406 int nat_sum
, nat_min
, nat_max
;
411 nat_min
= ma
->domainGroups
[0].numAtoms
;
412 nat_max
= ma
->domainGroups
[0].numAtoms
;
413 for (int rank
= 0; rank
< dd
->nnodes
; rank
++)
415 int numAtoms
= ma
->domainGroups
[rank
].numAtoms
;
417 // cast to double to avoid integer overflows when squaring
418 nat2_sum
+= gmx::square(static_cast<double>(numAtoms
));
419 nat_min
= std::min(nat_min
, numAtoms
);
420 nat_max
= std::max(nat_max
, numAtoms
);
422 nat_sum
/= dd
->nnodes
;
423 nat2_sum
/= dd
->nnodes
;
425 fprintf(fplog
, "Atom distribution over %d domains: av %d stddev %d min %d max %d\n",
428 static_cast<int>(std::sqrt(nat2_sum
- gmx::square(static_cast<double>(nat_sum
)) + 0.5)),
435 static void distributeAtomGroups(FILE *fplog
, gmx_domdec_t
*dd
,
437 const matrix box
, const gmx_ddbox_t
*ddbox
,
440 AtomDistribution
*ma
= nullptr;
441 int *ibuf
, buf2
[2] = { 0, 0 };
442 gmx_bool bMaster
= DDMASTER(dd
);
444 std::vector
< std::vector
< int>> groupIndices
;
452 check_screw_box(box
);
455 groupIndices
= getAtomGroupDistribution(fplog
, box
, *ddbox
, cgs
, pos
, dd
);
457 for (int rank
= 0; rank
< dd
->nnodes
; rank
++)
459 ma
->intBuffer
[rank
*2] = groupIndices
[rank
].size();
460 ma
->intBuffer
[rank
*2 + 1] = ma
->domainGroups
[rank
].numAtoms
;
462 ibuf
= ma
->intBuffer
.data();
468 dd_scatter(dd
, 2*sizeof(int), ibuf
, buf2
);
470 dd
->ncg_home
= buf2
[0];
471 dd
->nat_home
= buf2
[1];
472 dd
->ncg_tot
= dd
->ncg_home
;
473 dd
->nat_tot
= dd
->nat_home
;
474 if (dd
->ncg_home
> dd
->cg_nalloc
|| dd
->cg_nalloc
== 0)
476 dd
->cg_nalloc
= over_alloc_dd(dd
->ncg_home
);
477 srenew(dd
->index_gl
, dd
->cg_nalloc
);
478 srenew(dd
->cgindex
, dd
->cg_nalloc
+1);
483 ma
->atomGroups
.clear();
486 for (int rank
= 0; rank
< dd
->nnodes
; rank
++)
488 ma
->intBuffer
[rank
] = groupIndices
[rank
].size()*sizeof(int);
489 ma
->intBuffer
[dd
->nnodes
+ rank
] = groupOffset
*sizeof(int);
491 ma
->atomGroups
.insert(ma
->atomGroups
.end(),
492 groupIndices
[rank
].begin(), groupIndices
[rank
].end());
494 ma
->domainGroups
[rank
].atomGroups
= gmx::constArrayRefFromArray(ma
->atomGroups
.data() + groupOffset
, groupIndices
[rank
].size());
496 groupOffset
+= groupIndices
[rank
].size();
501 bMaster
? ma
->intBuffer
.data() : nullptr,
502 bMaster
? ma
->intBuffer
.data() + dd
->nnodes
: nullptr,
503 bMaster
? ma
->atomGroups
.data() : nullptr,
504 dd
->ncg_home
*sizeof(int), dd
->index_gl
);
506 /* Determine the home charge group sizes */
508 for (int i
= 0; i
< dd
->ncg_home
; i
++)
510 int cg_gl
= dd
->index_gl
[i
];
512 dd
->cgindex
[i
] + cgs
->index
[cg_gl
+1] - cgs
->index
[cg_gl
];
517 fprintf(debug
, "Home charge groups:\n");
518 for (int i
= 0; i
< dd
->ncg_home
; i
++)
520 fprintf(debug
, " %d", dd
->index_gl
[i
]);
523 fprintf(debug
, "\n");
526 fprintf(debug
, "\n");
530 void distributeState(FILE *fplog
,
532 t_state
*state_global
,
533 const t_block
&cgs_gl
,
534 const gmx_ddbox_t
&ddbox
,
535 t_state
*state_local
,
538 rvec
*xGlobal
= (DDMASTER(dd
) ? as_rvec_array(state_global
->x
.data()) : nullptr);
540 distributeAtomGroups(fplog
, dd
, &cgs_gl
,
541 DDMASTER(dd
) ? state_global
->box
: nullptr,
544 dd_distribute_state(dd
, &cgs_gl
,
545 state_global
, state_local
, f
);