2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2005,2006,2007,2008,2009 by the GROMACS development team.
5 * Copyright (c) 2010,2011,2012,2013,2014 by the GROMACS development team.
6 * Copyright (c) 2015,2016,2017,2018,2019 by the GROMACS development team.
7 * Copyright (c) 2020, by the GROMACS development team, led by
8 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
9 * and including many others, as listed in the AUTHORS file in the
10 * top-level source directory and at http://www.gromacs.org.
12 * GROMACS is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 2.1
15 * of the License, or (at your option) any later version.
17 * GROMACS is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with GROMACS; if not, see
24 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 * If you want to redistribute modifications to GROMACS, please
28 * consider that scientific software is very special. Version
29 * control is crucial - bugs must be traceable. We will be happy to
30 * consider code for inclusion in the official distribution, but
31 * derived work must not be called official GROMACS. Details are found
32 * in the README & COPYING files - if they are missing, get the
33 * official version at http://www.gromacs.org.
35 * To help us fund GROMACS development, we humbly ask that you cite
36 * the research papers on the package. Check out http://www.gromacs.org.
40 * \brief Implements atom redistribution functions.
42 * \author Berk Hess <hess@kth.se>
43 * \ingroup module_domdec
48 #include "redistribute.h"
52 #include "gromacs/domdec/domdec_network.h"
53 #include "gromacs/domdec/ga2la.h"
54 #include "gromacs/gmxlib/nrnb.h"
55 #include "gromacs/math/vec.h"
56 #include "gromacs/mdlib/gmx_omp_nthreads.h"
57 #include "gromacs/mdlib/nsgrid.h"
58 #include "gromacs/mdtypes/forcerec.h"
59 #include "gromacs/mdtypes/nblist.h"
60 #include "gromacs/mdtypes/state.h"
61 #include "gromacs/utility/cstringutil.h"
62 #include "gromacs/utility/fatalerror.h"
63 #include "gromacs/utility/gmxomp.h"
65 #include "domdec_internal.h"
68 /* The size per charge group of the cggl_flag buffer in gmx_domdec_comm_t */
69 static constexpr int DD_CGIBS = 2;
71 /* The flags for the cggl_flag buffer in gmx_domdec_comm_t */
73 /* The lower 16 bits are reserved for the charge group size */
74 static constexpr int DD_FLAG_NRCG = 65535;
76 /* Returns which bit tells whether to move a group forward along dimension d */
77 static inline int DD_FLAG_FW(int d)
79 return 1 << (16 + d * 2);
82 /* Returns which bit tells whether to move a group backward along dimension d */
83 static inline int DD_FLAG_BW(int d)
85 return 1 << (16 + d * 2 + 1);
88 static void copyMovedAtomsToBufferPerAtom(gmx::ArrayRef<const int> move,
92 gmx_domdec_comm_t* comm)
94 int pos_vec[DIM * 2] = { 0 };
96 for (gmx::index i = 0; i < move.ssize(); i++)
98 /* Skip moved atoms */
99 const int m = move[i];
102 /* Copy to the communication buffer */
103 pos_vec[m] += 1 + vec;
104 copy_rvec(src[i], comm->cgcm_state[m][pos_vec[m]++]);
105 pos_vec[m] += nvec - vec - 1;
110 static void copyMovedUpdateGroupCogs(gmx::ArrayRef<const int> move,
112 gmx::ArrayRef<const gmx::RVec> coordinates,
113 gmx_domdec_comm_t* comm)
115 int pos_vec[DIM * 2] = { 0 };
117 for (gmx::index g = 0; g < move.ssize(); g++)
119 /* Skip moved atoms */
120 const int m = move[g];
123 /* Copy to the communication buffer */
124 const gmx::RVec& cog =
125 (comm->systemInfo.useUpdateGroups ? comm->updateGroupsCog->cogForAtom(g)
127 copy_rvec(cog, comm->cgcm_state[m][pos_vec[m]]);
128 pos_vec[m] += 1 + nvec;
133 static void clear_and_mark_ind(gmx::ArrayRef<const int> move,
134 gmx::ArrayRef<const int> globalAtomIndices,
138 for (gmx::index a = 0; a < move.ssize(); a++)
142 /* Clear the global indices */
143 ga2la->erase(globalAtomIndices[a]);
144 /* Signal that this atom has moved using the ns cell index.
145 * Here we set it to -1. fill_grid will change it
146 * from -1 to NSGRID_SIGNAL_MOVED_FAC*grid->ncells.
153 static void print_cg_move(FILE* fplog,
154 const gmx_domdec_t* dd,
159 gmx_bool bHaveCgcmOld,
165 const gmx_domdec_comm_t* comm = dd->comm;
168 fprintf(fplog, "\nStep %" PRId64 ":\n", step);
170 if (comm->systemInfo.useUpdateGroups)
172 mesg += "The update group starting at atom";
178 mesg += gmx::formatString(
179 " %d moved more than the distance allowed by the domain decomposition", ddglatnr(dd, cg));
182 mesg += gmx::formatString(" (%f)", limitd);
184 mesg += gmx::formatString(" in direction %c\n", dim2char(dim));
185 fprintf(fplog, "%s", mesg.c_str());
188 "distance out of cell %f\n",
189 dir == 1 ? pos_d - comm->cell_x1[dim] : pos_d - comm->cell_x0[dim]);
192 fprintf(fplog, "Old coordinates: %8.3f %8.3f %8.3f\n", cm_old[XX], cm_old[YY], cm_old[ZZ]);
194 fprintf(fplog, "New coordinates: %8.3f %8.3f %8.3f\n", cm_new[XX], cm_new[YY], cm_new[ZZ]);
196 "Old cell boundaries in direction %c: %8.3f %8.3f\n",
198 comm->old_cell_x0[dim],
199 comm->old_cell_x1[dim]);
201 "New cell boundaries in direction %c: %8.3f %8.3f\n",
207 [[noreturn]] static void cg_move_error(FILE* fplog,
208 const gmx_domdec_t* dd,
213 gmx_bool bHaveCgcmOld,
221 print_cg_move(fplog, dd, step, cg, dim, dir, bHaveCgcmOld, limitd, cm_old, cm_new, pos_d);
223 print_cg_move(stderr, dd, step, cg, dim, dir, bHaveCgcmOld, limitd, cm_old, cm_new, pos_d);
225 "One or more atoms moved too far between two domain decomposition steps.\n"
226 "This usually means that your system is not well equilibrated");
229 static void rotate_state_atom(t_state* state, int a)
231 if (state->flags & (1 << estX))
233 auto x = makeArrayRef(state->x);
234 /* Rotate the complete state; for a rectangular box only */
235 x[a][YY] = state->box[YY][YY] - x[a][YY];
236 x[a][ZZ] = state->box[ZZ][ZZ] - x[a][ZZ];
238 if (state->flags & (1 << estV))
240 auto v = makeArrayRef(state->v);
241 v[a][YY] = -v[a][YY];
242 v[a][ZZ] = -v[a][ZZ];
244 if (state->flags & (1 << estCGP))
246 auto cg_p = makeArrayRef(state->cg_p);
247 cg_p[a][YY] = -cg_p[a][YY];
248 cg_p[a][ZZ] = -cg_p[a][ZZ];
252 /* Returns a pointer to a buffer of size \p numAtomsNew with contents 0 from numAtomsOld upwards
254 * Note: numAtomsOld should either be 0 or match the current buffer size.
256 static int* getMovedBuffer(gmx_domdec_comm_t* comm, size_t numAtomsOld, size_t numAtomsNew)
258 std::vector<int>& movedBuffer = comm->movedBuffer;
260 GMX_RELEASE_ASSERT(numAtomsOld == 0 || movedBuffer.size() == numAtomsOld,
261 "numAtomsOld should either be 0 or match the current size");
263 /* Contents up to numAtomsOld should be preserved, clear from numAtomsOld */
264 if (numAtomsOld == 0)
268 movedBuffer.resize(numAtomsNew);
270 return movedBuffer.data();
273 /* Bounds to determine whether an atom group moved to far between DD steps */
276 rvec distance; /* Maximum distance over which a group can move */
277 rvec lower; /* Lower bound for group location */
278 rvec upper; /* Upper bound for group location */
281 /* Compute flag that tells where to move an atom group
283 * The input dev tells whether the group moves fw,remains,bw (-1,0,1) along
285 * The return value is -1 when the group does not move.
286 * The return has move flags set when the group does move and the lower 4 bits
287 * are (mis)used to tell which is the first dimension (bit 1,2,3) the group
288 * needs to be moved along and in which direction (bit 0 not set for fw
291 static int computeMoveFlag(const gmx_domdec_t& dd, const ivec& dev)
294 int firstMoveDimValue = -1;
295 for (int d = 0; d < dd.ndim; d++)
297 const int dim = dd.dim[d];
300 flag |= DD_FLAG_FW(d);
301 if (firstMoveDimValue == -1)
303 firstMoveDimValue = d * 2;
306 else if (dev[dim] == -1)
308 flag |= DD_FLAG_BW(d);
309 if (firstMoveDimValue == -1)
311 if (dd.numCells[dim] > 2)
313 firstMoveDimValue = d * 2 + 1;
317 firstMoveDimValue = d * 2;
323 return firstMoveDimValue + flag;
326 /* Determine to which atoms in the range \p cg_start, \p cg_end should go.
328 * Returns in the move array where the atoms should go.
330 static void calc_cg_move(FILE* fplog,
338 const MoveLimits& moveLimits,
341 gmx::ArrayRef<int> move)
343 const int npbcdim = dd->unitCellInfo.npbcdim;
344 auto x = makeArrayRef(state->x);
346 for (int a = cg_start; a < cg_end; a++)
348 // TODO: Rename this center of geometry variable to cogNew
350 copy_rvec(x[a], cm_new);
353 /* Do pbc and check DD cell boundary crossings */
354 for (int d = DIM - 1; d >= 0; d--)
356 if (dd->numCells[d] > 1)
358 bool bScrew = (dd->unitCellInfo.haveScrewPBC && d == XX);
359 /* Determine the location of this cg in lattice coordinates */
360 real pos_d = cm_new[d];
363 for (int d2 = d + 1; d2 < DIM; d2++)
365 pos_d += cm_new[d2] * tcm[d2][d];
368 /* Put the charge group in the triclinic unit-cell */
369 if (pos_d >= cell_x1[d])
371 if (pos_d >= moveLimits.upper[d])
374 fplog, dd, step, a, d, 1, false, moveLimits.distance[d], cm_new, cm_new, pos_d);
377 if (dd->ci[d] == dd->numCells[d] - 1)
379 rvec_dec(cm_new, state->box[d]);
382 cm_new[YY] = state->box[YY][YY] - cm_new[YY];
383 cm_new[ZZ] = state->box[ZZ][ZZ] - cm_new[ZZ];
385 rvec_dec(x[a], state->box[d]);
388 rotate_state_atom(state, a);
392 else if (pos_d < cell_x0[d])
394 if (pos_d < moveLimits.lower[d])
397 fplog, dd, step, a, d, -1, false, moveLimits.distance[d], cm_new, cm_new, pos_d);
402 rvec_inc(cm_new, state->box[d]);
405 cm_new[YY] = state->box[YY][YY] - cm_new[YY];
406 cm_new[ZZ] = state->box[ZZ][ZZ] - cm_new[ZZ];
408 rvec_inc(x[a], state->box[d]);
411 rotate_state_atom(state, a);
416 else if (d < npbcdim)
418 /* Put the charge group in the rectangular unit-cell */
419 while (cm_new[d] >= state->box[d][d])
421 rvec_dec(cm_new, state->box[d]);
422 rvec_dec(x[a], state->box[d]);
424 while (cm_new[d] < 0)
426 rvec_inc(cm_new, state->box[d]);
427 rvec_inc(x[a], state->box[d]);
432 /* Temporarily store the flag in move */
433 move[a] = computeMoveFlag(*dd, dev);
439 /* Constructor that purposely does not initialize anything */
446 /* Determine to which domains update groups in the range \p groupBegin, \p groupEnd should go.
448 * Returns in the move array where the groups should go.
449 * Also updates the COGs and coordinates for jumps over periodic boundaries.
451 static void calcGroupMove(FILE* fplog,
453 const gmx_domdec_t* dd,
454 const t_state* state,
459 const MoveLimits& moveLimits,
462 gmx::ArrayRef<PbcAndFlag> pbcAndFlags)
464 GMX_RELEASE_ASSERT(!dd->unitCellInfo.haveScrewPBC, "Screw PBC is not supported here");
466 const int npbcdim = dd->unitCellInfo.npbcdim;
468 gmx::UpdateGroupsCog* updateGroupsCog = dd->comm->updateGroupsCog.get();
470 for (int g = groupBegin; g < groupEnd; g++)
473 gmx::RVec& cog = updateGroupsCog->cog(g);
474 gmx::RVec cogOld = cog;
477 /* Do pbc and check DD cell boundary crossings */
478 for (int d = DIM - 1; d >= 0; d--)
480 if (dd->numCells[d] > 1)
482 /* Determine the location of this COG in lattice coordinates */
486 for (int d2 = d + 1; d2 < DIM; d2++)
488 pos_d += cog[d2] * tcm[d2][d];
491 /* Put the COG in the triclinic unit-cell */
492 if (pos_d >= cell_x1[d])
494 if (pos_d >= moveLimits.upper[d])
497 fplog, dd, step, g, d, 1, true, moveLimits.distance[d], cogOld, cog, pos_d);
500 if (dd->ci[d] == dd->numCells[d] - 1)
502 rvec_dec(cog, state->box[d]);
505 else if (pos_d < cell_x0[d])
507 if (pos_d < moveLimits.lower[d])
510 fplog, dd, step, g, d, -1, true, moveLimits.distance[d], cogOld, cog, pos_d);
515 rvec_inc(cog, state->box[d]);
519 else if (d < npbcdim)
521 /* Put the COG in the rectangular unit-cell */
522 while (cog[d] >= state->box[d][d])
524 rvec_dec(cog, state->box[d]);
528 rvec_inc(cog, state->box[d]);
533 /* Store the PBC and move flag, so we can later apply them to the atoms */
534 PbcAndFlag& pbcAndFlag = pbcAndFlags[g];
536 rvec_sub(cog, cogOld, pbcAndFlag.pbcShift);
537 pbcAndFlag.moveFlag = computeMoveFlag(*dd, dev);
541 static void applyPbcAndSetMoveFlags(const gmx::UpdateGroupsCog& updateGroupsCog,
542 gmx::ArrayRef<const PbcAndFlag> pbcAndFlags,
545 gmx::ArrayRef<gmx::RVec> atomCoords,
546 gmx::ArrayRef<int> move)
548 for (int a = atomBegin; a < atomEnd; a++)
550 const PbcAndFlag& pbcAndFlag = pbcAndFlags[updateGroupsCog.cogIndex(a)];
551 rvec_inc(atomCoords[a], pbcAndFlag.pbcShift);
552 /* Temporarily store the flag in move */
553 move[a] = pbcAndFlag.moveFlag;
557 void dd_redistribute_cg(FILE* fplog,
566 gmx_domdec_comm_t* comm = dd->comm;
568 if (dd->unitCellInfo.haveScrewPBC)
570 check_screw_box(state->box);
573 // Positions are always present, so there's nothing to flag
574 bool bV = (state->flags & (1 << estV)) != 0;
575 bool bCGP = (state->flags & (1 << estCGP)) != 0;
577 DDBufferAccess<int> moveBuffer(comm->intBuffer, dd->ncg_home);
578 gmx::ArrayRef<int> move = moveBuffer.buffer;
580 const int npbcdim = dd->unitCellInfo.npbcdim;
582 rvec cell_x0, cell_x1;
583 MoveLimits moveLimits;
584 for (int d = 0; (d < DIM); d++)
586 moveLimits.distance[d] = dd->comm->cellsize_min[d];
587 if (d >= npbcdim && dd->ci[d] == 0)
589 cell_x0[d] = -GMX_FLOAT_MAX;
593 cell_x0[d] = comm->cell_x0[d];
595 if (d >= npbcdim && dd->ci[d] == dd->numCells[d] - 1)
597 cell_x1[d] = GMX_FLOAT_MAX;
601 cell_x1[d] = comm->cell_x1[d];
605 moveLimits.lower[d] = comm->old_cell_x0[d] - moveLimits.distance[d];
606 moveLimits.upper[d] = comm->old_cell_x1[d] + moveLimits.distance[d];
610 /* We check after communication if a charge group moved
611 * more than one cell. Set the pre-comm check limit to float_max.
613 moveLimits.lower[d] = -GMX_FLOAT_MAX;
614 moveLimits.upper[d] = GMX_FLOAT_MAX;
619 make_tric_corr_matrix(npbcdim, state->box, tcm);
621 const int nthread = gmx_omp_nthreads_get(emntDomdec);
623 /* Compute the center of geometry for all home charge groups
624 * and put them in the box and determine where they should go.
626 std::vector<PbcAndFlag> pbcAndFlags(
627 comm->systemInfo.useUpdateGroups ? comm->updateGroupsCog->numCogs() : 0);
629 #pragma omp parallel num_threads(nthread)
633 const int thread = gmx_omp_get_thread_num();
635 if (comm->systemInfo.useUpdateGroups)
637 const auto& updateGroupsCog = *comm->updateGroupsCog;
638 const int numGroups = updateGroupsCog.numCogs();
648 (thread * numGroups) / nthread,
649 ((thread + 1) * numGroups) / nthread,
651 /* We need a barrier as atoms below can be in a COG of a different thread */
653 const int numHomeAtoms = comm->atomRanges.numHomeAtoms();
654 applyPbcAndSetMoveFlags(updateGroupsCog,
656 (thread * numHomeAtoms) / nthread,
657 ((thread + 1) * numHomeAtoms) / nthread,
663 /* Here we handle single atoms or charge groups */
673 (thread * dd->ncg_home) / nthread,
674 ((thread + 1) * dd->ncg_home) / nthread,
678 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
681 int ncg[DIM * 2] = { 0 };
682 int nat[DIM * 2] = { 0 };
683 for (int cg = 0; cg < dd->ncg_home; cg++)
687 const int flag = move[cg] & ~DD_FLAG_NRCG;
688 const int mc = move[cg] & DD_FLAG_NRCG;
691 std::vector<int>& cggl_flag = comm->cggl_flag[mc];
693 /* TODO: See if we can use push_back instead */
694 if ((ncg[mc] + 1) * DD_CGIBS > gmx::index(cggl_flag.size()))
696 cggl_flag.resize((ncg[mc] + 1) * DD_CGIBS);
698 cggl_flag[ncg[mc] * DD_CGIBS] = dd->globalAtomGroupIndices[cg];
699 /* We store the cg size in the lower 16 bits
700 * and the place where the charge group should go
701 * in the next 6 bits. This saves some communication volume.
703 * TODO: Remove the size, as it is now always 1.
705 const int numAtomsInGroup = 1;
706 cggl_flag[ncg[mc] * DD_CGIBS + 1] = numAtomsInGroup | flag;
708 nat[mc] += numAtomsInGroup;
712 inc_nrnb(nrnb, eNR_CGCM, comm->atomRanges.numHomeAtoms());
713 inc_nrnb(nrnb, eNR_RESETX, dd->ncg_home);
716 for (int i = 0; i < dd->ndim * 2; i++)
718 *ncg_moved += ncg[i];
731 /* Make sure the communication buffers are large enough */
732 for (int mc = 0; mc < dd->ndim * 2; mc++)
734 size_t nvr = ncg[mc] + nat[mc] * nvec;
735 if (nvr > comm->cgcm_state[mc].size())
737 comm->cgcm_state[mc].resize(nvr);
741 /* With update groups we send over their COGs.
742 * Without update groups we send the moved atom coordinates
743 * over twice. This is so the code further down can be used
744 * without many conditionals both with and without update groups.
746 copyMovedUpdateGroupCogs(move, nvec, state->x, comm);
749 copyMovedAtomsToBufferPerAtom(move, nvec, vectorIndex++, state->x.rvec_array(), comm);
752 copyMovedAtomsToBufferPerAtom(move, nvec, vectorIndex++, state->v.rvec_array(), comm);
756 copyMovedAtomsToBufferPerAtom(move, nvec, vectorIndex++, state->cg_p.rvec_array(), comm);
759 int* moved = getMovedBuffer(comm, 0, dd->ncg_home);
761 clear_and_mark_ind(move, dd->globalAtomIndices, dd->ga2la, moved);
763 /* Now we can remove the excess global atom-group indices from the list */
764 dd->globalAtomGroupIndices.resize(dd->ncg_home);
766 /* We reuse the intBuffer without reacquiring since we are in the same scope */
767 DDBufferAccess<int>& flagBuffer = moveBuffer;
769 gmx::ArrayRef<const cginfo_mb_t> cginfo_mb = fr->cginfo_mb;
771 /* Temporarily store atoms passed to our rank at the end of the range */
772 int home_pos_cg = dd->ncg_home;
773 int home_pos_at = dd->ncg_home;
774 for (int d = 0; d < dd->ndim; d++)
776 DDBufferAccess<gmx::RVec> rvecBuffer(comm->rvecBuffer, 0);
778 const int dim = dd->dim[d];
781 for (int dir = 0; dir < (dd->numCells[dim] == 2 ? 1 : 2); dir++)
783 const int cdd = d * 2 + dir;
784 /* Communicate the cg and atom counts */
785 int sbuf[2] = { ncg[cdd], nat[cdd] };
788 fprintf(debug, "Sending ddim %d dir %d: ncg %d nat %d\n", d, dir, sbuf[0], sbuf[1]);
791 ddSendrecv(dd, d, dir, sbuf, 2, rbuf, 2);
793 flagBuffer.resize((ncg_recv + rbuf[0]) * DD_CGIBS);
795 /* Communicate the charge group indices, sizes and flags */
799 comm->cggl_flag[cdd].data(),
801 flagBuffer.buffer.data() + ncg_recv * DD_CGIBS,
804 const int nvs = ncg[cdd] + nat[cdd] * nvec;
805 const int i = rbuf[0] + rbuf[1] * nvec;
806 rvecBuffer.resize(nvr + i);
808 /* Communicate cgcm and state */
812 as_rvec_array(comm->cgcm_state[cdd].data()),
814 as_rvec_array(rvecBuffer.buffer.data()) + nvr,
820 dd_resize_atominfo_and_state(fr, state, home_pos_cg + ncg_recv);
822 /* Process the received charge or update groups */
824 for (int cg = 0; cg < ncg_recv; cg++)
826 /* Extract the move flags and COG for the charge or update group */
827 int flag = flagBuffer.buffer[cg * DD_CGIBS + 1];
828 const gmx::RVec& cog = rvecBuffer.buffer[buf_pos];
830 if (dim >= npbcdim && dd->numCells[dim] > 2)
832 /* No pbc in this dim and more than one domain boundary.
833 * We do a separate check if a charge group didn't move too far.
835 if (((flag & DD_FLAG_FW(d)) && cog[dim] > cell_x1[dim])
836 || ((flag & DD_FLAG_BW(d)) && cog[dim] < cell_x0[dim]))
838 rvec pos = { cog[0], cog[1], cog[2] };
840 fplog, dd, step, cg, dim, (flag & DD_FLAG_FW(d)) ? 1 : 0, false, 0, pos, pos, pos[dim]);
845 if (d < dd->ndim - 1)
847 /* Check which direction this cg should go */
848 for (int d2 = d + 1; (d2 < dd->ndim && mc == -1); d2++)
850 if (isDlbOn(dd->comm))
852 /* The cell boundaries for dimension d2 are not equal
853 * for each cell row of the lower dimension(s),
854 * therefore we might need to redetermine where
857 const int dim2 = dd->dim[d2];
858 /* The DD grid is not staggered at the box boundaries,
859 * so we do not need to handle boundary crossings.
860 * This also means we do not have to handle PBC here.
862 if (!((dd->ci[dim2] == dd->numCells[dim2] - 1 && (flag & DD_FLAG_FW(d2)))
863 || (dd->ci[dim2] == 0 && (flag & DD_FLAG_BW(d2)))))
865 /* Clear the two flags for this dimension */
866 flag &= ~(DD_FLAG_FW(d2) | DD_FLAG_BW(d2));
867 /* Determine the location of this cg
868 * in lattice coordinates
870 real pos_d = cog[dim2];
873 for (int d3 = dim2 + 1; d3 < DIM; d3++)
875 pos_d += cog[d3] * tcm[d3][dim2];
879 GMX_ASSERT(dim2 >= 0 && dim2 < DIM, "Keep the static analyzer happy");
881 /* Check if we need to move this group
882 * to an adjacent cell because of the
885 if (pos_d >= cell_x1[dim2] && dd->ci[dim2] != dd->numCells[dim2] - 1)
887 flag |= DD_FLAG_FW(d2);
889 else if (pos_d < cell_x0[dim2] && dd->ci[dim2] != 0)
891 flag |= DD_FLAG_BW(d2);
894 flagBuffer.buffer[cg * DD_CGIBS + 1] = flag;
897 /* Set to which neighboring cell this cg should go */
898 if (flag & DD_FLAG_FW(d2))
902 else if (flag & DD_FLAG_BW(d2))
904 if (dd->numCells[dd->dim[d2]] > 2)
916 GMX_ASSERT((flag & DD_FLAG_NRCG) == 1,
917 "Charge groups are gone, so all groups should have size 1");
918 constexpr int nrcg = 1;
921 /* Set the global charge group index and size */
922 const int globalAtomGroupIndex = flagBuffer.buffer[cg * DD_CGIBS];
923 dd->globalAtomGroupIndices.push_back(globalAtomGroupIndex);
924 /* Skip the COG entry in the buffer */
928 fr->cginfo[home_pos_cg] = ddcginfo(cginfo_mb, globalAtomGroupIndex);
930 auto x = makeArrayRef(state->x);
931 auto v = makeArrayRef(state->v);
932 auto cg_p = makeArrayRef(state->cg_p);
933 rvec* rvecPtr = as_rvec_array(rvecBuffer.buffer.data());
934 for (int i = 0; i < nrcg; i++)
936 copy_rvec(rvecPtr[buf_pos++], x[home_pos_at + i]);
940 for (int i = 0; i < nrcg; i++)
942 copy_rvec(rvecPtr[buf_pos++], v[home_pos_at + i]);
947 for (int i = 0; i < nrcg; i++)
949 copy_rvec(rvecPtr[buf_pos++], cg_p[home_pos_at + i]);
957 /* Reallocate the buffers if necessary */
958 if ((ncg[mc] + 1) * DD_CGIBS > gmx::index(comm->cggl_flag[mc].size()))
960 comm->cggl_flag[mc].resize((ncg[mc] + 1) * DD_CGIBS);
962 size_t nvr = ncg[mc] + nat[mc] * nvec;
963 if (nvr + 1 + nrcg * nvec > comm->cgcm_state[mc].size())
965 comm->cgcm_state[mc].resize(nvr + 1 + nrcg * nvec);
967 /* Copy from the receive to the send buffers */
968 memcpy(comm->cggl_flag[mc].data() + ncg[mc] * DD_CGIBS,
969 flagBuffer.buffer.data() + cg * DD_CGIBS,
970 DD_CGIBS * sizeof(int));
971 memcpy(comm->cgcm_state[mc][nvr],
972 rvecBuffer.buffer.data() + buf_pos,
973 (1 + nrcg * nvec) * sizeof(rvec));
974 buf_pos += 1 + nrcg * nvec;
981 /* Note that the indices are now only partially up to date
982 * and ncg_home and nat_home are not the real count, since there are
983 * "holes" in the arrays for the charge groups that moved to neighbors.
986 /* We need to clear the moved flags for the received atoms,
987 * because the moved buffer will be passed to the nbnxm gridding call.
989 moved = getMovedBuffer(comm, dd->ncg_home, home_pos_cg);
991 for (int i = dd->ncg_home; i < home_pos_cg; i++)
996 dd->ncg_home = home_pos_cg;
997 comm->atomRanges.setEnd(DDAtomRanges::Type::Home, home_pos_at);
1002 "Finished repartitioning: cgs moved out %d, new home %d\n",
1004 dd->ncg_home - *ncg_moved);