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.
37 * \brief Implements atom redistribution functions.
39 * \author Berk Hess <hess@kth.se>
40 * \ingroup module_domdec
45 #include "redistribute.h"
49 #include "gromacs/domdec/domdec_network.h"
50 #include "gromacs/domdec/ga2la.h"
51 #include "gromacs/gmxlib/nrnb.h"
52 #include "gromacs/math/vec.h"
53 #include "gromacs/mdlib/gmx_omp_nthreads.h"
54 #include "gromacs/mdlib/nsgrid.h"
55 #include "gromacs/mdtypes/forcerec.h"
56 #include "gromacs/mdtypes/nblist.h"
57 #include "gromacs/mdtypes/state.h"
58 #include "gromacs/utility/cstringutil.h"
59 #include "gromacs/utility/fatalerror.h"
61 #include "domdec_internal.h"
64 /* The size per charge group of the cggl_flag buffer in gmx_domdec_comm_t */
67 /* The flags for the cggl_flag buffer in gmx_domdec_comm_t */
68 #define DD_FLAG_NRCG 65535
69 #define DD_FLAG_FW(d) (1<<(16+(d)*2))
70 #define DD_FLAG_BW(d) (1<<(16+(d)*2+1))
72 static int compact_and_copy_vec_at(int ncg, int *move,
73 const gmx::RangePartitioning &atomGroups,
75 rvec *src, gmx_domdec_comm_t *comm,
79 int pos_vec[DIM*2] = { 0 };
81 for (int g = 0; g < ncg; g++)
83 const auto atomGroup = atomGroups.block(g);
89 /* Compact the home array in place */
90 for (int i : atomGroup)
92 copy_rvec(src[i], src[home_pos++]);
98 /* Copy to the communication buffer */
99 int numAtoms = atomGroup.size();
100 pos_vec[m] += 1 + vec*numAtoms;
101 for (int i : atomGroup)
103 copy_rvec(src[i], comm->cgcm_state[m][pos_vec[m]++]);
105 pos_vec[m] += (nvec - vec - 1)*numAtoms;
109 home_pos += atomGroup.size();
116 static int compact_and_copy_vec_cg(int ncg, int *move,
117 const gmx::RangePartitioning &atomGroups,
118 int nvec, rvec *src, gmx_domdec_comm_t *comm,
122 int pos_vec[DIM*2] = { 0 };
124 for (int g = 0; g < ncg; g++)
126 const auto atomGroup = atomGroups.block(g);
132 /* Compact the home array in place */
133 copy_rvec(src[g], src[home_pos++]);
138 /* Copy to the communication buffer */
139 copy_rvec(src[g], comm->cgcm_state[m][pos_vec[m]]);
140 pos_vec[m] += 1 + atomGroup.size()*nvec;
151 static int compact_ind(int numAtomGroups,
153 gmx::ArrayRef<int> globalAtomGroupIndices,
154 gmx::RangePartitioning *atomGroups,
155 gmx::ArrayRef<int> globalAtomIndices,
163 for (int g = 0; g < numAtomGroups; g++)
167 /* Compact the home arrays in place.
168 * Anything that can be done here avoids access to global arrays.
170 atomGroups->appendBlock(nat);
171 for (int a : atomGroups->block(g))
173 const int a_gl = globalAtomIndices[a];
174 globalAtomIndices[nat] = a_gl;
175 /* The cell number stays 0, so we don't need to set it */
176 ga2la_change_la(ga2la, a_gl, nat);
179 globalAtomGroupIndices[home_pos] = globalAtomGroupIndices[g];
180 cginfo[home_pos] = cginfo[g];
181 /* The charge group remains local, so bLocalCG does not change */
186 /* Clear the global indices */
187 for (int a : atomGroups->block(g))
189 ga2la_del(ga2la, globalAtomIndices[a]);
193 bLocalCG[globalAtomGroupIndices[g]] = FALSE;
198 GMX_ASSERT(atomGroups->numBlocks() == home_pos, "The atom group data and atomGroups should be consistent");
203 static void clear_and_mark_ind(int numAtomGroups,
205 gmx::ArrayRef<const int> globalAtomGroupIndices,
206 const gmx::RangePartitioning &atomGroups,
207 gmx::ArrayRef<const int> globalAtomIndices,
212 for (int g = 0; g < numAtomGroups; g++)
216 /* Clear the global indices */
217 for (int a : atomGroups.block(g))
219 ga2la_del(ga2la, globalAtomIndices[a]);
223 bLocalCG[globalAtomGroupIndices[g]] = FALSE;
225 /* Signal that this group has moved using the ns cell index.
226 * Here we set it to -1. fill_grid will change it
227 * from -1 to NSGRID_SIGNAL_MOVED_FAC*grid->ncells.
234 static void print_cg_move(FILE *fplog,
236 gmx_int64_t step, int cg, int dim, int dir,
237 gmx_bool bHaveCgcmOld, real limitd,
238 rvec cm_old, rvec cm_new, real pos_d)
240 gmx_domdec_comm_t *comm;
245 fprintf(fplog, "\nStep %s:\n", gmx_step_str(step, buf));
248 fprintf(fplog, "%s %d moved more than the distance allowed by the domain decomposition (%f) in direction %c\n",
249 dd->comm->bCGs ? "The charge group starting at atom" : "Atom",
250 ddglatnr(dd, dd->atomGrouping().block(cg).begin()), limitd, dim2char(dim));
254 /* We don't have a limiting distance available: don't print it */
255 fprintf(fplog, "%s %d moved more than the distance allowed by the domain decomposition in direction %c\n",
256 dd->comm->bCGs ? "The charge group starting at atom" : "Atom",
257 ddglatnr(dd, dd->atomGrouping().block(cg).begin()), dim2char(dim));
259 fprintf(fplog, "distance out of cell %f\n",
260 dir == 1 ? pos_d - comm->cell_x1[dim] : pos_d - comm->cell_x0[dim]);
263 fprintf(fplog, "Old coordinates: %8.3f %8.3f %8.3f\n",
264 cm_old[XX], cm_old[YY], cm_old[ZZ]);
266 fprintf(fplog, "New coordinates: %8.3f %8.3f %8.3f\n",
267 cm_new[XX], cm_new[YY], cm_new[ZZ]);
268 fprintf(fplog, "Old cell boundaries in direction %c: %8.3f %8.3f\n",
270 comm->old_cell_x0[dim], comm->old_cell_x1[dim]);
271 fprintf(fplog, "New cell boundaries in direction %c: %8.3f %8.3f\n",
273 comm->cell_x0[dim], comm->cell_x1[dim]);
276 static void cg_move_error(FILE *fplog,
278 gmx_int64_t step, int cg, int dim, int dir,
279 gmx_bool bHaveCgcmOld, real limitd,
280 rvec cm_old, rvec cm_new, real pos_d)
284 print_cg_move(fplog, dd, step, cg, dim, dir,
285 bHaveCgcmOld, limitd, cm_old, cm_new, pos_d);
287 print_cg_move(stderr, dd, step, cg, dim, dir,
288 bHaveCgcmOld, limitd, cm_old, cm_new, pos_d);
290 "%s moved too far between two domain decomposition steps\n"
291 "This usually means that your system is not well equilibrated",
292 dd->comm->bCGs ? "A charge group" : "An atom");
295 static void rotate_state_atom(t_state *state, int a)
297 if (state->flags & (1 << estX))
299 /* Rotate the complete state; for a rectangular box only */
300 state->x[a][YY] = state->box[YY][YY] - state->x[a][YY];
301 state->x[a][ZZ] = state->box[ZZ][ZZ] - state->x[a][ZZ];
303 if (state->flags & (1 << estV))
305 state->v[a][YY] = -state->v[a][YY];
306 state->v[a][ZZ] = -state->v[a][ZZ];
308 if (state->flags & (1 << estCGP))
310 state->cg_p[a][YY] = -state->cg_p[a][YY];
311 state->cg_p[a][ZZ] = -state->cg_p[a][ZZ];
315 /* Returns a pointer to a buffer of size \p numAtomsNew with contents 0 from numAtomsOld upwards
317 * Note: numAtomsOld should either be 0 or match the current buffer size.
319 static int *getMovedBuffer(gmx_domdec_comm_t *comm,
323 std::vector<int> &movedBuffer = comm->movedBuffer;
325 GMX_RELEASE_ASSERT(numAtomsOld == 0 || movedBuffer.size() == numAtomsOld, "numAtomsOld should either be 0 or match the current size");
327 /* Contents up to numAtomsOld should be preserved, clear from numAtomsOld */
328 if (numAtomsOld == 0)
332 movedBuffer.resize(numAtomsNew);
334 return movedBuffer.data();
337 /* Determine to which domains atomGroups in the range \p cg_start, \p cg_end should go.
339 * Returns in the move array where the groups should go.
340 * Also updates \p cg_cm for jumps over periodic boundaries.
342 * \TODO Rename cg to atomGroup.
344 static void calc_cg_move(FILE *fplog, gmx_int64_t step,
347 ivec tric_dir, matrix tcm,
348 rvec cell_x0, rvec cell_x1,
349 rvec limitd, rvec limit0, rvec limit1,
350 const gmx::RangePartitioning &atomGroups,
351 int cg_start, int cg_end,
355 const int npbcdim = dd->npbcdim;
357 for (int g = cg_start; g < cg_end; g++)
359 const auto atomGroup = atomGroups.block(g);
360 const int numAtoms = atomGroup.size();
361 // TODO: Rename this center of geometry variable to cogNew
365 copy_rvec(state->x[atomGroup.begin()], cm_new);
369 real invNumAtoms = 1/static_cast<real>(numAtoms);
371 for (int k : atomGroup)
373 rvec_inc(cm_new, state->x[k]);
375 for (int d = 0; d < DIM; d++)
377 cm_new[d] = invNumAtoms*cm_new[d];
382 /* Do pbc and check DD cell boundary crossings */
383 for (int d = DIM - 1; d >= 0; d--)
387 bool bScrew = (dd->bScrewPBC && d == XX);
388 /* Determine the location of this cg in lattice coordinates */
389 real pos_d = cm_new[d];
392 for (int d2 = d + 1; d2 < DIM; d2++)
394 pos_d += cm_new[d2]*tcm[d2][d];
397 /* Put the charge group in the triclinic unit-cell */
398 if (pos_d >= cell_x1[d])
400 if (pos_d >= limit1[d])
402 cg_move_error(fplog, dd, step, g, d, 1,
403 cg_cm != as_rvec_array(state->x.data()), limitd[d],
404 cg_cm[g], cm_new, pos_d);
407 if (dd->ci[d] == dd->nc[d] - 1)
409 rvec_dec(cm_new, state->box[d]);
412 cm_new[YY] = state->box[YY][YY] - cm_new[YY];
413 cm_new[ZZ] = state->box[ZZ][ZZ] - cm_new[ZZ];
415 for (int k : atomGroup)
417 rvec_dec(state->x[k], state->box[d]);
420 rotate_state_atom(state, k);
425 else if (pos_d < cell_x0[d])
427 if (pos_d < limit0[d])
429 cg_move_error(fplog, dd, step, g, d, -1,
430 cg_cm != as_rvec_array(state->x.data()), limitd[d],
431 cg_cm[g], cm_new, pos_d);
436 rvec_inc(cm_new, state->box[d]);
439 cm_new[YY] = state->box[YY][YY] - cm_new[YY];
440 cm_new[ZZ] = state->box[ZZ][ZZ] - cm_new[ZZ];
442 for (int k : atomGroup)
444 rvec_inc(state->x[k], state->box[d]);
447 rotate_state_atom(state, k);
453 else if (d < npbcdim)
455 /* Put the charge group in the rectangular unit-cell */
456 while (cm_new[d] >= state->box[d][d])
458 rvec_dec(cm_new, state->box[d]);
459 for (int k : atomGroup)
461 rvec_dec(state->x[k], state->box[d]);
464 while (cm_new[d] < 0)
466 rvec_inc(cm_new, state->box[d]);
467 for (int k : atomGroup)
469 rvec_inc(state->x[k], state->box[d]);
475 copy_rvec(cm_new, cg_cm[g]);
477 /* Determine where this cg should go */
480 for (int d = 0; d < dd->ndim; d++)
482 int dim = dd->dim[d];
485 flag |= DD_FLAG_FW(d);
491 else if (dev[dim] == -1)
493 flag |= DD_FLAG_BW(d);
507 /* Temporarily store the flag in move */
512 void dd_redistribute_cg(FILE *fplog, gmx_int64_t step,
513 gmx_domdec_t *dd, ivec tric_dir,
514 t_state *state, PaddedRVecVector *f,
523 int ncg[DIM*2] = { 0 }, nat[DIM*2] = { 0 };
524 int i, cg, d, dim, dim2, dir, d2, d3;
525 int mc, cdd, nrcg, ncg_recv, nvs, nvec, vec;
526 int sbuf[2], rbuf[2];
527 int home_pos_cg, home_pos_at, buf_pos;
530 rvec *cg_cm = nullptr, cell_x0, cell_x1, limitd, limit0, limit1;
531 cginfo_mb_t *cginfo_mb;
532 gmx_domdec_comm_t *comm;
538 check_screw_box(state->box);
542 if (fr->cutoff_scheme == ecutsGROUP)
547 // Positions are always present, so there's nothing to flag
548 bool bV = state->flags & (1<<estV);
549 bool bCGP = state->flags & (1<<estCGP);
551 DDBufferAccess<int> moveBuffer(comm->intBuffer, dd->globalAtomGroupIndices.size());
552 move = moveBuffer.buffer.data();
554 npbcdim = dd->npbcdim;
556 for (d = 0; (d < DIM); d++)
558 limitd[d] = dd->comm->cellsize_min[d];
559 if (d >= npbcdim && dd->ci[d] == 0)
561 cell_x0[d] = -GMX_FLOAT_MAX;
565 cell_x0[d] = comm->cell_x0[d];
567 if (d >= npbcdim && dd->ci[d] == dd->nc[d] - 1)
569 cell_x1[d] = GMX_FLOAT_MAX;
573 cell_x1[d] = comm->cell_x1[d];
577 limit0[d] = comm->old_cell_x0[d] - limitd[d];
578 limit1[d] = comm->old_cell_x1[d] + limitd[d];
582 /* We check after communication if a charge group moved
583 * more than one cell. Set the pre-comm check limit to float_max.
585 limit0[d] = -GMX_FLOAT_MAX;
586 limit1[d] = GMX_FLOAT_MAX;
590 make_tric_corr_matrix(npbcdim, state->box, tcm);
592 const gmx::RangePartitioning &atomGrouping = dd->atomGrouping();
594 nthread = gmx_omp_nthreads_get(emntDomdec);
596 /* Compute the center of geometry for all home charge groups
597 * and put them in the box and determine where they should go.
599 #pragma omp parallel for num_threads(nthread) schedule(static)
600 for (thread = 0; thread < nthread; thread++)
604 calc_cg_move(fplog, step, dd, state, tric_dir, tcm,
605 cell_x0, cell_x1, limitd, limit0, limit1,
607 ( thread *dd->ncg_home)/nthread,
608 ((thread+1)*dd->ncg_home)/nthread,
609 fr->cutoff_scheme == ecutsGROUP ? cg_cm : as_rvec_array(state->x.data()),
612 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
615 for (cg = 0; cg < dd->ncg_home; cg++)
620 int flag = mc & ~DD_FLAG_NRCG;
621 mc = mc & DD_FLAG_NRCG;
624 std::vector<int> &cggl_flag = comm->cggl_flag[mc];
626 /* TODO: See if we can use push_back instead */
627 if (static_cast<size_t>((ncg[mc] + 1)*DD_CGIBS) > cggl_flag.size())
629 cggl_flag.resize((ncg[mc] + 1)*DD_CGIBS);
631 cggl_flag[ncg[mc]*DD_CGIBS ] = dd->globalAtomGroupIndices[cg];
632 /* We store the cg size in the lower 16 bits
633 * and the place where the charge group should go
634 * in the next 6 bits. This saves some communication volume.
636 nrcg = atomGrouping.block(cg).size();
637 cggl_flag[ncg[mc]*DD_CGIBS+1] = nrcg | flag;
643 inc_nrnb(nrnb, eNR_CGCM, comm->atomRanges.numHomeAtoms());
644 inc_nrnb(nrnb, eNR_RESETX, dd->ncg_home);
647 for (i = 0; i < dd->ndim*2; i++)
649 *ncg_moved += ncg[i];
662 /* Make sure the communication buffers are large enough */
663 for (mc = 0; mc < dd->ndim*2; mc++)
665 size_t nvr = ncg[mc] + nat[mc]*nvec;
666 if (nvr > comm->cgcm_state[mc].size())
668 comm->cgcm_state[mc].resize(nvr);
672 switch (fr->cutoff_scheme)
675 /* Recalculating cg_cm might be cheaper than communicating,
676 * but that could give rise to rounding issues.
679 compact_and_copy_vec_cg(dd->ncg_home, move, dd->atomGrouping(),
680 nvec, cg_cm, comm, bCompact);
683 /* Without charge groups we send the moved atom coordinates
684 * over twice. This is so the code below can be used without
685 * many conditionals for both for with and without charge groups.
688 compact_and_copy_vec_cg(dd->ncg_home, move, dd->atomGrouping(),
689 nvec, as_rvec_array(state->x.data()), comm, FALSE);
692 home_pos_cg -= *ncg_moved;
696 gmx_incons("unimplemented");
702 compact_and_copy_vec_at(dd->ncg_home, move, dd->atomGrouping(),
703 nvec, vec++, as_rvec_array(state->x.data()),
707 compact_and_copy_vec_at(dd->ncg_home, move, dd->atomGrouping(),
708 nvec, vec++, as_rvec_array(state->v.data()),
713 compact_and_copy_vec_at(dd->ncg_home, move, dd->atomGrouping(),
714 nvec, vec++, as_rvec_array(state->cg_p.data()),
720 compact_ind(dd->ncg_home, move,
721 dd->globalAtomGroupIndices, &dd->atomGrouping_, dd->globalAtomIndices,
722 dd->ga2la, comm->bLocalCG,
727 if (fr->cutoff_scheme == ecutsVERLET)
729 moved = getMovedBuffer(comm, 0, dd->ncg_home);
733 moved = fr->ns->grid->cell_index;
736 clear_and_mark_ind(dd->ncg_home, move,
737 dd->globalAtomGroupIndices, dd->atomGrouping(), dd->globalAtomIndices,
738 dd->ga2la, comm->bLocalCG,
742 /* Now we can remove the excess global atom-group indices from the list */
743 dd->globalAtomGroupIndices.resize(home_pos_cg);
744 dd->atomGrouping_.reduceNumBlocks(home_pos_cg);
746 /* We reuse the intBuffer without reacquiring since we are in the same scope */
747 DDBufferAccess<int> &flagBuffer = moveBuffer;
749 cginfo_mb = fr->cginfo_mb;
751 *ncg_stay_home = home_pos_cg;
752 for (d = 0; d < dd->ndim; d++)
754 DDBufferAccess<gmx::RVec> rvecBuffer(comm->rvecBuffer, 0);
759 for (dir = 0; dir < (dd->nc[dim] == 2 ? 1 : 2); dir++)
762 /* Communicate the cg and atom counts */
767 fprintf(debug, "Sending ddim %d dir %d: ncg %d nat %d\n",
768 d, dir, sbuf[0], sbuf[1]);
770 ddSendrecv(dd, d, dir, sbuf, 2, rbuf, 2);
772 flagBuffer.resize((ncg_recv + rbuf[0])*DD_CGIBS);
774 /* Communicate the charge group indices, sizes and flags */
775 ddSendrecv(dd, d, dir,
776 comm->cggl_flag[cdd].data(), sbuf[0]*DD_CGIBS,
777 flagBuffer.buffer.data() + ncg_recv*DD_CGIBS, rbuf[0]*DD_CGIBS);
779 nvs = ncg[cdd] + nat[cdd]*nvec;
780 i = rbuf[0] + rbuf[1] *nvec;
781 rvecBuffer.resize(nvr + i);
783 /* Communicate cgcm and state */
784 ddSendrecv(dd, d, dir,
785 as_rvec_array(comm->cgcm_state[cdd].data()), nvs,
786 as_rvec_array(rvecBuffer.buffer.data()) + nvr, i);
791 dd_check_alloc_ncg(fr, state, f, home_pos_cg + ncg_recv);
792 if (fr->cutoff_scheme == ecutsGROUP)
794 /* Here we resize to more than necessary and shrink later */
795 dd_resize_state(state, f, home_pos_at + ncg_recv*MAX_CGCGSIZE);
798 /* Process the received charge groups */
800 for (cg = 0; cg < ncg_recv; cg++)
802 int flag = flagBuffer.buffer[cg*DD_CGIBS + 1];
803 rvec &pos = as_rvec_array(rvecBuffer.buffer.data())[buf_pos];
805 if (dim >= npbcdim && dd->nc[dim] > 2)
807 rvec &pos = as_rvec_array(rvecBuffer.buffer.data())[buf_pos];
809 /* No pbc in this dim and more than one domain boundary.
810 * We do a separate check if a charge group didn't move too far.
812 if (((flag & DD_FLAG_FW(d)) &&
813 pos[dim] > cell_x1[dim]) ||
814 ((flag & DD_FLAG_BW(d)) &&
815 pos[dim] < cell_x0[dim]))
817 cg_move_error(fplog, dd, step, cg, dim,
818 (flag & DD_FLAG_FW(d)) ? 1 : 0,
819 fr->cutoff_scheme == ecutsGROUP, 0,
827 /* Check which direction this cg should go */
828 for (d2 = d+1; (d2 < dd->ndim && mc == -1); d2++)
830 if (isDlbOn(dd->comm))
832 /* The cell boundaries for dimension d2 are not equal
833 * for each cell row of the lower dimension(s),
834 * therefore we might need to redetermine where
838 /* If this cg crosses the box boundary in dimension d2
839 * we can use the communicated flag, so we do not
840 * have to worry about pbc.
842 if (!((dd->ci[dim2] == dd->nc[dim2]-1 &&
843 (flag & DD_FLAG_FW(d2))) ||
844 (dd->ci[dim2] == 0 &&
845 (flag & DD_FLAG_BW(d2)))))
847 /* Clear the two flags for this dimension */
848 flag &= ~(DD_FLAG_FW(d2) | DD_FLAG_BW(d2));
849 /* Determine the location of this cg
850 * in lattice coordinates
852 pos_d = rvecBuffer.buffer[buf_pos][dim2];
855 for (d3 = dim2+1; d3 < DIM; d3++)
857 pos_d += pos[d3]*tcm[d3][dim2];
861 GMX_ASSERT(dim2 >= 0 && dim2 < DIM, "Keep the static analyzer happy");
863 /* Check of we are not at the box edge.
864 * pbc is only handled in the first step above,
865 * but this check could move over pbc while
866 * the first step did not due to different rounding.
868 if (pos_d >= cell_x1[dim2] &&
869 dd->ci[dim2] != dd->nc[dim2]-1)
871 flag |= DD_FLAG_FW(d2);
873 else if (pos_d < cell_x0[dim2] &&
876 flag |= DD_FLAG_BW(d2);
878 flagBuffer.buffer[cg*DD_CGIBS + 1] = flag;
881 /* Set to which neighboring cell this cg should go */
882 if (flag & DD_FLAG_FW(d2))
886 else if (flag & DD_FLAG_BW(d2))
888 if (dd->nc[dd->dim[d2]] > 2)
900 nrcg = flag & DD_FLAG_NRCG;
903 /* Set the global charge group index and size */
904 const int globalAtomGroupIndex = flagBuffer.buffer[cg*DD_CGIBS];
905 dd->globalAtomGroupIndices.push_back(globalAtomGroupIndex);
906 dd->atomGrouping_.appendBlock(nrcg);
907 /* Copy the state from the buffer */
908 if (fr->cutoff_scheme == ecutsGROUP)
911 copy_rvec(pos, cg_cm[home_pos_cg]);
916 fr->cginfo[home_pos_cg] = ddcginfo(cginfo_mb,
917 globalAtomGroupIndex);
920 comm->bLocalCG[globalAtomGroupIndex] = TRUE;
923 rvec *rvecPtr = as_rvec_array(rvecBuffer.buffer.data());
924 for (i = 0; i < nrcg; i++)
926 copy_rvec(rvecPtr[buf_pos++],
927 state->x[home_pos_at+i]);
931 for (i = 0; i < nrcg; i++)
933 copy_rvec(rvecPtr[buf_pos++],
934 state->v[home_pos_at+i]);
939 for (i = 0; i < nrcg; i++)
941 copy_rvec(rvecPtr[buf_pos++],
942 state->cg_p[home_pos_at+i]);
950 /* Reallocate the buffers if necessary */
951 if (static_cast<size_t>((ncg[mc] + 1)*DD_CGIBS) > comm->cggl_flag[mc].size())
953 comm->cggl_flag[mc].resize((ncg[mc] + 1)*DD_CGIBS);
955 size_t nvr = ncg[mc] + nat[mc]*nvec;
956 if (nvr + 1 + nrcg*nvec > comm->cgcm_state[mc].size())
958 comm->cgcm_state[mc].resize(nvr + 1 + nrcg*nvec);
960 /* Copy from the receive to the send buffers */
961 memcpy(comm->cggl_flag[mc].data() + ncg[mc]*DD_CGIBS,
962 flagBuffer.buffer.data() + cg*DD_CGIBS,
963 DD_CGIBS*sizeof(int));
964 memcpy(comm->cgcm_state[mc][nvr],
965 rvecBuffer.buffer.data() + buf_pos,
966 (1 + nrcg*nvec)*sizeof(rvec));
967 buf_pos += 1 + nrcg*nvec;
974 /* With sorting (!bCompact) the indices are now only partially up to date
975 * and ncg_home and nat_home are not the real count, since there are
976 * "holes" in the arrays for the charge groups that moved to neighbors.
978 if (fr->cutoff_scheme == ecutsVERLET)
980 /* We need to clear the moved flags for the received atoms,
981 * because the moved buffer will be passed to the nbnxn gridding call.
983 moved = getMovedBuffer(comm, dd->ncg_home, home_pos_cg);
985 for (int i = dd->ncg_home; i < home_pos_cg; i++)
991 dd->ncg_home = home_pos_cg;
992 comm->atomRanges.setEnd(DDAtomRanges::Type::Home, home_pos_at);
994 if (fr->cutoff_scheme == ecutsGROUP && !bCompact)
996 /* We overallocated before, we need to set the right size here */
997 dd_resize_state(state, f, comm->atomRanges.numHomeAtoms());
1003 "Finished repartitioning: cgs moved out %d, new home %d\n",
1004 *ncg_moved, dd->ncg_home-*ncg_moved);