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