AutoPas  3.0.0
Loading...
Searching...
No Matches
ClusterTowerBlock2D.h
Go to the documentation of this file.
1
7#pragma once
8
9#include <array>
10#include <vector>
11
15
16namespace autopas::internal {
17
24template <class Particle_T>
26 public:
36 ClusterTowerBlock2D(const std::array<double, 3> &boxMin, const std::array<double, 3> &boxMax,
37 double interactionLength)
38 : _interactionLength(interactionLength),
39 _boxMin(boxMin),
40 _boxMax(boxMax),
41 _haloBoxMin{utils::ArrayMath::subScalar(boxMin, interactionLength)},
42 _haloBoxMax{utils::ArrayMath::addScalar(boxMax, interactionLength)} {}
47 typename std::vector<ClusterTower<Particle_T>>::iterator begin() { return _towers.begin(); }
52 typename std::vector<ClusterTower<Particle_T>>::const_iterator begin() const { return _towers.begin(); }
57 typename std::vector<ClusterTower<Particle_T>>::iterator end() { return _towers.end(); }
62 typename std::vector<ClusterTower<Particle_T>>::const_iterator end() const { return _towers.end(); }
63
69 ClusterTower<Particle_T> &operator[](size_t i) { return _towers[i]; }
70
76 const ClusterTower<Particle_T> &operator[](size_t i) const { return _towers[i]; }
77
82 size_t size() const { return _towers.size(); }
83
89 void resize(const std::array<double, 2> &towerSideLength, const std::array<size_t, 2> &towersPerDim) {
90 using namespace autopas::utils::ArrayMath::literals;
93 _towerSideLength = towerSideLength;
94 _towerSideLengthReciprocal = 1. / towerSideLength;
95 const auto numTowersPerInteractionLength2D =
96 static_cast_copy_array<int>(ceil(_interactionLength / _towerSideLength));
97 // Sanity check. This is not necessarily a problem with the method but potentially with the way the code is written.
98 if (numTowersPerInteractionLength2D[0] != numTowersPerInteractionLength2D[1]) {
99 AutoPasLog(WARN,
100 "Number of towers per interaction length differs in X vs Y direction! "
101 "The container is built on the assumption that they are the same, "
102 "so from here on the behavior might be undefined. Values: {}",
103 utils::ArrayUtils::to_string(numTowersPerInteractionLength2D));
104 }
105 _numTowersPerInteractionLength =
106 *std::max_element(numTowersPerInteractionLength2D.begin(), numTowersPerInteractionLength2D.end());
107 _towersPerDim = towersPerDim;
108 _towers.resize(_towersPerDim[0] * _towersPerDim[1]);
109
110 // converting indices relies on _towersPerDim to already have the new values.
111 _firstOwnedTowerIndex = towerIndex2DTo1D(_numTowersPerInteractionLength, _numTowersPerInteractionLength);
112 _lastOwnedTowerIndex = towerIndex2DTo1D(_towersPerDim[0] - _numTowersPerInteractionLength,
113 _towersPerDim[1] - _numTowersPerInteractionLength);
114 }
115
120 bool empty() const { return _towers.empty(); }
121
126 void addTower(size_t clusterSize) { _towers.emplace_back(clusterSize); }
127
140 [[nodiscard]] std::tuple<std::array<double, 2>, std::array<size_t, 2>> estimateOptimalGridSideLength(
141 size_t numParticles, size_t clusterSize) const {
142 using namespace autopas::utils::ArrayMath::literals;
145
146 // estimate the grid size for the actual box, then add halo layers as necessary
147 const std::array<double, 3> boxSize = _boxMax - _boxMin;
148 const std::array<double, 2> boxSize2D{boxSize[0], boxSize[1]};
149 if (numParticles == 0) {
150 // We always build at least 3 towers per direction (one owned, two halo)
151 // This is needed for sliced traversals to work correctly.
152 return {boxSize2D, {3, 3}};
153 }
154
155 const double volume = boxSize[0] * boxSize[1] * boxSize[2];
156 // We use double here to avoid back and forth casting
157 // estimate particle density
158 const double density = static_cast<double>(numParticles) / volume;
159 const auto optimalSideLength = std::cbrt(static_cast<double>(clusterSize) / density);
160 // make sure the towers fill the domain exactly
161 const auto numTowersOwned(ceil(boxSize2D / optimalSideLength));
162 const auto towerSideLengthNew = boxSize2D / numTowersOwned;
163 // pad a halo layer of towers in both directions, filling one interaction length each.
164 const auto numTowers = numTowersOwned + (ceil(_interactionLength / towerSideLengthNew) * 2.);
165 // Do not resize the number of towers here!
166 // If we get less towers we need to save the particles in the towers we throw away.
167 return {towerSideLengthNew, static_cast_copy_array<size_t>(numTowers)};
168 }
169
178 [[nodiscard]] std::tuple<std::array<double, 3>, std::array<double, 3>> getTowerBoundingBox(size_t index1D) const {
179 // case: towers are not built yet.
180 if (_towersPerDim[0] == 0) {
181 return {_boxMin, _boxMax};
182 }
183 return getTowerBoundingBox(towerIndex1DTo2D(index1D));
184 }
185
192 std::tuple<std::array<double, 3>, std::array<double, 3>> getTowerBoundingBox(
193 const std::array<size_t, 2> &index2D) const {
194 // case: towers are not built yet.
195 if (_towersPerDim[0] == 0) {
196 return {_boxMin, _boxMax};
197 }
198 // towerBoxMin[0/1] does NOT start at _haloBoxMin[0/1] because the halo towers might extend beyond the halo box.
199 const std::array<double, 3> towerBoxMin{
200 _boxMin[0] - _towerSideLength[0] * _numTowersPerInteractionLength +
201 _towerSideLength[0] * static_cast<double>(index2D[0]),
202 _boxMin[1] - _towerSideLength[1] * _numTowersPerInteractionLength +
203 _towerSideLength[1] * static_cast<double>(index2D[1]),
204 _haloBoxMin[2],
205 };
206 const std::array<double, 3> towerBoxMax{
207 towerBoxMin[0] + _towerSideLength[0],
208 towerBoxMin[1] + _towerSideLength[1],
209 _haloBoxMax[2],
210 };
211 return {towerBoxMin, towerBoxMax};
212 }
213
220 [[nodiscard]] std::array<size_t, 2> getTowerIndex2DAtPosition(const std::array<double, 3> &pos) const {
221 // special case: Towers are not yet built, then everything is in this one tower.
222 if (_towers.size() == 1) {
223 return {0, 0};
224 }
225
226 std::array<size_t, 2> towerIndex2D{};
227
228 for (int dim = 0; dim < 2; dim++) {
229 const auto towerDimIndex =
230 static_cast<long int>(std::floor((pos[dim] - _boxMin[dim]) * _towerSideLengthReciprocal[dim])) +
231 _numTowersPerInteractionLength;
232 const auto towerDimIndexNonNegative = static_cast<size_t>(std::max(towerDimIndex, 0l));
233 const auto towerDimIndexNonLargerValue = std::min(towerDimIndexNonNegative, _towersPerDim[dim] - 1);
234 towerIndex2D[dim] = towerDimIndexNonLargerValue;
236 // flag manager
237 if (pos[dim] >= _haloBoxMax[dim]) {
238 towerIndex2D[dim] = _towersPerDim[dim] - 1;
239 } else if (pos[dim] < _haloBoxMin[dim]) {
240 towerIndex2D[dim] = 0;
241 }
242 }
243
244 return towerIndex2D;
245 }
246
252 [[nodiscard]] size_t getTowerIndex1DAtPosition(const std::array<double, 3> &pos) const {
253 const auto [x, y] = getTowerIndex2DAtPosition(pos);
254 return towerIndex2DTo1D(x, y);
255 }
256
262 ClusterTower<Particle_T> &getTowerAtPosition(const std::array<double, 3> &pos) {
263 const auto [x, y] = getTowerIndex2DAtPosition(pos);
264 return getTowerByIndex2D(x, y);
265 }
266
273 ClusterTower<Particle_T> &getTowerByIndex2D(const size_t x, const size_t y) {
274 return _towers[towerIndex2DTo1D(x, y)];
275 }
276
284 [[nodiscard]] size_t towerIndex2DTo1D(const size_t x, const size_t y) const { return x + y * _towersPerDim[0]; }
285
292 [[nodiscard]] std::array<size_t, 2> towerIndex1DTo2D(size_t index) const {
293 if (_towersPerDim[0] == 0) {
294 return {0, 0};
295 } else {
296 return {index % _towersPerDim[0], index / _towersPerDim[0]};
297 }
298 }
299
304 size_t getFirstOwnedTowerIndex() const { return _firstOwnedTowerIndex; }
309 size_t getLastOwnedTowerIndex() const { return _lastOwnedTowerIndex; }
314 double getInteractionLength() const { return _interactionLength; }
319 int getNumTowersPerInteractionLength() const { return _numTowersPerInteractionLength; }
324 const std::array<double, 3> &getBoxMin() const { return _boxMin; }
329 const std::array<double, 3> &getBoxMax() const { return _boxMax; }
334 const std::array<double, 3> &getHaloBoxMin() const { return _haloBoxMin; }
339 const std::array<double, 3> &getHaloBoxMax() const { return _haloBoxMax; }
344 const std::vector<ClusterTower<Particle_T>> &getTowers() const { return _towers; }
349 std::vector<ClusterTower<Particle_T>> &getTowersRef() { return _towers; }
354 const std::array<size_t, 2> &getTowersPerDim() const { return _towersPerDim; }
359 const std::array<double, 2> &getTowerSideLength() const { return _towerSideLength; }
364 const std::array<double, 2> &getTowerSideLengthReciprocal() const { return _towerSideLengthReciprocal; }
365
366 bool cellCanContainHaloParticles(index_t index1d) const override {
367 // Always true because towers cover the whole z dimension
368 return true;
369 }
370
371 bool cellCanContainOwnedParticles(index_t index1d) const override {
372 // check if the tower is strictly in the halo region
373 if (index1d < _firstOwnedTowerIndex or index1d > _lastOwnedTowerIndex) {
374 return false;
375 }
376 const auto index2D = towerIndex1DTo2D(index1d);
377 bool isHaloTower = false;
378 for (size_t i = 0; i < index2D.size(); ++i) {
379 if (index2D[i] < _numTowersPerInteractionLength or
380 index2D[i] >= _towersPerDim[i] - _numTowersPerInteractionLength) {
381 isHaloTower = true;
382 break;
383 }
384 }
385 return not isHaloTower;
386 }
387
388 private:
392 size_t _firstOwnedTowerIndex{};
396 size_t _lastOwnedTowerIndex{};
400 double _interactionLength;
405 int _numTowersPerInteractionLength{};
406
410 std::array<double, 3> _boxMin;
411
415 std::array<double, 3> _boxMax;
416
420 std::array<double, 3> _haloBoxMin;
421
425 std::array<double, 3> _haloBoxMax;
426
430 std::vector<ClusterTower<Particle_T>> _towers;
431
435 std::array<size_t, 2> _towersPerDim{};
436
440 std::array<double, 2> _towerSideLength{0.};
441
445 std::array<double, 2> _towerSideLengthReciprocal{0.};
446};
447} // namespace autopas::internal
#define AutoPasLog(lvl, fmt,...)
Macro for logging providing common meta information without filename.
Definition: Logger.h:24
Interface class to handle cell borders and cell types of cells.
Definition: CellBorderAndFlagManager.h:17
std::size_t index_t
The index type to access the particle cells.
Definition: CellBorderAndFlagManager.h:22
Class to manage the grid of towers for the Verlet Cluster Lists container.
Definition: ClusterTowerBlock2D.h:25
std::vector< ClusterTower< Particle_T > >::const_iterator end() const
End iterator over towers.
Definition: ClusterTowerBlock2D.h:62
size_t getTowerIndex1DAtPosition(const std::array< double, 3 > &pos) const
Return the 1D index of the tower at a given position.
Definition: ClusterTowerBlock2D.h:252
size_t towerIndex2DTo1D(const size_t x, const size_t y) const
Returns the 1D index for the given 2D-coordinates of a tower.
Definition: ClusterTowerBlock2D.h:284
const std::array< double, 3 > & getBoxMax() const
Getter.
Definition: ClusterTowerBlock2D.h:329
bool empty() const
Indicator if the block contains any towers.
Definition: ClusterTowerBlock2D.h:120
const std::array< double, 3 > & getHaloBoxMin() const
Getter.
Definition: ClusterTowerBlock2D.h:334
std::vector< ClusterTower< Particle_T > > & getTowersRef()
Getter for a mutable reference.
Definition: ClusterTowerBlock2D.h:349
const std::array< double, 3 > & getHaloBoxMax() const
Getter.
Definition: ClusterTowerBlock2D.h:339
size_t size() const
Return the number of towers.
Definition: ClusterTowerBlock2D.h:82
size_t getFirstOwnedTowerIndex() const
Getter.
Definition: ClusterTowerBlock2D.h:304
const std::array< double, 2 > & getTowerSideLength() const
Getter.
Definition: ClusterTowerBlock2D.h:359
std::vector< ClusterTower< Particle_T > >::iterator begin()
Start iterator over towers.
Definition: ClusterTowerBlock2D.h:47
const std::array< double, 3 > & getBoxMin() const
Getter.
Definition: ClusterTowerBlock2D.h:324
std::vector< ClusterTower< Particle_T > >::iterator end()
End iterator over towers.
Definition: ClusterTowerBlock2D.h:57
bool cellCanContainOwnedParticles(index_t index1d) const override
Checks if the cell with the one-dimensional index index1d can contain owned particles.
Definition: ClusterTowerBlock2D.h:371
std::vector< ClusterTower< Particle_T > >::const_iterator begin() const
Start iterator over towers.
Definition: ClusterTowerBlock2D.h:52
void resize(const std::array< double, 2 > &towerSideLength, const std::array< size_t, 2 > &towersPerDim)
Resize the internal grid and storage.
Definition: ClusterTowerBlock2D.h:89
std::array< size_t, 2 > getTowerIndex2DAtPosition(const std::array< double, 3 > &pos) const
Returns the 2D index of the tower in the tower grid the given 3D coordinates are in.
Definition: ClusterTowerBlock2D.h:220
const ClusterTower< Particle_T > & operator[](size_t i) const
Access operator for towers.
Definition: ClusterTowerBlock2D.h:76
std::tuple< std::array< double, 3 >, std::array< double, 3 > > getTowerBoundingBox(const std::array< size_t, 2 > &index2D) const
Calculates the low and high corner of a tower given by its 2D grid index.
Definition: ClusterTowerBlock2D.h:192
size_t getLastOwnedTowerIndex() const
Getter.
Definition: ClusterTowerBlock2D.h:309
std::tuple< std::array< double, 3 >, std::array< double, 3 > > getTowerBoundingBox(size_t index1D) const
Calculates the low and high corner of a tower given by its index.
Definition: ClusterTowerBlock2D.h:178
void addTower(size_t clusterSize)
Construct a new tower at the end of the storage.
Definition: ClusterTowerBlock2D.h:126
const std::array< size_t, 2 > & getTowersPerDim() const
Getter.
Definition: ClusterTowerBlock2D.h:354
const std::vector< ClusterTower< Particle_T > > & getTowers() const
Getter.
Definition: ClusterTowerBlock2D.h:344
const std::array< double, 2 > & getTowerSideLengthReciprocal() const
Getter.
Definition: ClusterTowerBlock2D.h:364
bool cellCanContainHaloParticles(index_t index1d) const override
Checks if the cell with the one-dimensional index index1d can contain halo particles.
Definition: ClusterTowerBlock2D.h:366
double getInteractionLength() const
Getter.
Definition: ClusterTowerBlock2D.h:314
ClusterTowerBlock2D(const std::array< double, 3 > &boxMin, const std::array< double, 3 > &boxMax, double interactionLength)
Constructor.
Definition: ClusterTowerBlock2D.h:36
std::tuple< std::array< double, 2 >, std::array< size_t, 2 > > estimateOptimalGridSideLength(size_t numParticles, size_t clusterSize) const
Estimates the optimal 2D tower grid side length.
Definition: ClusterTowerBlock2D.h:140
ClusterTower< Particle_T > & getTowerByIndex2D(const size_t x, const size_t y)
Returns a reference to the tower for the given tower grid coordinates.
Definition: ClusterTowerBlock2D.h:273
int getNumTowersPerInteractionLength() const
Getter.
Definition: ClusterTowerBlock2D.h:319
ClusterTower< Particle_T > & operator[](size_t i)
Access operator for towers.
Definition: ClusterTowerBlock2D.h:69
ClusterTower< Particle_T > & getTowerAtPosition(const std::array< double, 3 > &pos)
Return a reference to the tower at a given position in the simulation coordinate system (e....
Definition: ClusterTowerBlock2D.h:262
std::array< size_t, 2 > towerIndex1DTo2D(size_t index) const
Returns the 2D index for the given 1D index of a tower.
Definition: ClusterTowerBlock2D.h:292
This class represents one tower for clusters in the VerletClusterLists container.
Definition: ClusterTower.h:43
This namespace is used for implementation specifics.
Definition: CellFunctor.h:14
constexpr std::array< T, SIZE > ceil(const std::array< T, SIZE > &a)
For each element in a, computes the smallest integer value not less than the element.
Definition: ArrayMath.h:316
constexpr std::array< output_t, SIZE > static_cast_copy_array(const std::array< input_t, SIZE > &a)
Creates a new array by performing an element-wise static_cast<>.
Definition: ArrayUtils.h:81
void to_string(std::ostream &os, const Container &container, const std::string &delimiter, const std::array< std::string, 2 > &surround, Fun elemToString)
Generates a string representation of a container which fulfills the Container requirement (provide cb...
Definition: ArrayUtils.h:102