Expand documentation for nbnxn_put_on_grid()
[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/mdlib/gmx_omp_nthreads.h"
50 #include "gromacs/mdlib/updategroupscog.h"
51 #include "gromacs/utility/fatalerror.h"
52
53 #include "atomdata.h"
54
55 namespace Nbnxm
56 {
57
58 //! Returns the number of search grids
59 static int numGrids(const GridSet::DomainSetup &domainSetup)
60 {
61     int numGrids;
62     if (domainSetup.doTestParticleInsertion)
63     {
64         numGrids = 2;
65     }
66     else
67     {
68         numGrids = 1;
69         for (auto haveDD : domainSetup.haveMultipleDomainsPerDim)
70         {
71             if (haveDD)
72             {
73                 numGrids *= 2;
74             }
75         }
76     }
77
78     return numGrids;
79 }
80
81 GridSet::DomainSetup::DomainSetup(const int                 ePBC,
82                                   const bool                doTestParticleInsertion,
83                                   const ivec               *numDDCells,
84                                   const gmx_domdec_zones_t *ddZones) :
85     ePBC(ePBC),
86     doTestParticleInsertion(doTestParticleInsertion),
87     haveMultipleDomains(numDDCells != nullptr),
88     zones(ddZones)
89 {
90     for (int d = 0; d < DIM; d++)
91     {
92         haveMultipleDomainsPerDim[d] = (numDDCells != nullptr && (*numDDCells)[d] > 1);
93     }
94 }
95
96 GridSet::GridSet(const int                 ePBC,
97                  const bool                doTestParticleInsertion,
98                  const ivec               *numDDCells,
99                  const gmx_domdec_zones_t *ddZones,
100                  const PairlistType        pairlistType,
101                  const bool                haveFep,
102                  const int                 numThreads,
103                  gmx::PinningPolicy        pinningPolicy) :
104     domainSetup_(ePBC, doTestParticleInsertion, numDDCells, ddZones),
105     grids_(numGrids(domainSetup_), Grid(pairlistType, haveFep_)),
106     haveFep_(haveFep),
107     numRealAtomsLocal_(0),
108     numRealAtomsTotal_(0),
109     gridWork_(numThreads)
110 {
111     clear_mat(box_);
112     changePinningPolicy(&gridSetData_.cells, pinningPolicy);
113     changePinningPolicy(&gridSetData_.atomIndices, pinningPolicy);
114 }
115
116 void GridSet::setLocalAtomOrder()
117 {
118     /* Set the atom order for the home cell (index 0) */
119     const Nbnxm::Grid &grid = grids_[0];
120
121     int                atomIndex = 0;
122     for (int cxy = 0; cxy < grid.numColumns(); cxy++)
123     {
124         const int numAtoms  = grid.numAtomsInColumn(cxy);
125         int       cellIndex = grid.firstCellInColumn(cxy)*grid.geometry().numAtomsPerCell;
126         for (int i = 0; i < numAtoms; i++)
127         {
128             gridSetData_.atomIndices[cellIndex] = atomIndex;
129             gridSetData_.cells[atomIndex]       = cellIndex;
130             atomIndex++;
131             cellIndex++;
132         }
133     }
134 }
135
136 void GridSet::putOnGrid(const matrix                    box,
137                         const int                       gridIndex,
138                         const rvec                      lowerCorner,
139                         const rvec                      upperCorner,
140                         const gmx::UpdateGroupsCog     *updateGroupsCog,
141                         const int                       atomStart,
142                         const int                       atomEnd,
143                         real                            atomDensity,
144                         gmx::ArrayRef<const int>        atomInfo,
145                         gmx::ArrayRef<const gmx::RVec>  x,
146                         const int                       numAtomsMoved,
147                         const int                      *move,
148                         nbnxn_atomdata_t               *nbat)
149 {
150     Nbnxm::Grid  &grid = grids_[gridIndex];
151
152     int           cellOffset;
153     if (gridIndex == 0)
154     {
155         cellOffset = 0;
156     }
157     else
158     {
159         const Nbnxm::Grid &previousGrid = grids_[gridIndex - 1];
160         cellOffset = previousGrid.atomIndexEnd()/previousGrid.geometry().numAtomsPerCell;
161     }
162
163     const int n = atomEnd - atomStart;
164
165     real      maxAtomGroupRadius;
166     if (gridIndex == 0)
167     {
168         copy_mat(box, box_);
169
170         numRealAtomsLocal_ = atomEnd - numAtomsMoved;
171         /* We assume that nbnxn_put_on_grid is called first
172          * for the local atoms (gridIndex=0).
173          */
174         numRealAtomsTotal_ = atomEnd - numAtomsMoved;
175
176         maxAtomGroupRadius = (updateGroupsCog ? updateGroupsCog->maxUpdateGroupRadius() : 0);
177
178         if (debug)
179         {
180             fprintf(debug, "natoms_local = %5d atom_density = %5.1f\n",
181                     numRealAtomsLocal_, atomDensity);
182         }
183     }
184     else
185     {
186         const Nbnxm::Grid::Dimensions &dimsGrid0 = grids_[0].dimensions();
187         atomDensity        = dimsGrid0.atomDensity;
188         maxAtomGroupRadius = dimsGrid0.maxAtomGroupRadius;
189
190         numRealAtomsTotal_ = std::max(numRealAtomsTotal_, atomEnd);
191     }
192
193     /* We always use the home zone (grid[0]) for setting the cell size,
194      * since determining densities for non-local zones is difficult.
195      */
196     const int ddZone = (domainSetup_.doTestParticleInsertion ? 0 : gridIndex);
197     // grid data used in GPU transfers inherits the gridset pinning policy
198     auto      pinPolicy = gridSetData_.cells.get_allocator().pinningPolicy();
199     grid.setDimensions(ddZone, n - numAtomsMoved,
200                        lowerCorner, upperCorner,
201                        atomDensity,
202                        maxAtomGroupRadius,
203                        haveFep_,
204                        pinPolicy);
205
206     for (GridWork &work : gridWork_)
207     {
208         work.numAtomsPerColumn.resize(grid.numColumns() + 1);
209     }
210
211     /* Make space for the new cell indices */
212     gridSetData_.cells.resize(atomEnd);
213
214     const int nthread = gmx_omp_nthreads_get(emntPairsearch);
215     GMX_ASSERT(nthread > 0, "We expect the OpenMP thread count to be set");
216
217 #pragma omp parallel for num_threads(nthread) schedule(static)
218     for (int thread = 0; thread < nthread; thread++)
219     {
220         try
221         {
222             Grid::calcColumnIndices(grid.dimensions(),
223                                     updateGroupsCog,
224                                     atomStart, atomEnd, x,
225                                     ddZone, move, thread, nthread,
226                                     gridSetData_.cells,
227                                     gridWork_[thread].numAtomsPerColumn);
228         }
229         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
230     }
231
232     /* Copy the already computed cell indices to the grid and sort, when needed */
233     grid.setCellIndices(ddZone, cellOffset, &gridSetData_, gridWork_,
234                         atomStart, atomEnd, atomInfo.data(), x, numAtomsMoved, nbat);
235
236     if (gridIndex == 0)
237     {
238         nbat->natoms_local = nbat->numAtoms();
239     }
240     if (gridIndex == gmx::ssize(grids_) - 1)
241     {
242         /* We are done setting up all grids, we can resize the force buffers */
243         nbat->resizeForceBuffers();
244     }
245
246     int maxNumColumns = 0;
247     for (int i = 0; i <= gridIndex; i++)
248     {
249         maxNumColumns = std::max(maxNumColumns, grids_[i].numColumns());
250     }
251     setNumColumnsMax(maxNumColumns);
252 }
253
254 } // namespace Nbnxm