2 * This file is part of the GROMACS molecular simulation package.
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.
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.
39 * Implements the GridSet class.
41 * \author Berk Hess <hess@kth.se>
42 * \ingroup module_nbnxm
49 #include "gromacs/mdlib/gmx_omp_nthreads.h"
50 #include "gromacs/mdlib/updategroupscog.h"
51 #include "gromacs/utility/fatalerror.h"
58 //! Returns the number of search grids
59 static int numGrids(const GridSet::DomainSetup
& domainSetup
)
62 if (domainSetup
.doTestParticleInsertion
)
69 for (auto haveDD
: domainSetup
.haveMultipleDomainsPerDim
)
81 GridSet::DomainSetup::DomainSetup(const PbcType pbcType
,
82 const bool doTestParticleInsertion
,
83 const ivec
* numDDCells
,
84 const gmx_domdec_zones_t
* ddZones
) :
86 doTestParticleInsertion(doTestParticleInsertion
),
87 haveMultipleDomains(numDDCells
!= nullptr),
90 for (int d
= 0; d
< DIM
; d
++)
92 haveMultipleDomainsPerDim
[d
] = (numDDCells
!= nullptr && (*numDDCells
)[d
] > 1);
96 GridSet::GridSet(const PbcType pbcType
,
97 const bool doTestParticleInsertion
,
98 const ivec
* numDDCells
,
99 const gmx_domdec_zones_t
* ddZones
,
100 const PairlistType pairlistType
,
102 const int numThreads
,
103 gmx::PinningPolicy pinningPolicy
) :
104 domainSetup_(pbcType
, doTestParticleInsertion
, numDDCells
, ddZones
),
105 grids_(numGrids(domainSetup_
), Grid(pairlistType
, haveFep_
)),
107 numRealAtomsLocal_(0),
108 numRealAtomsTotal_(0),
109 gridWork_(numThreads
)
112 changePinningPolicy(&gridSetData_
.cells
, pinningPolicy
);
113 changePinningPolicy(&gridSetData_
.atomIndices
, pinningPolicy
);
116 void GridSet::setLocalAtomOrder()
118 /* Set the atom order for the home cell (index 0) */
119 const Nbnxm::Grid
& grid
= grids_
[0];
122 for (int cxy
= 0; cxy
< grid
.numColumns(); cxy
++)
124 const int numAtoms
= grid
.numAtomsInColumn(cxy
);
125 int cellIndex
= grid
.firstCellInColumn(cxy
) * grid
.geometry().numAtomsPerCell
;
126 for (int i
= 0; i
< numAtoms
; i
++)
128 gridSetData_
.atomIndices
[cellIndex
] = atomIndex
;
129 gridSetData_
.cells
[atomIndex
] = cellIndex
;
136 void GridSet::putOnGrid(const matrix box
,
138 const rvec lowerCorner
,
139 const rvec upperCorner
,
140 const gmx::UpdateGroupsCog
* updateGroupsCog
,
141 const gmx::Range
<int> atomRange
,
143 gmx::ArrayRef
<const int> atomInfo
,
144 gmx::ArrayRef
<const gmx::RVec
> x
,
145 const int numAtomsMoved
,
147 nbnxn_atomdata_t
* nbat
)
149 Nbnxm::Grid
& grid
= grids_
[gridIndex
];
158 const Nbnxm::Grid
& previousGrid
= grids_
[gridIndex
- 1];
159 cellOffset
= previousGrid
.atomIndexEnd() / previousGrid
.geometry().numAtomsPerCell
;
162 const int n
= atomRange
.size();
164 real maxAtomGroupRadius
;
169 numRealAtomsLocal_
= *atomRange
.end() - numAtomsMoved
;
170 /* We assume that nbnxn_put_on_grid is called first
171 * for the local atoms (gridIndex=0).
173 numRealAtomsTotal_
= *atomRange
.end() - numAtomsMoved
;
175 maxAtomGroupRadius
= (updateGroupsCog
? updateGroupsCog
->maxUpdateGroupRadius() : 0);
179 fprintf(debug
, "natoms_local = %5d atom_density = %5.1f\n", numRealAtomsLocal_
, atomDensity
);
184 const Nbnxm::Grid::Dimensions
& dimsGrid0
= grids_
[0].dimensions();
185 atomDensity
= dimsGrid0
.atomDensity
;
186 maxAtomGroupRadius
= dimsGrid0
.maxAtomGroupRadius
;
188 numRealAtomsTotal_
= std::max(numRealAtomsTotal_
, *atomRange
.end());
191 /* We always use the home zone (grid[0]) for setting the cell size,
192 * since determining densities for non-local zones is difficult.
194 const int ddZone
= (domainSetup_
.doTestParticleInsertion
? 0 : gridIndex
);
195 // grid data used in GPU transfers inherits the gridset pinning policy
196 auto pinPolicy
= gridSetData_
.cells
.get_allocator().pinningPolicy();
197 grid
.setDimensions(ddZone
, n
- numAtomsMoved
, lowerCorner
, upperCorner
, atomDensity
,
198 maxAtomGroupRadius
, haveFep_
, pinPolicy
);
200 for (GridWork
& work
: gridWork_
)
202 work
.numAtomsPerColumn
.resize(grid
.numColumns() + 1);
205 /* Make space for the new cell indices */
206 gridSetData_
.cells
.resize(*atomRange
.end());
208 const int nthread
= gmx_omp_nthreads_get(emntPairsearch
);
209 GMX_ASSERT(nthread
> 0, "We expect the OpenMP thread count to be set");
211 #pragma omp parallel for num_threads(nthread) schedule(static)
212 for (int thread
= 0; thread
< nthread
; thread
++)
216 Grid::calcColumnIndices(grid
.dimensions(), updateGroupsCog
, atomRange
, x
, ddZone
, move
, thread
,
217 nthread
, gridSetData_
.cells
, gridWork_
[thread
].numAtomsPerColumn
);
219 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
222 /* Copy the already computed cell indices to the grid and sort, when needed */
223 grid
.setCellIndices(ddZone
, cellOffset
, &gridSetData_
, gridWork_
, atomRange
, atomInfo
.data(), x
,
224 numAtomsMoved
, nbat
);
228 nbat
->natoms_local
= nbat
->numAtoms();
230 if (gridIndex
== gmx::ssize(grids_
) - 1)
232 /* We are done setting up all grids, we can resize the force buffers */
233 nbat
->resizeForceBuffers();
236 int maxNumColumns
= 0;
237 for (int i
= 0; i
<= gridIndex
; i
++)
239 maxNumColumns
= std::max(maxNumColumns
, grids_
[i
].numColumns());
241 setNumColumnsMax(maxNumColumns
);