AutoPas  3.0.0
Loading...
Searching...
No Matches
ContainerIterator.h
Go to the documentation of this file.
1
8#pragma once
9
10#include <array>
11#include <limits>
12#include <tuple>
13#include <type_traits>
14#include <vector>
15
20#include "autopas/utils/inBox.h"
21
22namespace autopas {
23
24namespace internal {
34template <class ParticleIterator>
35void deleteParticle(ParticleIterator &iterator) {
36 iterator.deleteCurrentParticle();
37}
38} // namespace internal
39
43namespace containerIteratorUtils {
56template <bool regionIter, class Particle_T, class Arr>
57[[nodiscard]] bool particleFulfillsIteratorRequirements(const Particle_T &p, IteratorBehavior behavior,
58 const Arr &regionMin, const Arr &regionMax) {
59 // If this is a region iterator check box condition first, otherwise race conditions can occur
60 // if multiple region iterator overlap and ownership state is touched.
61 // (e.g. during collection of leaving particles)
62 if constexpr (regionIter) {
63 if (not utils::inBox(p.getR(), regionMin, regionMax)) {
64 return false;
65 }
66 }
67
68 // Check ownership
69 // Dummy is not in sync with iterator behavior because it needs to be 0.
70 // `a & b == b` idiom is to check a == b disregarding any bits beyond b. This is needed due to e.g. forceSequential.
71 if (((behavior & IteratorBehavior::ownedOrHaloOrDummy) == IteratorBehavior::ownedOrHaloOrDummy) or
72 (behavior & IteratorBehavior::dummy and p.isDummy())) {
73 return true;
74 } else {
75 // relies on both enums having the same encoding. This should be guaranteed statically in IteratorBehaviorTest!
76 return static_cast<unsigned int>(p.getOwnershipState()) & static_cast<unsigned int>(behavior);
77 }
78}
79} // namespace containerIteratorUtils
80
92template <class Particle_T, bool modifiable, bool regionIter>
94 template <class T>
95 friend void internal::deleteParticle(T &);
96
97 public:
101 using ParticleType = std::conditional_t<modifiable, Particle_T, const Particle_T>;
105 using ParticleVecType = std::conditional_t<modifiable, std::vector<std::vector<Particle_T> *>,
106 std::vector<std::vector<Particle_T> const *>>;
110 using ContainerType = std::conditional_t<modifiable, ParticleContainerInterface<Particle_T>,
112
116 ContainerIterator() : _currentParticle(nullptr){};
117
127 ContainerIterator(ContainerType &container, IteratorBehavior behavior, ParticleVecType *additionalVectorsToIterate,
128 const std::array<double, 3> &regionMin, const std::array<double, 3> &regionMax)
129 : ContainerIterator(nullptr, container, behavior, additionalVectorsToIterate, regionMin, regionMax) {
130 // sanity check
131 static_assert(regionIter == true,
132 "Constructor for Region iterator called but template argument regionIter is false");
133 }
134
142 ContainerIterator(ContainerType &container, IteratorBehavior behavior, ParticleVecType *additionalVectorsToIterate)
143 : ContainerIterator(nullptr, container, behavior, additionalVectorsToIterate, {}, {}) {
144 static_assert(regionIter == false,
145 "Constructor for non-Region iterator called but template argument regionIter is true");
146 }
147
153 : _container(other._container),
154 _currentParticleIndex(other._currentParticleIndex),
155 _currentVectorIndex(other._currentVectorIndex),
156 _currentParticle(other._currentParticle),
157 _additionalVectors(other._additionalVectors),
158 _behavior(other._behavior),
159 _iteratingAdditionalVectors(other._iteratingAdditionalVectors),
160 _vectorIndexOffset(other._vectorIndexOffset),
161 _regionMin(other._regionMin),
162 _regionMax(other._regionMax) {}
163
171 if (this != other) {
172 _container = other._container;
173 _currentParticleIndex = other._currentParticleIndex;
174 _currentVectorIndex = other._currentVectorIndex;
175 _currentParticle = other._currentParticle;
176 _additionalVectors = other._additionalVectors;
177 _behavior = other._behavior;
178 _iteratingAdditionalVectors = other._iteratingAdditionalVectors;
179 _vectorIndexOffset = other._vectorIndexOffset;
180 if constexpr (regionIter) {
181 _regionMin = other._regionMin;
182 _regionMax = other._regionMax;
183 }
184 }
185 return *this;
186 }
187
193 : _container(other._container),
194 _currentParticleIndex(other._currentParticleIndex),
195 _currentVectorIndex(other._currentVectorIndex),
196 _currentParticle(other._currentParticle),
197 _additionalVectors(std::move(other._additionalVectors)),
198 _behavior(other._behavior),
199 _iteratingAdditionalVectors(other._iteratingAdditionalVectors),
200 _vectorIndexOffset(other._vectorIndexOffset),
201 _regionMin(std::move(other._regionMin)),
202 _regionMax(std::move(other._regionMax)) {}
203
211 if (this != &other) {
212 _container = other._container;
213 _currentParticleIndex = other._currentParticleIndex;
214 _currentVectorIndex = other._currentVectorIndex;
215 _currentParticle = other._currentParticle;
216 _additionalVectors = std::move(other._additionalVectors);
217 _behavior = other._behavior;
218 _iteratingAdditionalVectors = other._iteratingAdditionalVectors;
219 _vectorIndexOffset = other._vectorIndexOffset;
220 if constexpr (regionIter) {
221 _regionMin = std::move(other._regionMin);
222 _regionMax = std::move(other._regionMax);
223 }
224 }
225 return *this;
226 }
227
228 private:
240 ContainerIterator(void * /*dummy*/, ContainerType &container, IteratorBehavior behavior,
241 ParticleVecType *additionalVectorsToIterate, const std::array<double, 3> &regionMin,
242 const std::array<double, 3> &regionMax)
243 : _container(&container),
244 _behavior(behavior),
245 _vectorIndexOffset((behavior & IteratorBehavior::forceSequential) ? 1 : autopas_get_num_threads()) {
246 if (additionalVectorsToIterate) {
247 // store pointers to all additional vectors
248 _additionalVectors.insert(_additionalVectors.end(), additionalVectorsToIterate->begin(),
249 additionalVectorsToIterate->end());
250 }
251
252 if constexpr (regionIter) {
253 // clamp region to the container, either with or without halo
254 const auto boxMaxWithHalo = utils::ArrayMath::addScalar(container.getBoxMax(), container.getInteractionLength());
255 const auto boxMinWithHalo = utils::ArrayMath::subScalar(container.getBoxMin(), container.getInteractionLength());
256 _regionMax = utils::ArrayMath::min(regionMax, boxMaxWithHalo);
257 _regionMin = utils::ArrayMath::max(regionMin, boxMinWithHalo);
258 }
259 // fetches the next (=first) valid particle or sets _currentParticle = nullptr which marks the iterator as invalid.
260 fetchParticleAtCurrentIndex();
261 }
262
263 public:
273 // bump the index. If it is invalid now, the container will give us the proper one.
274 ++_currentParticleIndex;
275 fetchParticleAtCurrentIndex();
276 return *this;
277 }
278
283 inline ParticleType &operator*() const { return *_currentParticle; }
284
289 inline ParticleType *operator->() const { return _currentParticle; }
290
295 [[nodiscard]] bool isValid() const { return _currentParticle != nullptr; }
296
306 bool operator==(const bool input) const { return isValid() == input; }
307
313 bool operator!=(const bool input) const { return not(*this == input); }
314
315 private:
320 void fetchParticleAtCurrentIndex() {
321 if (not _iteratingAdditionalVectors) {
322 // getParticle either gives us a particle with the desired properties or a nullptr
323 if constexpr (regionIter) {
324 std::tie(_currentParticle, _currentVectorIndex, _currentParticleIndex) =
325 _container->getParticle(_currentVectorIndex, _currentParticleIndex, _behavior, _regionMin, _regionMax);
326 } else {
327 std::tie(_currentParticle, _currentVectorIndex, _currentParticleIndex) =
328 _container->getParticle(_currentVectorIndex, _currentParticleIndex, _behavior);
329 }
330 // if getParticle told us that the container doesn't have a particle in the first vector for our thread...
331 if (_currentParticle == nullptr and not _additionalVectors.empty()) {
332 // determine which additional vector this thread should start to iterate
333 _currentVectorIndex = (_behavior & IteratorBehavior::forceSequential) ? 0 : autopas_get_thread_num();
334 _currentParticleIndex = 0;
335 _iteratingAdditionalVectors = true;
336 } else {
337 // Case: nothing left in the container and no additional vectors to iterate
338 return;
339 }
340 }
341 // no "else" here because the first case might trigger the second if we reached the end of the container
342 if (_iteratingAdditionalVectors) {
343 // check all vectors ...
344 for (; _currentVectorIndex < _additionalVectors.size(); _currentVectorIndex += _vectorIndexOffset) {
345 // ... and all particles within the vector ...
346 for (; _currentParticleIndex < _additionalVectors[_currentVectorIndex]->size(); ++_currentParticleIndex) {
347 _currentParticle = &(_additionalVectors[_currentVectorIndex]->operator[](_currentParticleIndex));
348 // ... until we find a particle that satisfies our requirements.
349 if (containerIteratorUtils::particleFulfillsIteratorRequirements<regionIter>(*_currentParticle, _behavior,
350 _regionMin, _regionMax)) {
351 return;
352 }
353 }
354 _currentParticleIndex = 0;
355 }
356 }
357 // if we reach this point there is no satisfying particle left neither in the container nor the additional vectors.
358 _currentParticle = nullptr;
359 _currentParticleIndex = std::numeric_limits<decltype(_currentParticleIndex)>::max();
360 _currentVectorIndex = std::numeric_limits<decltype(_currentVectorIndex)>::max();
361 }
362
368 void deleteCurrentParticle() {
369 if (_iteratingAdditionalVectors) {
370 // the current particle address needs to be between start and end of the current vector
371 // otherwise it is from the previous vector
372 auto &currentVector = *_additionalVectors[_currentVectorIndex];
373 // swap-delete
374 *_currentParticle = currentVector.back();
375 currentVector.pop_back();
376 // make sure _currentParticle always points to a valid particle if there is one.
377 if (currentVector.empty() or not containerIteratorUtils::particleFulfillsIteratorRequirements<regionIter>(
378 *_currentParticle, _behavior, _regionMin, _regionMax)) {
379 this->operator++();
380 }
381 } else {
382 const auto indicesValid = _container->deleteParticle(_currentVectorIndex, _currentParticleIndex);
383 // Edge cases:
384 if (not indicesValid) {
385 // CASE: the indices and thus the pointer are invalid now
386 this->operator++();
387 } else if (not containerIteratorUtils::particleFulfillsIteratorRequirements<regionIter>(
388 *_currentParticle, _behavior, _regionMin, _regionMax)) {
389 // CASE: the particle was swapped and now the pointer points at something uninteresting
390 this->operator++();
391 }
392 }
393 // move the current index back so that the next ++ points again to the same particle.
394 --_currentParticleIndex;
395 }
396
400 ContainerType *_container;
401
406 size_t _currentParticleIndex{0};
407
413 size_t _currentVectorIndex{};
414
419 ParticleType *_currentParticle = nullptr;
420
424 ParticleVecType _additionalVectors;
425
429 IteratorBehavior _behavior;
430
435 bool _iteratingAdditionalVectors{false};
436
440 size_t _vectorIndexOffset{};
441
445 struct empty {};
449 using RegionCornerT = std::conditional_t<regionIter, std::array<double, 3>, empty>;
455 [[no_unique_address]] RegionCornerT _regionMin{};
461 [[no_unique_address]] RegionCornerT _regionMax{};
462};
463} // namespace autopas
Public iterator class that iterates over a particle container and additional vectors (which are typic...
Definition: ContainerIterator.h:93
std::conditional_t< modifiable, Particle_T, const Particle_T > ParticleType
Type of the particle this iterator points to.
Definition: ContainerIterator.h:101
ContainerIterator(const ContainerIterator< Particle_T, modifiable, regionIter > &other)
Copy constructor.
Definition: ContainerIterator.h:152
ContainerIterator< Particle_T, modifiable, regionIter > & operator=(ContainerIterator< Particle_T, modifiable, regionIter > &&other) noexcept
Move assignment operator.
Definition: ContainerIterator.h:209
std::conditional_t< modifiable, ParticleContainerInterface< Particle_T >, const ParticleContainerInterface< Particle_T > > ContainerType
Type of the Particle Container type.
Definition: ContainerIterator.h:111
ContainerIterator< Particle_T, modifiable, regionIter > & operator=(const ContainerIterator< Particle_T, modifiable, regionIter > &other)
Copy assignment operator.
Definition: ContainerIterator.h:169
ParticleType * operator->() const
Dereference operator.
Definition: ContainerIterator.h:289
bool operator==(const bool input) const
Checks if the current iterator has a given validity.
Definition: ContainerIterator.h:306
bool operator!=(const bool input) const
Checks if the current iterator does not have a given validity.
Definition: ContainerIterator.h:313
ContainerIterator< Particle_T, modifiable, regionIter > & operator++()
Increments the iterator.
Definition: ContainerIterator.h:272
std::conditional_t< modifiable, std::vector< std::vector< Particle_T > * >, std::vector< std::vector< Particle_T > const * > > ParticleVecType
Type of the additional vector collection.
Definition: ContainerIterator.h:106
ContainerIterator(ContainerIterator< Particle_T, modifiable, regionIter > &&other) noexcept
Move constructor.
Definition: ContainerIterator.h:192
ContainerIterator(ContainerType &container, IteratorBehavior behavior, ParticleVecType *additionalVectorsToIterate)
Regular Iterator constructor meant to be called from the logic handler.
Definition: ContainerIterator.h:142
ContainerIterator()
Default constructor that guarantees an invalid iterator.
Definition: ContainerIterator.h:116
ParticleType & operator*() const
Dereference operator.
Definition: ContainerIterator.h:283
ContainerIterator(ContainerType &container, IteratorBehavior behavior, ParticleVecType *additionalVectorsToIterate, const std::array< double, 3 > &regionMin, const std::array< double, 3 > &regionMax)
Region Iterator constructor meant to be called from the logic handler.
Definition: ContainerIterator.h:127
bool isValid() const
Check whether the iterator currently points to a valid particle.
Definition: ContainerIterator.h:295
The ParticleContainerInterface class provides a basic interface for all Containers within AutoPas.
Definition: ParticleContainerInterface.h:37
bool particleFulfillsIteratorRequirements(const Particle_T &p, IteratorBehavior behavior, const Arr &regionMin, const Arr &regionMax)
Indicates whether the particle has the correct ownership state and if this is a region iterator is in...
Definition: ContainerIterator.h:57
void deleteParticle(ParticleIterator &iterator)
Function to access private iterator.deleteCurrentParticle() via friend.
Definition: ContainerIterator.h:35
constexpr std::array< T, SIZE > max(const std::array< T, SIZE > &a, const std::array< T, SIZE > &b)
Takes elementwise maximum and returns the result.
Definition: ArrayMath.h:96
constexpr std::array< T, SIZE > subScalar(const std::array< T, SIZE > &a, T s)
Subtracts a scalar s from each element of array a and returns the result.
Definition: ArrayMath.h:164
constexpr std::array< T, SIZE > addScalar(const std::array< T, SIZE > &a, T s)
Adds a scalar s to each element of array a and returns the result.
Definition: ArrayMath.h:147
constexpr std::array< T, SIZE > min(const std::array< T, SIZE > &a, const std::array< T, SIZE > &b)
Takes elementwise minimum, returns the result.
Definition: ArrayMath.h:62
bool inBox(const std::array< T, 3 > &position, const std::array< T, 3 > &low, const std::array< T, 3 > &high)
Checks if position is inside of a box defined by low and high.
Definition: inBox.h:26
This is the main namespace of AutoPas.
Definition: AutoPasDecl.h:32
int autopas_get_num_threads()
Dummy for omp_get_num_threads() when no OpenMP is available.
Definition: WrapOpenMP.h:138
int autopas_get_thread_num()
Dummy for omp_set_lock() when no OpenMP is available.
Definition: WrapOpenMP.h:132