AutoPas  3.0.0
Loading...
Searching...
No Matches
CellFunctor3B.h
Go to the documentation of this file.
1
7#pragma once
8
12
13namespace autopas::internal {
23template <class ParticleCell_T, class ParticleFunctor_T, bool bidirectional = true>
25 public:
35 explicit CellFunctor3B(ParticleFunctor_T &f, const double sortingCutoff, DataLayoutOption dataLayout, bool useNewton3)
36 : _functor(f), _sortingCutoff(sortingCutoff), _dataLayout(dataLayout), _useNewton3(useNewton3) {}
37
42 void processCell(ParticleCell_T &cell);
43
53 void processCellPair(ParticleCell_T &cell1, ParticleCell_T &cell2,
54 const std::array<double, 3> &sortingDirection = {0., 0., 0.});
55
64 void processCellTriple(ParticleCell_T &cell1, ParticleCell_T &cell2, ParticleCell_T &cell3,
65 const std::array<double, 3> &sortingDirection = {0., 0., 0.});
66
71 [[nodiscard]] DataLayoutOption::Value getDataLayout() const { return _dataLayout; }
72
77 [[nodiscard]] bool getNewton3() const { return _useNewton3; }
78
83 [[nodiscard]] bool getBidirectional() const { return bidirectional; }
84
91 void setSortingThreshold(size_t sortingThreshold);
92
93 private:
100 [[nodiscard]] bool shouldUseSorting(size_t particleCount, const std::array<double, 3> &sortingDirection) const {
101 return particleCount >= _sortingThreshold and
102 (sortingDirection[0] != 0.0 or sortingDirection[1] != 0.0 or sortingDirection[2] != 0.0);
103 }
104
114 void processCellAoSImpl(ParticleCell_T &cell);
115
123 void processCellPairAoSImpl(ParticleCell_T &cell1, ParticleCell_T &cell2,
124 const std::array<double, 3> &sortingDirection);
125
136 void processCellTripleAoSImpl(ParticleCell_T &cell1, ParticleCell_T &cell2, ParticleCell_T &cell3,
137 const std::array<double, 3> &sortingDirection);
138
144 void processCellPairSoAImpl(ParticleCell_T &cell1, ParticleCell_T &cell2);
145
152 void processCellTripleSoAImpl(ParticleCell_T &cell1, ParticleCell_T &cell2, ParticleCell_T &cell3);
153
154 ParticleFunctor_T &_functor;
155
156 const double _sortingCutoff;
157
163 size_t _sortingThreshold{8};
164
165 const DataLayoutOption::Value _dataLayout;
166
167 const bool _useNewton3;
168};
169
170template <class ParticleCell_T, class ParticleFunctor_T, bool bidirectional>
172 _sortingThreshold = sortingThreshold;
173}
174
175template <class ParticleCell_T, class ParticleFunctor_T, bool bidirectional>
177 const bool isAoS = _dataLayout == DataLayoutOption::aos ? true : false;
178 const bool isSoA = _dataLayout == DataLayoutOption::soa ? true : false;
179
180 // Return early if the cell is empty.
181 if ((isSoA and cell._particleSoABuffer.size() == 0) or (isAoS and cell.isEmpty())) {
182 return;
183 }
184 // Avoid force calculations if the cell contains only halo particles or if the cell is empty (=dummy)
185 if (not cell.canHaveOwnedParticles()) {
186 return;
187 }
188
189 if (isAoS) {
190 processCellAoSImpl(cell);
191 } else if (isSoA) {
192 _functor.SoAFunctorSingle(cell._particleSoABuffer, _useNewton3);
193 }
194}
195
196template <class ParticleCell_T, class ParticleFunctor_T, bool bidirectional>
198
199 ParticleCell_T &cell1, ParticleCell_T &cell2, const std::array<double, 3> &sortingDirection) {
200 const bool isAoS = _dataLayout == DataLayoutOption::aos ? true : false;
201 const bool isSoA = _dataLayout == DataLayoutOption::soa ? true : false;
202
203 // Return early if a cell is empty.
204 if ((isSoA and (cell1._particleSoABuffer.size() == 0 or cell2._particleSoABuffer.size() == 0)) or
205 (isAoS and (cell1.isEmpty() or cell2.isEmpty()))) {
206 return;
207 }
208
209 if (not cell1.canHaveOwnedParticles()) {
210 // Nothing to do if cell1 has no owned particles and we don't write to cell2 particles.
211 if constexpr (not bidirectional) {
212 if (not _useNewton3) {
213 return;
214 }
215 }
216 // Nothing to do if both cells cannot have owned particles.
217 if (not cell2.canHaveOwnedParticles()) {
218 return;
219 }
220 }
221
222 if (isAoS) {
223 processCellPairAoSImpl(cell1, cell2, sortingDirection);
224 } else if (isSoA) {
225 processCellPairSoAImpl(cell1, cell2);
226 }
227}
228
229template <class ParticleCell_T, class ParticleFunctor_T, bool bidirectional>
231
232 ParticleCell_T &cell1, ParticleCell_T &cell2, ParticleCell_T &cell3,
233 const std::array<double, 3> &sortingDirection) {
234 const bool isAoS = _dataLayout == DataLayoutOption::aos ? true : false;
235 const bool isSoA = _dataLayout == DataLayoutOption::soa ? true : false;
236
237 // Return early if a cell is empty.
238 if ((isSoA and (cell1._particleSoABuffer.size() == 0 or cell2._particleSoABuffer.size() == 0 or
239 cell3._particleSoABuffer.size() == 0)) or
240 (isAoS and (cell1.isEmpty() or cell2.isEmpty() or cell3.isEmpty()))) {
241 return;
242 }
243
244 if (not cell1.canHaveOwnedParticles()) {
245 // Nothing to do if cell1 has no owned particles and we would only write to cell1 particles.
246 if constexpr (not bidirectional) {
247 if (not _useNewton3) {
248 return;
249 }
250 }
251 // Nothing to do if all three cells cannot have owned particles.
252 if (not cell2.canHaveOwnedParticles() and not cell3.canHaveOwnedParticles()) {
253 return;
254 }
255 }
256
257 if (isAoS) {
258 processCellTripleAoSImpl(cell1, cell2, cell3, sortingDirection);
259 } else if (isSoA) {
260 processCellTripleSoAImpl(cell1, cell2, cell3);
261 }
262}
263
264template <class ParticleCell_T, class ParticleFunctor_T, bool bidirectional>
266 // helper function
267 const auto interactParticles = [this](auto &p1, auto &p2, auto &p3) {
268 this->_functor.AoSFunctor(p1, p2, p3, this->_useNewton3);
269 if (not this->_useNewton3) {
270 this->_functor.AoSFunctor(p2, p1, p3, false);
271 this->_functor.AoSFunctor(p3, p1, p2, false);
272 }
273 };
274
275 if (cell.size() >= _sortingThreshold) {
276 SortedCellView<ParticleCell_T> cellSorted(cell, utils::ArrayMath::normalize(std::array<double, 3>{1.0, 1.0, 1.0}));
277
278 for (auto cellIter1 = cellSorted._particles.begin(); cellIter1 != cellSorted._particles.end(); ++cellIter1) {
279 auto &[p1Projection, p1Ptr] = *cellIter1;
280
281 for (auto cellIter2 = std::next(cellIter1); cellIter2 != cellSorted._particles.end(); ++cellIter2) {
282 auto &[p2Projection, p2Ptr] = *cellIter2;
283 if (std::abs(p2Projection - p1Projection) > _sortingCutoff) {
284 break;
285 }
286
287 for (auto cellIter3 = std::next(cellIter2); cellIter3 != cellSorted._particles.end(); ++cellIter3) {
288 auto &[p3Projection, p3Ptr] = *cellIter3;
289 if (std::abs(p3Projection - p1Projection) > _sortingCutoff or
290 std::abs(p3Projection - p2Projection) > _sortingCutoff) {
291 break;
292 }
293 interactParticles(*p1Ptr, *p2Ptr, *p3Ptr);
294 }
295 }
296 }
297 } else {
298 for (auto p1Ptr = cell.begin(); p1Ptr != cell.end(); ++p1Ptr) {
299 auto p2Ptr = p1Ptr;
300 ++p2Ptr;
301 for (; p2Ptr != cell.end(); ++p2Ptr) {
302 auto p3Ptr = p2Ptr;
303 ++p3Ptr;
304 for (; p3Ptr != cell.end(); ++p3Ptr) {
305 interactParticles(*p1Ptr, *p2Ptr, *p3Ptr);
306 }
307 }
308 }
309 }
310}
311
312template <class ParticleCell_T, class ParticleFunctor_T, bool bidirectional>
313void CellFunctor3B<ParticleCell_T, ParticleFunctor_T, bidirectional>::processCellPairAoSImpl(
314 ParticleCell_T &cell1, ParticleCell_T &cell2, const std::array<double, 3> &sortingDirection) {
315 const auto interactParticles = [this](auto &p1, auto &p2, auto &p3, const bool p2FromCell1) {
316 this->_functor.AoSFunctor(p1, p2, p3, this->_useNewton3);
317 if (not this->_useNewton3) {
318 if (p2FromCell1) {
319 this->_functor.AoSFunctor(p2, p1, p3, false); // because of no newton3 and p2 is still in cell1
320 } else {
321 if constexpr (bidirectional) {
322 this->_functor.AoSFunctor(p2, p1, p3, false);
323 }
324 }
325 if constexpr (bidirectional) {
326 this->_functor.AoSFunctor(p3, p1, p2, false);
327 }
328 }
329 };
330
331 if (shouldUseSorting(cell1.size() + cell2.size(), sortingDirection)) {
332 SortedCellView<ParticleCell_T> cell1Sorted(cell1, sortingDirection);
333 SortedCellView<ParticleCell_T> cell2Sorted(cell2, sortingDirection);
334
335 // Particle 1 from cell1
336 for (auto cellIter1 = cell1Sorted._particles.begin(); cellIter1 != cell1Sorted._particles.end(); ++cellIter1) {
337 auto &[p1Projection, p1Ptr] = *cellIter1;
338
339 // Particle 2 in cell1, particle 3 in cell2
340 for (auto cellIter2 = std::next(cellIter1); cellIter2 != cell1Sorted._particles.end(); ++cellIter2) {
341 auto &[p2Projection, p2Ptr] = *cellIter2;
342 if (std::abs(p2Projection - p1Projection) > _sortingCutoff) {
343 break;
344 }
345 for (auto &[p3Projection, p3Ptr] : cell2Sorted._particles) {
346 if (std::abs(p3Projection - p2Projection) > _sortingCutoff or
347 std::abs(p3Projection - p1Projection) > _sortingCutoff) {
348 break;
349 }
350 interactParticles(*p1Ptr, *p2Ptr, *p3Ptr, true);
351 }
352 }
353
354 // Particle 2 and 3 in cell 2
355 for (auto cellIter2 = cell2Sorted._particles.begin(); cellIter2 != cell2Sorted._particles.end(); ++cellIter2) {
356 auto &[p2Projection, p2Ptr] = *cellIter2;
357 if (std::abs(p2Projection - p1Projection) > _sortingCutoff) {
358 break;
359 }
360 for (auto cellIter3 = std::next(cellIter2); cellIter3 != cell2Sorted._particles.end(); ++cellIter3) {
361 auto &[p3Projection, p3Ptr] = *cellIter3;
362 if (std::abs(p3Projection - p2Projection) > _sortingCutoff or
363 std::abs(p3Projection - p1Projection) > _sortingCutoff) {
364 break;
365 }
366 interactParticles(*p1Ptr, *p2Ptr, *p3Ptr, false);
367 }
368 }
369 }
370 } else { // no sorting
371 // Particle 1 always from cell1
372 for (auto p1Ptr = cell1.begin(); p1Ptr != cell1.end(); ++p1Ptr) {
373 // Particle 2 still in cell1, particle 3 in cell2
374 auto p2Ptr = p1Ptr;
375 ++p2Ptr;
376 for (; p2Ptr != cell1.end(); ++p2Ptr) {
377 for (auto &p3 : cell2) {
378 interactParticles(*p1Ptr, *p2Ptr, p3, true);
379 }
380 }
381
382 // Particles 2 and 3 in cell2
383 for (auto p2Ptr = cell2.begin(); p2Ptr != cell2.end(); ++p2Ptr) {
384 auto p3Ptr = p2Ptr;
385 ++p3Ptr;
386 for (; p3Ptr != cell2.end(); ++p3Ptr) {
387 interactParticles(*p1Ptr, *p2Ptr, *p3Ptr, false);
388 }
389 }
390 }
391 }
392}
393
394template <class ParticleCell_T, class ParticleFunctor_T, bool bidirectional>
395void CellFunctor3B<ParticleCell_T, ParticleFunctor_T, bidirectional>::processCellTripleAoSImpl(
396 ParticleCell_T &cell1, ParticleCell_T &cell2, ParticleCell_T &cell3,
397 const std::array<double, 3> &sortingDirection) {
398 const auto interactParticles = [this](auto &p1, auto &p2, auto &p3) {
399 this->_functor.AoSFunctor(p1, p2, p3, this->_useNewton3);
400
401 if constexpr (bidirectional) {
402 if (not this->_useNewton3) {
403 this->_functor.AoSFunctor(p2, p1, p3, false);
404 this->_functor.AoSFunctor(p3, p1, p2, false);
405 }
406 }
407 };
408
409 if (shouldUseSorting(cell1.size() + cell2.size() + cell3.size(), sortingDirection)) {
410 SortedCellView<ParticleCell_T> cell1Sorted(cell1, sortingDirection);
411 SortedCellView<ParticleCell_T> cell2Sorted(cell2, sortingDirection);
412
413 for (auto &[p1Projection, p1Ptr] : cell1Sorted._particles) {
414 for (auto &[p2Projection, p2Ptr] : cell2Sorted._particles) {
415 if (std::abs(p2Projection - p1Projection) > _sortingCutoff) {
416 break;
417 }
418 for (auto &p3 : cell3) {
419 interactParticles(*p1Ptr, *p2Ptr, p3);
420 }
421 }
422 }
423 } else {
424 for (auto &p1 : cell1) {
425 for (auto &p2 : cell2) {
426 for (auto &p3 : cell3) {
427 interactParticles(p1, p2, p3);
428 }
429 }
430 }
431 }
432}
433
434template <class ParticleCell_T, class ParticleFunctor_T, bool bidirectional>
435void CellFunctor3B<ParticleCell_T, ParticleFunctor_T, bidirectional>::processCellPairSoAImpl(ParticleCell_T &cell1,
436 ParticleCell_T &cell2) {
437 _functor.SoAFunctorPair(cell1._particleSoABuffer, cell2._particleSoABuffer, _useNewton3);
438 if constexpr (bidirectional) {
439 if (not _useNewton3) {
440 _functor.SoAFunctorPair(cell2._particleSoABuffer, cell1._particleSoABuffer, false);
441 }
442 }
443}
444
445template <class ParticleCell_T, class ParticleFunctor_T, bool bidirectional>
446void CellFunctor3B<ParticleCell_T, ParticleFunctor_T, bidirectional>::processCellTripleSoAImpl(ParticleCell_T &cell1,
447 ParticleCell_T &cell2,
448 ParticleCell_T &cell3) {
449 _functor.SoAFunctorTriple(cell1._particleSoABuffer, cell2._particleSoABuffer, cell3._particleSoABuffer, _useNewton3);
450 if constexpr (bidirectional) {
451 if (not _useNewton3) {
452 _functor.SoAFunctorTriple(cell2._particleSoABuffer, cell1._particleSoABuffer, cell3._particleSoABuffer, false);
453 _functor.SoAFunctorTriple(cell3._particleSoABuffer, cell1._particleSoABuffer, cell2._particleSoABuffer, false);
454 }
455 }
456}
457} // namespace autopas::internal
A cell functor.
Definition: CellFunctor3B.h:24
DataLayoutOption::Value getDataLayout() const
Getter.
Definition: CellFunctor3B.h:71
void processCellTriple(ParticleCell_T &cell1, ParticleCell_T &cell2, ParticleCell_T &cell3, const std::array< double, 3 > &sortingDirection={0., 0., 0.})
Process the interactions between 3 particles, all located in a different cell.
Definition: CellFunctor3B.h:230
void processCell(ParticleCell_T &cell)
Process the interactions inside one cell.
Definition: CellFunctor3B.h:176
CellFunctor3B(ParticleFunctor_T &f, const double sortingCutoff, DataLayoutOption dataLayout, bool useNewton3)
The constructor of CellFunctor3B.
Definition: CellFunctor3B.h:35
bool getBidirectional() const
Getter.
Definition: CellFunctor3B.h:83
void processCellPair(ParticleCell_T &cell1, ParticleCell_T &cell2, const std::array< double, 3 > &sortingDirection={0., 0., 0.})
Process the interactions between the particles of cell1 with particles of cell2.
Definition: CellFunctor3B.h:197
bool getNewton3() const
Getter.
Definition: CellFunctor3B.h:77
void setSortingThreshold(size_t sortingThreshold)
Set the sorting-threshold If the sum of the number of particles in three cells is greater or equal to...
Definition: CellFunctor3B.h:171
This namespace is used for implementation specifics.
Definition: CellFunctor.h:14
constexpr std::array< T, SIZE > normalize(const std::array< T, SIZE > &a)
Generates a normalized array (|a| = 1).
Definition: ArrayMath.h:304