75dc905fd5f14e4a6ee13b400b0e385158f6e135
[alexxy/gromacs.git] / src / gromacs / nbnxm / gridset.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2019, 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.
8  *
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.
13  *
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.
18  *
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.
23  *
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.
31  *
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.
34  */
35
36 /*! \internal \file
37  *
38  * \brief
39  * Implements the GridSet class.
40  *
41  * \author Berk Hess <hess@kth.se>
42  * \ingroup module_nbnxm
43  */
44
45 #include "gmxpre.h"
46
47 #include "gridset.h"
48
49 #include "gromacs/domdec/domdec_struct.h"
50 #include "gromacs/mdlib/gmx_omp_nthreads.h"
51 #include "gromacs/mdlib/updategroupscog.h"
52 #include "gromacs/nbnxm/nbnxm.h"
53 #include "gromacs/utility/fatalerror.h"
54
55 #include "internal.h"
56
57 namespace Nbnxm
58 {
59
60 //! Returns the number of DD zones
61 static int numDDZones(const std::array<bool, DIM> &haveDomDecPerDim)
62 {
63     int  numDDZones = 1;
64     for (auto haveDD : haveDomDecPerDim)
65     {
66         if (haveDD)
67         {
68             numDDZones *= 2;
69         }
70     }
71
72     return numDDZones;
73 }
74
75 GridSet::GridSet(const std::array<bool, DIM> &haveDomDecPerDim,
76                  const PairlistType           pairlistType,
77                  const bool                   haveFep,
78                  const int                    numThreads) :
79     grids_(numDDZones(haveDomDecPerDim), pairlistType),
80     haveFep_(haveFep),
81     numRealAtomsLocal_(0),
82     numRealAtomsTotal_(0),
83     gridWork_(numThreads)
84 {
85     clear_mat(box_);
86 }
87
88 void GridSet::setLocalAtomOrder()
89 {
90     /* Set the atom order for the home cell (index 0) */
91     const Nbnxm::Grid &grid = grids_[0];
92
93     int                atomIndex = 0;
94     for (int cxy = 0; cxy < grid.numColumns(); cxy++)
95     {
96         const int numAtoms  = grid.numAtomsInColumn(cxy);
97         int       cellIndex = grid.firstCellInColumn(cxy)*grid.geometry().numAtomsPerCell;
98         for (int i = 0; i < numAtoms; i++)
99         {
100             atomIndices_[cellIndex] = atomIndex;
101             cells_[atomIndex]       = cellIndex;
102             atomIndex++;
103             cellIndex++;
104         }
105     }
106 }
107
108 // TODO: Move to gridset.cpp
109 void GridSet::putOnGrid(const matrix                    box,
110                         const int                       ddZone,
111                         const rvec                      lowerCorner,
112                         const rvec                      upperCorner,
113                         const gmx::UpdateGroupsCog     *updateGroupsCog,
114                         const int                       atomStart,
115                         const int                       atomEnd,
116                         real                            atomDensity,
117                         const int                      *atinfo,
118                         gmx::ArrayRef<const gmx::RVec>  x,
119                         const int                       numAtomsMoved,
120                         const int                      *move,
121                         nbnxn_atomdata_t               *nbat)
122 {
123     Nbnxm::Grid  &grid = grids_[ddZone];
124
125     int           cellOffset;
126     if (ddZone == 0)
127     {
128         cellOffset = 0;
129     }
130     else
131     {
132         const Nbnxm::Grid &previousGrid = grids_[ddZone - 1];
133         cellOffset = previousGrid.atomIndexEnd()/previousGrid.geometry().numAtomsPerCell;
134     }
135
136     const int n = atomEnd - atomStart;
137
138     real      maxAtomGroupRadius;
139     if (ddZone == 0)
140     {
141         copy_mat(box, box_);
142
143         numRealAtomsLocal_ = atomEnd - numAtomsMoved;
144         /* We assume that nbnxn_put_on_grid is called first
145          * for the local atoms (ddZone=0).
146          */
147         numRealAtomsTotal_ = atomEnd - numAtomsMoved;
148
149         maxAtomGroupRadius = (updateGroupsCog ? updateGroupsCog->maxUpdateGroupRadius() : 0);
150
151         if (debug)
152         {
153             fprintf(debug, "natoms_local = %5d atom_density = %5.1f\n",
154                     numRealAtomsLocal_, atomDensity);
155         }
156     }
157     else
158     {
159         const Nbnxm::Grid::Dimensions &dimsGrid0 = grids_[0].dimensions();
160         atomDensity        = dimsGrid0.atomDensity;
161         maxAtomGroupRadius = dimsGrid0.maxAtomGroupRadius;
162
163         numRealAtomsTotal_ = std::max(numRealAtomsTotal_, atomEnd);
164     }
165
166     /* We always use the home zone (grid[0]) for setting the cell size,
167      * since determining densities for non-local zones is difficult.
168      */
169     grid.setDimensions(ddZone, n - numAtomsMoved,
170                        lowerCorner, upperCorner,
171                        atomDensity,
172                        maxAtomGroupRadius,
173                        haveFep_);
174
175     for (GridWork &work : gridWork_)
176     {
177         work.numAtomsPerColumn.resize(grid.numColumns() + 1);
178     }
179
180     /* Make space for the new cell indices */
181     cells_.resize(atomEnd);
182
183     const int nthread = gmx_omp_nthreads_get(emntPairsearch);
184
185 #pragma omp parallel for num_threads(nthread) schedule(static)
186     for (int thread = 0; thread < nthread; thread++)
187     {
188         try
189         {
190             Grid::calcColumnIndices(grid.dimensions(),
191                                     updateGroupsCog,
192                                     atomStart, atomEnd, x,
193                                     ddZone, move, thread, nthread,
194                                     cells_, gridWork_[thread].numAtomsPerColumn);
195         }
196         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
197     }
198
199     GridSetData gridSetData = getGridSetData();
200
201     /* Copy the already computed cell indices to the grid and sort, when needed */
202     grid.setCellIndices(ddZone, cellOffset, &gridSetData, gridWork_,
203                         atomStart, atomEnd, atinfo, x, numAtomsMoved, nbat);
204
205     if (ddZone == 0)
206     {
207         nbat->natoms_local = nbat->numAtoms();
208     }
209     if (ddZone == gmx::ssize(grids_) - 1)
210     {
211         /* We are done setting up all grids, we can resize the force buffers */
212         nbat->resizeForceBuffers();
213     }
214 }
215
216 } // namespace Nbnxm
217
218 // TODO: Move this function to a proper location after refactoring nbnxn_search
219 void nbnxn_put_on_grid(nonbonded_verlet_t             *nb_verlet,
220                        const matrix                    box,
221                        int                             ddZone,
222                        const rvec                      lowerCorner,
223                        const rvec                      upperCorner,
224                        const gmx::UpdateGroupsCog     *updateGroupsCog,
225                        int                             atomStart,
226                        int                             atomEnd,
227                        real                            atomDensity,
228                        const int                      *atinfo,
229                        gmx::ArrayRef<const gmx::RVec>  x,
230                        int                             numAtomsMoved,
231                        const int                      *move)
232 {
233     nbnxn_search &nbs = *nb_verlet->nbs;
234
235     nbs_cycle_start(&nbs.cc[enbsCCgrid]);
236
237     nbs.gridSet_.putOnGrid(box, ddZone, lowerCorner, upperCorner,
238                            updateGroupsCog, atomStart, atomEnd, atomDensity,
239                            atinfo, x, numAtomsMoved, move,
240                            nb_verlet->nbat.get());
241
242     nbs_cycle_stop(&nbs.cc[enbsCCgrid]);
243 }
244
245 /* Calls nbnxn_put_on_grid for all non-local domains */
246 void nbnxn_put_on_grid_nonlocal(nonbonded_verlet_t              *nbv,
247                                 const struct gmx_domdec_zones_t *zones,
248                                 const int                       *atinfo,
249                                 gmx::ArrayRef<const gmx::RVec>   x)
250 {
251     for (int zone = 1; zone < zones->n; zone++)
252     {
253         rvec c0, c1;
254         for (int d = 0; d < DIM; d++)
255         {
256             c0[d] = zones->size[zone].bb_x0[d];
257             c1[d] = zones->size[zone].bb_x1[d];
258         }
259
260         nbnxn_put_on_grid(nbv, nullptr,
261                           zone, c0, c1,
262                           nullptr,
263                           zones->cg_range[zone],
264                           zones->cg_range[zone+1],
265                           -1,
266                           atinfo,
267                           x,
268                           0, nullptr);
269     }
270 }
271
272 gmx::ArrayRef<const int> nbnxn_get_atomorder(const nbnxn_search *nbs)
273 {
274     /* Return the atom order for the home cell (index 0) */
275     const Nbnxm::Grid &grid       = nbs->gridSet().grids()[0];
276
277     const int          numIndices = grid.atomIndexEnd() - grid.firstAtomInColumn(0);
278
279     return gmx::constArrayRefFromArray(nbs->gridSet().atomIndices().data(), numIndices);
280 }
281
282 void nonbonded_verlet_t::setLocalAtomOrder()
283 {
284     nbs->gridSet_.setLocalAtomOrder();
285 }
286
287 void nonbonded_verlet_t::getLocalNumCells(int *numCellsX,
288                                           int *numCellsY) const
289 {
290     nbs->gridSet().getLocalNumCells(numCellsX, numCellsY);
291 }
292
293 gmx::ArrayRef<const int> nbnxn_get_gridindices(const nbnxn_search* nbs)
294 {
295     return nbs->gridSet().cells();
296 }