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 return {boxSize2D, {1, 1}};
151 }
152
153 const double volume = boxSize[0] * boxSize[1] * boxSize[2];
154 // We use double here to avoid back and forth casting
155 // estimate particle density
156 const double density = static_cast<double>(numParticles) / volume;
157 const auto optimalSideLength = std::cbrt(static_cast<double>(clusterSize) / density);
158 // make sure the towers fill the domain exactly
159 const auto numTowersOwned(ceil(boxSize2D / optimalSideLength));
160 const auto towerSideLengthNew = boxSize2D / numTowersOwned;
161 // pad a halo layer of towers in both directions, filling one interaction length each.
162 const auto numTowers = numTowersOwned + (ceil(_interactionLength / towerSideLengthNew) * 2.);
163 // Do not resize the number of towers here!
164 // If we get less towers we need to save the particles in the towers we throw away.
165 return {towerSideLengthNew, static_cast_copy_array<size_t>(numTowers)};
166 }
167
176 [[nodiscard]] std::tuple<std::array<double, 3>, std::array<double, 3>> getTowerBoundingBox(size_t index1D) const {
177 // case: towers are not built yet.
178 if (_towersPerDim[0] == 0) {
179 return {_boxMin, _boxMax};
180 }
181 return getTowerBoundingBox(towerIndex1DTo2D(index1D));
182 }
183
190 std::tuple<std::array<double, 3>, std::array<double, 3>> getTowerBoundingBox(
191 const std::array<size_t, 2> &index2D) const {
192 // case: towers are not built yet.
193 if (_towersPerDim[0] == 0) {
194 return {_boxMin, _boxMax};
195 }
196 // towerBoxMin[0/1] does NOT start at _haloBoxMin[0/1] because the halo towers might extend beyond the halo box.
197 const std::array<double, 3> towerBoxMin{
198 _boxMin[0] - _towerSideLength[0] * _numTowersPerInteractionLength +
199 _towerSideLength[0] * static_cast<double>(index2D[0]),
200 _boxMin[1] - _towerSideLength[1] * _numTowersPerInteractionLength +
201 _towerSideLength[1] * static_cast<double>(index2D[1]),
202 _haloBoxMin[2],
203 };
204 const std::array<double, 3> towerBoxMax{
205 towerBoxMin[0] + _towerSideLength[0],
206 towerBoxMin[1] + _towerSideLength[1],
207 _haloBoxMax[2],
208 };
209 return {towerBoxMin, towerBoxMax};
210 }
211
218 [[nodiscard]] std::array<size_t, 2> getTowerIndex2DAtPosition(const std::array<double, 3> &pos) const {
219 // special case: Towers are not yet built, then everything is in this one tower.
220 if (_towers.size() == 1) {
221 return {0, 0};
222 }
223
224 std::array<size_t, 2> towerIndex2D{};
225
226 for (int dim = 0; dim < 2; dim++) {
227 const auto towerDimIndex =
228 static_cast<long int>(std::floor((pos[dim] - _boxMin[dim]) * _towerSideLengthReciprocal[dim])) +
229 _numTowersPerInteractionLength;
230 const auto towerDimIndexNonNegative = static_cast<size_t>(std::max(towerDimIndex, 0l));
231 const auto towerDimIndexNonLargerValue = std::min(towerDimIndexNonNegative, _towersPerDim[dim] - 1);
232 towerIndex2D[dim] = towerDimIndexNonLargerValue;
234 // flag manager
235 if (pos[dim] >= _haloBoxMax[dim]) {
236 towerIndex2D[dim] = _towersPerDim[dim] - 1;
237 } else if (pos[dim] < _haloBoxMin[dim]) {
238 towerIndex2D[dim] = 0;
239 }
240 }
241
242 return towerIndex2D;
243 }
244
250 [[nodiscard]] size_t getTowerIndex1DAtPosition(const std::array<double, 3> &pos) const {
251 const auto [x, y] = getTowerIndex2DAtPosition(pos);
252 return towerIndex2DTo1D(x, y);
253 }
254
260 ClusterTower<Particle_T> &getTowerAtPosition(const std::array<double, 3> &pos) {
261 const auto [x, y] = getTowerIndex2DAtPosition(pos);
262 return getTowerByIndex2D(x, y);
263 }
264
271 ClusterTower<Particle_T> &getTowerByIndex2D(const size_t x, const size_t y) {
272 return _towers[towerIndex2DTo1D(x, y)];
273 }
274
282 [[nodiscard]] size_t towerIndex2DTo1D(const size_t x, const size_t y) const { return x + y * _towersPerDim[0]; }
283
290 [[nodiscard]] std::array<size_t, 2> towerIndex1DTo2D(size_t index) const {
291 if (_towersPerDim[0] == 0) {
292 return {0, 0};
293 } else {
294 return {index % _towersPerDim[0], index / _towersPerDim[0]};
295 }
296 }
297
302 size_t getFirstOwnedTowerIndex() const { return _firstOwnedTowerIndex; }
307 size_t getLastOwnedTowerIndex() const { return _lastOwnedTowerIndex; }
312 double getInteractionLength() const { return _interactionLength; }
317 int getNumTowersPerInteractionLength() const { return _numTowersPerInteractionLength; }
322 const std::array<double, 3> &getBoxMin() const { return _boxMin; }
327 const std::array<double, 3> &getBoxMax() const { return _boxMax; }
332 const std::array<double, 3> &getHaloBoxMin() const { return _haloBoxMin; }
337 const std::array<double, 3> &getHaloBoxMax() const { return _haloBoxMax; }
342 const std::vector<ClusterTower<Particle_T>> &getTowers() const { return _towers; }
347 std::vector<ClusterTower<Particle_T>> &getTowersRef() { return _towers; }
352 const std::array<size_t, 2> &getTowersPerDim() const { return _towersPerDim; }
357 const std::array<double, 2> &getTowerSideLength() const { return _towerSideLength; }
362 const std::array<double, 2> &getTowerSideLengthReciprocal() const { return _towerSideLengthReciprocal; }
363
364 bool cellCanContainHaloParticles(index_t index1d) const override {
365 // Always true because towers cover the whole z dimension
366 return true;
367 }
368
369 bool cellCanContainOwnedParticles(index_t index1d) const override {
370 // check if the tower is strictly in the halo region
371 if (index1d < _firstOwnedTowerIndex or index1d > _lastOwnedTowerIndex) {
372 return false;
373 }
374 const auto index2D = towerIndex1DTo2D(index1d);
375 bool isHaloTower = false;
376 for (size_t i = 0; i < index2D.size(); ++i) {
377 if (index2D[i] < _numTowersPerInteractionLength or
378 index2D[i] >= _towersPerDim[i] - _numTowersPerInteractionLength) {
379 isHaloTower = true;
380 break;
381 }
382 }
383 return not isHaloTower;
384 }
385
386 private:
390 size_t _firstOwnedTowerIndex{};
394 size_t _lastOwnedTowerIndex{};
398 double _interactionLength;
403 int _numTowersPerInteractionLength{};
404
408 std::array<double, 3> _boxMin;
409
413 std::array<double, 3> _boxMax;
414
418 std::array<double, 3> _haloBoxMin;
419
423 std::array<double, 3> _haloBoxMax;
424
428 std::vector<ClusterTower<Particle_T>> _towers;
429
433 std::array<size_t, 2> _towersPerDim{};
434
438 std::array<double, 2> _towerSideLength{0.};
439
443 std::array<double, 2> _towerSideLengthReciprocal{0.};
444};
445} // 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:250
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:282
const std::array< double, 3 > & getBoxMax() const
Getter.
Definition: ClusterTowerBlock2D.h:327
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:332
std::vector< ClusterTower< Particle_T > > & getTowersRef()
Getter for a mutable reference.
Definition: ClusterTowerBlock2D.h:347
const std::array< double, 3 > & getHaloBoxMax() const
Getter.
Definition: ClusterTowerBlock2D.h:337
size_t size() const
Return the number of towers.
Definition: ClusterTowerBlock2D.h:82
size_t getFirstOwnedTowerIndex() const
Getter.
Definition: ClusterTowerBlock2D.h:302
const std::array< double, 2 > & getTowerSideLength() const
Getter.
Definition: ClusterTowerBlock2D.h:357
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:322
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:369
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:218
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:190
size_t getLastOwnedTowerIndex() const
Getter.
Definition: ClusterTowerBlock2D.h:307
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:176
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:352
const std::vector< ClusterTower< Particle_T > > & getTowers() const
Getter.
Definition: ClusterTowerBlock2D.h:342
const std::array< double, 2 > & getTowerSideLengthReciprocal() const
Getter.
Definition: ClusterTowerBlock2D.h:362
bool cellCanContainHaloParticles(index_t index1d) const override
Checks if the cell with the one-dimensional index index1d can contain halo particles.
Definition: ClusterTowerBlock2D.h:364
double getInteractionLength() const
Getter.
Definition: ClusterTowerBlock2D.h:312
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:271
int getNumTowersPerInteractionLength() const
Getter.
Definition: ClusterTowerBlock2D.h:317
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:260
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:290
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