47736d18d154cf7edf1aae04dbe925271a16cf93
[alexxy/gromacs.git] / src / gromacs / mdlib / nsgrid.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5  * Copyright (c) 2001-2004, The GROMACS development team.
6  * Copyright (c) 2013,2014,2015,2017,2018 by the GROMACS development team.
7  * Copyright (c) 2019,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.
11  *
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.
16  *
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.
21  *
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.
26  *
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.
34  *
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.
37  */
38 /* This file is completely threadsafe - keep it that way! */
39 #include "gmxpre.h"
40
41 #include "nsgrid.h"
42
43 #include <cmath>
44 #include <cstdio>
45 #include <cstdlib>
46
47 #include <algorithm>
48
49 #include "gromacs/domdec/dlb.h"
50 #include "gromacs/domdec/domdec.h"
51 #include "gromacs/domdec/domdec_struct.h"
52 #include "gromacs/fileio/pdbio.h"
53 #include "gromacs/gmxlib/network.h"
54 #include "gromacs/math/vec.h"
55 #include "gromacs/mdtypes/forcerec.h"
56 #include "gromacs/pbcutil/pbc.h"
57 #include "gromacs/utility/fatalerror.h"
58 #include "gromacs/utility/futil.h"
59 #include "gromacs/utility/smalloc.h"
60
61 /***********************************
62  *         Grid Routines
63  ***********************************/
64
65 static const char* range_warn =
66         "Explanation: During neighborsearching, we assign each particle to a grid\n"
67         "based on its coordinates. If your system contains collisions or parameter\n"
68         "errors that give particles very high velocities you might end up with some\n"
69         "coordinates being +-Infinity or NaN (not-a-number). Obviously, we cannot\n"
70         "put these on a grid, so this is usually where we detect those errors.\n"
71         "Make sure your system is properly energy-minimized and that the potential\n"
72         "energy seems reasonable before trying again.";
73
74 static void calc_x_av_stddev(int n, rvec* x, rvec av, rvec stddev)
75 {
76     dvec s1, s2;
77     int  i, d;
78
79     clear_dvec(s1);
80     clear_dvec(s2);
81
82     for (i = 0; i < n; i++)
83     {
84         for (d = 0; d < DIM; d++)
85         {
86             s1[d] += x[i][d];
87             s2[d] += x[i][d] * x[i][d];
88         }
89     }
90
91     dsvmul(1.0 / n, s1, s1);
92     dsvmul(1.0 / n, s2, s2);
93
94     for (d = 0; d < DIM; d++)
95     {
96         av[d]     = s1[d];
97         stddev[d] = std::sqrt(s2[d] - s1[d] * s1[d]);
98     }
99 }
100
101 static void get_nsgrid_boundaries_vac(real av, real stddev, real* bound0, real* bound1, real* bdens0, real* bdens1)
102 {
103     /* Set the grid to 2 times the standard deviation of
104      * the charge group centers in both directions.
105      * For a uniform bounded distribution the width is sqrt(3)*stddev,
106      * so all charge groups fall within the width.
107      * For a sphere stddev is r/sqrt(5): 99.2% falls within the width.
108      * For a Gaussian distribution 98% fall within the width.
109      */
110     *bound0 = av - NSGRID_STDDEV_FAC * stddev;
111     *bound1 = av + NSGRID_STDDEV_FAC * stddev;
112
113     *bdens0 = av - GRID_STDDEV_FAC * stddev;
114     *bdens1 = av + GRID_STDDEV_FAC * stddev;
115 }
116
117 static void dd_box_bounds_to_ns_bounds(real box0, real box_size, real* gr0, real* gr1)
118 {
119     real av, stddev;
120
121     /* Redetermine av and stddev from the DD box boundaries */
122     av     = box0 + 0.5 * box_size;
123     stddev = 0.5 * box_size / GRID_STDDEV_FAC;
124
125     *gr0 = av - NSGRID_STDDEV_FAC * stddev;
126     *gr1 = av + NSGRID_STDDEV_FAC * stddev;
127 }
128
129 void get_nsgrid_boundaries(int           nboundeddim,
130                            matrix        box,
131                            gmx_domdec_t* dd,
132                            gmx_ddbox_t*  ddbox,
133                            rvec*         gr0,
134                            rvec*         gr1,
135                            int           ncg,
136                            rvec*         cgcm,
137                            rvec          grid_x0,
138                            rvec          grid_x1,
139                            real*         grid_density)
140 {
141     rvec av, stddev;
142     real vol, bdens0, bdens1;
143     int  d;
144
145     if (nboundeddim < DIM)
146     {
147         calc_x_av_stddev(ncg, cgcm, av, stddev);
148     }
149
150     vol = 1;
151     for (d = 0; d < DIM; d++)
152     {
153         if (d < nboundeddim)
154         {
155             grid_x0[d] = (gr0 != nullptr ? (*gr0)[d] : 0);
156             grid_x1[d] = (gr1 != nullptr ? (*gr1)[d] : box[d][d]);
157             vol *= (grid_x1[d] - grid_x0[d]);
158         }
159         else
160         {
161             if (ddbox == nullptr)
162             {
163                 get_nsgrid_boundaries_vac(av[d], stddev[d], &grid_x0[d], &grid_x1[d], &bdens0, &bdens1);
164             }
165             else
166             {
167                 /* Temporary fix which uses global ddbox boundaries
168                  * for unbounded dimensions.
169                  * Should be replaced by local boundaries, which makes
170                  * the ns grid smaller and does not require global comm.
171                  */
172                 dd_box_bounds_to_ns_bounds(ddbox->box0[d], ddbox->box_size[d], &grid_x0[d], &grid_x1[d]);
173                 bdens0 = grid_x0[d];
174                 bdens1 = grid_x1[d];
175             }
176             /* Check for a DD cell not at a lower edge */
177             if (dd != nullptr && gr0 != nullptr && dd->ci[d] > 0)
178             {
179                 grid_x0[d] = (*gr0)[d];
180                 bdens0     = (*gr0)[d];
181             }
182             /* Check for a DD cell not at a higher edge */
183             if (dd != nullptr && gr1 != nullptr && dd->ci[d] < dd->numCells[d] - 1)
184             {
185                 grid_x1[d] = (*gr1)[d];
186                 bdens1     = (*gr1)[d];
187             }
188             vol *= (bdens1 - bdens0);
189         }
190
191         if (debug)
192         {
193             fprintf(debug, "Set grid boundaries dim %d: %f %f\n", d, grid_x0[d], grid_x1[d]);
194         }
195     }
196
197     *grid_density = ncg / vol;
198 }
199
200 static void set_grid_sizes(matrix              box,
201                            rvec                izones_x0,
202                            rvec                izones_x1,
203                            real                rlist,
204                            const gmx_domdec_t* dd,
205                            const gmx_ddbox_t*  ddbox,
206                            t_grid*             grid,
207                            real                grid_density)
208 {
209     int      i, j;
210     gmx_bool bDD, bDDRect;
211     rvec     izones_size;
212     real     inv_r_ideal, size, add_tric, radd;
213
214     for (i = 0; (i < DIM); i++)
215     {
216         if (debug)
217         {
218             fprintf(debug,
219                     "set_grid_sizes, i-zone bounds for dim %d: %6.3f %6.3f\n",
220                     i,
221                     izones_x0[i],
222                     izones_x1[i]);
223         }
224         izones_size[i] = izones_x1[i] - izones_x0[i];
225     }
226
227     /* Use the ideal number of cg's per cell to set the ideal cell size */
228     inv_r_ideal = std::cbrt(grid_density / grid->ncg_ideal);
229     if (rlist > 0 && inv_r_ideal * rlist < 1)
230     {
231         inv_r_ideal = 1 / rlist;
232     }
233     if (debug)
234     {
235         fprintf(debug, "CG density %f ideal ns cell size %f\n", grid_density, 1 / inv_r_ideal);
236     }
237
238     clear_rvec(grid->cell_offset);
239     for (i = 0; (i < DIM); i++)
240     {
241         /* Initial settings, for DD might change below */
242         grid->cell_offset[i] = izones_x0[i];
243         size                 = izones_size[i];
244
245         bDD = (dd != nullptr) && (dd->numCells[i] > 1);
246         if (!bDD)
247         {
248             bDDRect = FALSE;
249         }
250         else
251         {
252             /* With DD grid cell jumps only the first decomposition
253              * direction has uniform DD cell boundaries.
254              */
255             bDDRect = !((ddbox->tric_dir[i] != 0) || (dd_dlb_is_on(dd) && i != dd->dim[0]));
256
257             radd = rlist;
258             if (i >= ddbox->npbcdim
259                 && (rlist == 0 || izones_x1[i] + radd > ddbox->box0[i] + ddbox->box_size[i]))
260             {
261                 radd = ddbox->box0[i] + ddbox->box_size[i] - izones_x1[i];
262                 if (radd < 0)
263                 {
264                     radd = 0;
265                 }
266             }
267
268             /* With DD we only need a grid of one DD cell size + rlist */
269             if (bDDRect)
270             {
271                 size += radd;
272             }
273             else
274             {
275                 size += radd / ddbox->skew_fac[i];
276             }
277
278             /* Check if the cell boundary in this direction is
279              * perpendicular to the Cartesian axis.
280              * Since grid->npbcdim isan integer that in principle can take
281              * any value, we help the compiler avoid warnings and potentially
282              * optimize by ensuring that j < DIM here.
283              */
284             for (j = i + 1; j < grid->npbcdim && j < DIM; j++)
285             {
286                 if (box[j][i] != 0)
287                 {
288                     /* Correct the offset for the home cell location */
289                     grid->cell_offset[i] += izones_x0[j] * box[j][i] / box[j][j];
290
291                     /* Correct the offset and size for the off-diagonal
292                      * displacement of opposing DD cell corners.
293                      */
294                     /* Without rouding we would need to add:
295                      * box[j][i]*rlist/(dd->skew_fac[i]*box[j][j])
296                      */
297                     /* Determine the shift for the corners of the triclinic box */
298                     add_tric = izones_size[j] * box[j][i] / box[j][j];
299                     if (dd->ndim == 1 && j == ZZ)
300                     {
301                         /* With 1D domain decomposition the cg's are not in
302                          * the triclinic box, but trilinic x-y and rectangular y-z.
303                          * Therefore we need to add the shift from the trilinic
304                          * corner to the corner at y=0.
305                          */
306                         add_tric += -box[YY][XX] * box[ZZ][YY] / box[YY][YY];
307                     }
308                     if (box[j][i] < 0)
309                     {
310                         grid->cell_offset[i] += add_tric;
311                         size -= add_tric;
312                     }
313                     else
314                     {
315                         size += add_tric;
316                     }
317                 }
318             }
319         }
320         if (!bDDRect)
321         {
322             /* No DD or the box is triclinic is this direction:
323              * we will use the normal grid ns that checks all cells
324              * that are within cut-off distance of the i-particle.
325              */
326             grid->n[i] = gmx::roundToInt(size * inv_r_ideal);
327             if (grid->n[i] < 2)
328             {
329                 grid->n[i] = 2;
330             }
331             grid->cell_size[i] = size / grid->n[i];
332             grid->ncpddc[i]    = 0;
333         }
334         else
335         {
336             /* We use grid->ncpddc[i] such that all particles
337              * in one ns cell belong to a single DD cell only.
338              * We can then beforehand exclude certain ns grid cells
339              * for non-home i-particles.
340              */
341             grid->ncpddc[i] = gmx::roundToInt(izones_size[i] * inv_r_ideal);
342             if (grid->ncpddc[i] < 2)
343             {
344                 grid->ncpddc[i] = 2;
345             }
346             grid->cell_size[i] = izones_size[i] / grid->ncpddc[i];
347             grid->n[i]         = grid->ncpddc[i] + static_cast<int>(radd / grid->cell_size[i]) + 1;
348         }
349         if (debug)
350         {
351             fprintf(debug,
352                     "grid dim %d size %d x %f: %f - %f\n",
353                     i,
354                     grid->n[i],
355                     grid->cell_size[i],
356                     grid->cell_offset[i],
357                     grid->cell_offset[i] + grid->n[i] * grid->cell_size[i]);
358         }
359     }
360
361     if (debug)
362     {
363         fprintf(debug,
364                 "CG ncg ideal %d, actual density %.1f\n",
365                 grid->ncg_ideal,
366                 grid_density * grid->cell_size[XX] * grid->cell_size[YY] * grid->cell_size[ZZ]);
367     }
368 }
369
370 t_grid* init_grid(FILE* fplog, t_forcerec* fr)
371 {
372     char*   ptr;
373     t_grid* grid;
374
375     snew(grid, 1);
376
377     grid->npbcdim = numPbcDimensions(fr->pbcType);
378
379     if (fr->pbcType == PbcType::XY && fr->nwall == 2)
380     {
381         grid->nboundeddim = 3;
382     }
383     else
384     {
385         grid->nboundeddim = grid->npbcdim;
386     }
387
388     if (debug)
389     {
390         fprintf(debug, "The coordinates are bounded in %d dimensions\n", grid->nboundeddim);
391     }
392
393     /* The ideal number of cg's per ns grid cell seems to be 10 */
394     grid->ncg_ideal = 10;
395     ptr             = getenv("GMX_NSCELL_NCG");
396     if (ptr)
397     {
398         sscanf(ptr, "%d", &grid->ncg_ideal);
399         if (fplog)
400         {
401             fprintf(fplog, "Set ncg_ideal to %d\n", grid->ncg_ideal);
402         }
403         if (grid->ncg_ideal <= 0)
404         {
405             gmx_fatal(FARGS, "The number of cg's per cell should be > 0");
406         }
407     }
408     if (debug)
409     {
410         fprintf(debug, "Set ncg_ideal to %d\n", grid->ncg_ideal);
411     }
412
413     return grid;
414 }
415
416 void done_grid(t_grid* grid)
417 {
418     if (grid == nullptr)
419     {
420         return;
421     }
422     grid->nr = 0;
423     clear_ivec(grid->n);
424     grid->ncells = 0;
425     sfree(grid->cell_index);
426     sfree(grid->a);
427     sfree(grid->index);
428     sfree(grid->nra);
429     grid->cells_nalloc = 0;
430     sfree(grid->dcx2);
431     sfree(grid->dcy2);
432     sfree(grid->dcz2);
433     grid->dc_nalloc = 0;
434
435     if (debug)
436     {
437         fprintf(debug, "Successfully freed memory for grid pointers.");
438     }
439     sfree(grid);
440 }
441
442 int xyz2ci_(int nry, int nrz, int x, int y, int z)
443 /* Return the cell index */
444 {
445     return (nry * nrz * x + nrz * y + z);
446 }
447
448 void ci2xyz(t_grid* grid, int i, int* x, int* y, int* z)
449 /* Return x,y and z from the cell index */
450 {
451     int ci;
452
453     range_check_mesg(i, 0, grid->nr, range_warn);
454
455     ci = grid->cell_index[i];
456     *x = ci / (grid->n[YY] * grid->n[ZZ]);
457     ci -= (*x) * grid->n[YY] * grid->n[ZZ];
458     *y = ci / grid->n[ZZ];
459     ci -= (*y) * grid->n[ZZ];
460     *z = ci;
461 }
462
463 static int ci_not_used(const ivec n)
464 {
465     /* Return an improbable value */
466     return xyz2ci(n[YY], n[ZZ], 3 * n[XX], 3 * n[YY], 3 * n[ZZ]);
467 }
468
469 static void set_grid_ncg(t_grid* grid, int ncg)
470 {
471     int nr_old, i;
472
473     grid->nr = ncg;
474     if (grid->nr + 1 > grid->nr_alloc)
475     {
476         nr_old         = grid->nr_alloc;
477         grid->nr_alloc = over_alloc_dd(grid->nr) + 1;
478         srenew(grid->cell_index, grid->nr_alloc);
479         for (i = nr_old; i < grid->nr_alloc; i++)
480         {
481             grid->cell_index[i] = 0;
482         }
483         srenew(grid->a, grid->nr_alloc);
484     }
485 }
486
487 void grid_first(FILE*              fplog,
488                 t_grid*            grid,
489                 gmx_domdec_t*      dd,
490                 const gmx_ddbox_t* ddbox,
491                 matrix             box,
492                 rvec               izones_x0,
493                 rvec               izones_x1,
494                 real               rlist,
495                 real               grid_density)
496 {
497     int i, m;
498
499     set_grid_sizes(box, izones_x0, izones_x1, rlist, dd, ddbox, grid, grid_density);
500
501     grid->ncells = grid->n[XX] * grid->n[YY] * grid->n[ZZ];
502
503     if (grid->ncells + 1 > grid->cells_nalloc)
504     {
505         /* Allocate double the size so we have some headroom */
506         grid->cells_nalloc = 2 * grid->ncells;
507         srenew(grid->nra, grid->cells_nalloc + 1);
508         srenew(grid->index, grid->cells_nalloc + 1);
509
510         if (fplog)
511         {
512             fprintf(fplog, "Grid: %d x %d x %d cells\n", grid->n[XX], grid->n[YY], grid->n[ZZ]);
513         }
514     }
515
516     m = std::max(grid->n[XX], std::max(grid->n[YY], grid->n[ZZ]));
517     if (m > grid->dc_nalloc)
518     {
519         /* Allocate with double the initial size for box scaling */
520         grid->dc_nalloc = 2 * m;
521         srenew(grid->dcx2, grid->dc_nalloc);
522         srenew(grid->dcy2, grid->dc_nalloc);
523         srenew(grid->dcz2, grid->dc_nalloc);
524     }
525
526     grid->nr = 0;
527     for (i = 0; (i < grid->ncells); i++)
528     {
529         grid->nra[i] = 0;
530     }
531 }
532
533 static void calc_bor(int cg0, int cg1, int ncg, int CG0[2], int CG1[2])
534 {
535     if (cg1 > ncg)
536     {
537         CG0[0] = cg0;
538         CG1[0] = ncg;
539         CG0[1] = 0;
540         CG1[1] = cg1 - ncg;
541     }
542     else
543     {
544         CG0[0] = cg0;
545         CG1[0] = cg1;
546         CG0[1] = 0;
547         CG1[1] = 0;
548     }
549     if (debug)
550     {
551         int m;
552
553         fprintf(debug, "calc_bor: cg0=%d, cg1=%d, ncg=%d\n", cg0, cg1, ncg);
554         for (m = 0; (m < 2); m++)
555         {
556             fprintf(debug, "CG0[%d]=%d, CG1[%d]=%d\n", m, CG0[m], m, CG1[m]);
557         }
558     }
559 }
560
561 void calc_elemnr(t_grid* grid, int cg0, int cg1, int ncg)
562 {
563     int  CG0[2], CG1[2];
564     int* cell_index = grid->cell_index;
565     int* nra        = grid->nra;
566     int  i, m, ncells;
567     int  ci, not_used;
568
569     ncells = grid->ncells;
570     if (ncells <= 0)
571     {
572         gmx_fatal(FARGS, "Number of grid cells is zero. Probably the system and box collapsed.\n");
573     }
574
575     not_used = ci_not_used(grid->n);
576
577     calc_bor(cg0, cg1, ncg, CG0, CG1);
578     for (m = 0; (m < 2); m++)
579     {
580         for (i = CG0[m]; (i < CG1[m]); i++)
581         {
582             ci = cell_index[i];
583             if (ci != not_used)
584             {
585                 range_check_mesg(ci, 0, ncells, range_warn);
586                 nra[ci]++;
587             }
588         }
589     }
590 }
591
592 void calc_ptrs(t_grid* grid)
593 {
594     int* index = grid->index;
595     int* nra   = grid->nra;
596     int  ix, iy, iz, ci, nr;
597     int  nnra, ncells;
598
599     ncells = grid->ncells;
600     if (ncells <= 0)
601     {
602         gmx_fatal(FARGS, "Number of grid cells is zero. Probably the system and box collapsed.\n");
603     }
604
605     ci = nr = 0;
606     for (ix = 0; (ix < grid->n[XX]); ix++)
607     {
608         for (iy = 0; (iy < grid->n[YY]); iy++)
609         {
610             for (iz = 0; (iz < grid->n[ZZ]); iz++, ci++)
611             {
612                 range_check_mesg(ci, 0, ncells, range_warn);
613                 index[ci] = nr;
614                 nnra      = nra[ci];
615                 nr += nnra;
616                 nra[ci] = 0;
617             }
618         }
619     }
620 }
621
622 void grid_last(t_grid* grid, int cg0, int cg1, int ncg)
623 {
624     int  CG0[2], CG1[2];
625     int  i, m;
626     int  ci, not_used, ind, ncells;
627     int* cell_index = grid->cell_index;
628     int* nra        = grid->nra;
629     int* index      = grid->index;
630     int* a          = grid->a;
631
632     ncells = grid->ncells;
633     if (ncells <= 0)
634     {
635         gmx_fatal(FARGS, "Number of grid cells is zero. Probably the system and box collapsed.\n");
636     }
637
638     not_used = ci_not_used(grid->n);
639
640     calc_bor(cg0, cg1, ncg, CG0, CG1);
641     for (m = 0; (m < 2); m++)
642     {
643         for (i = CG0[m]; (i < CG1[m]); i++)
644         {
645             ci = cell_index[i];
646             if (ci != not_used)
647             {
648                 range_check_mesg(ci, 0, ncells, range_warn);
649                 ind = index[ci] + nra[ci]++;
650                 range_check_mesg(ind, 0, grid->nr, range_warn);
651                 a[ind] = i;
652             }
653         }
654     }
655 }
656
657 void fill_grid(gmx_domdec_zones_t* dd_zones, t_grid* grid, int ncg_tot, int cg0, int cg1, rvec cg_cm[])
658 {
659     int*     cell_index;
660     int      nry, nrz;
661     rvec     n_box, offset;
662     int      zone, ccg0, ccg1, cg, d, not_used;
663     ivec     shift0, useall, b0, b1, ind;
664     gmx_bool bUse;
665
666     if (cg0 == -1)
667     {
668         /* We have already filled the grid up to grid->ncg,
669          * continue from there.
670          */
671         cg0 = grid->nr;
672     }
673
674     set_grid_ncg(grid, ncg_tot);
675
676     cell_index = grid->cell_index;
677
678     /* Initiate cell borders */
679     nry = grid->n[YY];
680     nrz = grid->n[ZZ];
681     for (d = 0; d < DIM; d++)
682     {
683         if (grid->cell_size[d] > 0)
684         {
685             n_box[d] = 1 / grid->cell_size[d];
686         }
687         else
688         {
689             n_box[d] = 0;
690         }
691     }
692     copy_rvec(grid->cell_offset, offset);
693
694     if (debug)
695     {
696         fprintf(debug, "Filling grid from %d to %d\n", cg0, cg1);
697     }
698
699     if (dd_zones == nullptr)
700     {
701         for (cg = cg0; cg < cg1; cg++)
702         {
703             for (d = 0; d < DIM; d++)
704             {
705                 ind[d] = static_cast<int>((cg_cm[cg][d] - offset[d]) * n_box[d]);
706                 /* With pbc we should be done here.
707                  * Without pbc cg's outside the grid
708                  * should be assigned to the closest grid cell.
709                  */
710                 if (ind[d] < 0)
711                 {
712                     ind[d] = 0;
713                 }
714                 else if (ind[d] >= grid->n[d])
715                 {
716                     ind[d] = grid->n[d] - 1;
717                 }
718             }
719             cell_index[cg] = xyz2ci(nry, nrz, ind[XX], ind[YY], ind[ZZ]);
720         }
721     }
722     else
723     {
724         for (zone = 0; zone < dd_zones->n; zone++)
725         {
726             ccg0 = dd_zones->cg_range[zone];
727             ccg1 = dd_zones->cg_range[zone + 1];
728             if (ccg1 <= cg0 || ccg0 >= cg1)
729             {
730                 continue;
731             }
732
733             /* Determine the ns grid cell limits for this DD zone */
734             for (d = 0; d < DIM; d++)
735             {
736                 shift0[d] = dd_zones->shift[zone][d];
737                 useall[d] = static_cast<int>(shift0[d] == 0 || d >= grid->npbcdim);
738                 /* Check if we need to do normal or optimized grid assignments.
739                  * Normal is required for dims without DD or triclinic dims.
740                  * DD edge cell on dims without pbc will be automatically
741                  * be correct, since the shift=0 zones with have b0 and b1
742                  * set to the grid boundaries and there are no shift=1 zones.
743                  */
744                 if (grid->ncpddc[d] == 0)
745                 {
746                     b0[d] = 0;
747                     b1[d] = grid->n[d];
748                 }
749                 else
750                 {
751                     if (shift0[d] == 0)
752                     {
753                         b0[d] = 0;
754                         b1[d] = grid->ncpddc[d];
755                     }
756                     else
757                     {
758                         /* shift = 1 */
759                         b0[d] = grid->ncpddc[d];
760                         b1[d] = grid->n[d];
761                     }
762                 }
763             }
764
765             not_used = ci_not_used(grid->n);
766
767             /* Put all the charge groups of this DD zone on the grid */
768             for (cg = ccg0; cg < ccg1; cg++)
769             {
770                 if (cell_index[cg] == -1)
771                 {
772                     /* This cg has moved to another node */
773                     cell_index[cg] = NSGRID_SIGNAL_MOVED_FAC * grid->ncells;
774                     continue;
775                 }
776
777                 bUse = TRUE;
778                 for (d = 0; d < DIM; d++)
779                 {
780                     ind[d] = static_cast<int>((cg_cm[cg][d] - offset[d]) * n_box[d]);
781                     /* Here we have to correct for rounding problems,
782                      * as this cg_cm to cell index operation is not necessarily
783                      * binary identical to the operation for the DD zone assignment
784                      * and therefore a cg could end up in an unused grid cell.
785                      * For dimensions without pbc we need to check
786                      * for cells on the edge if charge groups are beyond
787                      * the grid and if so, store them in the closest cell.
788                      */
789                     if (ind[d] < b0[d])
790                     {
791                         ind[d] = b0[d];
792                     }
793                     else if (ind[d] >= b1[d])
794                     {
795                         if (useall[d])
796                         {
797                             ind[d] = b1[d] - 1;
798                         }
799                         else
800                         {
801                             /* Charge groups in this DD zone further away than the cut-off
802                              * in direction do not participate in non-bonded interactions.
803                              */
804                             bUse = FALSE;
805                         }
806                     }
807                 }
808                 if (cg > grid->nr_alloc)
809                 {
810                     fprintf(stderr, "WARNING: nra_alloc %d cg0 %d cg1 %d cg %d\n", grid->nr_alloc, cg0, cg1, cg);
811                 }
812                 if (bUse)
813                 {
814                     cell_index[cg] = xyz2ci(nry, nrz, ind[XX], ind[YY], ind[ZZ]);
815                 }
816                 else
817                 {
818                     cell_index[cg] = not_used;
819                 }
820             }
821         }
822     }
823 }
824
825 void check_grid(t_grid* grid)
826 {
827     int ix, iy, iz, ci, cci, nra;
828
829     if (grid->ncells <= 0)
830     {
831         gmx_fatal(FARGS, "Number of grid cells is zero. Probably the system and box collapsed.\n");
832     }
833
834     ci  = 0;
835     cci = 0;
836     for (ix = 0; (ix < grid->n[XX]); ix++)
837     {
838         for (iy = 0; (iy < grid->n[YY]); iy++)
839         {
840             for (iz = 0; (iz < grid->n[ZZ]); iz++, ci++)
841             {
842                 if (ci > 0)
843                 {
844                     nra = grid->index[ci] - grid->index[cci];
845                     if (nra != grid->nra[cci])
846                     {
847                         gmx_fatal(FARGS, "nra=%d, grid->nra=%d, cci=%d", nra, grid->nra[cci], cci);
848                     }
849                 }
850                 cci = xyz2ci(grid->n[YY], grid->n[ZZ], ix, iy, iz);
851                 range_check_mesg(cci, 0, grid->ncells, range_warn);
852
853                 if (cci != ci)
854                 {
855                     gmx_fatal(FARGS, "ci = %d, cci = %d", ci, cci);
856                 }
857             }
858         }
859     }
860 }
861
862 void print_grid(FILE* log, t_grid* grid)
863 {
864     int i, nra, index;
865     int ix, iy, iz, ci;
866
867     fprintf(log, "nr:        %d\n", grid->nr);
868     fprintf(log, "nrx:       %d\n", grid->n[XX]);
869     fprintf(log, "nry:       %d\n", grid->n[YY]);
870     fprintf(log, "nrz:       %d\n", grid->n[ZZ]);
871     fprintf(log, "ncg_ideal: %d\n", grid->ncg_ideal);
872     fprintf(log, "    i  cell_index\n");
873     for (i = 0; (i < grid->nr); i++)
874     {
875         fprintf(log, "%5d  %5d\n", i, grid->cell_index[i]);
876     }
877     fprintf(log, "cells\n");
878     fprintf(log, " ix iy iz   nr  index  cgs...\n");
879     ci = 0;
880     for (ix = 0; (ix < grid->n[XX]); ix++)
881     {
882         for (iy = 0; (iy < grid->n[YY]); iy++)
883         {
884             for (iz = 0; (iz < grid->n[ZZ]); iz++, ci++)
885             {
886                 index = grid->index[ci];
887                 nra   = grid->nra[ci];
888                 fprintf(log, "%3d%3d%3d%5d%5d", ix, iy, iz, nra, index);
889                 for (i = 0; (i < nra); i++)
890                 {
891                     fprintf(log, "%5d", grid->a[index + i]);
892                 }
893                 fprintf(log, "\n");
894             }
895         }
896     }
897     fflush(log);
898 }