AutoPas  3.0.0
Loading...
Searching...
No Matches
AxilrodTellerMutoFunctor.h
Go to the documentation of this file.
1
7#pragma once
8
15#include "autopas/utils/SoA.h"
18#include "autopas/utils/inBox.h"
19
20namespace mdLib {
21
101template <class Particle_T, bool useMixing = false, autopas::FunctorN3Modes useNewton3 = autopas::FunctorN3Modes::Both,
102 bool calculateGlobals = false, bool countFLOPs = false>
105 Particle_T, AxilrodTellerMutoFunctor<Particle_T, useMixing, useNewton3, calculateGlobals, countFLOPs>> {
109 using SoAArraysType = typename Particle_T::SoAArraysType;
110
114 using SoAFloatPrecision = typename Particle_T::ParticleSoAFloatPrecision;
115
116 public:
121
122 private:
128 explicit AxilrodTellerMutoFunctor(double cutoff, void * /*dummy*/)
130 Particle_T, AxilrodTellerMutoFunctor<Particle_T, useMixing, useNewton3, calculateGlobals, countFLOPs>>(
131 cutoff),
132 _cutoffSquared{cutoff * cutoff},
133 _potentialEnergySum{0.},
134 _virialSum{0., 0., 0.},
135 _aosThreadDataGlobals(),
136 _postProcessed{false} {
137 if constexpr (calculateGlobals) {
138 _aosThreadDataGlobals.resize(autopas::autopas_get_max_threads());
139 }
140 if constexpr (countFLOPs) {
141 _aosThreadDataFLOPs.resize(autopas::autopas_get_max_threads());
142 }
143 }
144
145 public:
154 explicit AxilrodTellerMutoFunctor(double cutoff) : AxilrodTellerMutoFunctor(cutoff, nullptr) {
155 static_assert(not useMixing,
156 "Mixing without a ParticlePropertiesLibrary is not possible! Use a different constructor or set "
157 "mixing to false.");
158 }
159
166 explicit AxilrodTellerMutoFunctor(double cutoff, ParticlePropertiesLibrary<double, size_t> &particlePropertiesLibrary)
167 : AxilrodTellerMutoFunctor(cutoff, nullptr) {
168 static_assert(useMixing,
169 "Not using Mixing but using a ParticlePropertiesLibrary is not allowed! Use a different constructor "
170 "or set mixing to true.");
171 _PPLibrary = &particlePropertiesLibrary;
172 }
173
174 std::string getName() final { return "AxilrodTellerMutoFunctorAutoVec"; }
175
176 bool isRelevantForTuning() final { return true; }
177
178 bool allowsNewton3() final {
179 return useNewton3 == autopas::FunctorN3Modes::Newton3Only or useNewton3 == autopas::FunctorN3Modes::Both;
180 }
181
182 bool allowsNonNewton3() final {
183 return useNewton3 == autopas::FunctorN3Modes::Newton3Off or useNewton3 == autopas::FunctorN3Modes::Both;
184 }
185
186 void AoSFunctor(Particle_T &i, Particle_T &j, Particle_T &k, bool newton3) final {
187 using namespace autopas::utils::ArrayMath::literals;
188
189 if (i.isDummy() or j.isDummy() or k.isDummy()) {
190 return;
191 }
192
193 const auto threadnum = autopas::autopas_get_thread_num();
194
195 if constexpr (countFLOPs) {
196 ++_aosThreadDataFLOPs[threadnum].numDistCalls;
197 }
198
199 auto nu = _nu;
200 if constexpr (useMixing) {
201 nu = _PPLibrary->getMixingNu(i.getTypeId(), j.getTypeId(), k.getTypeId());
202 }
203
204 const auto displacementIJ = j.getR() - i.getR();
205 const auto displacementJK = k.getR() - j.getR();
206 const auto displacementKI = i.getR() - k.getR();
207
208 const double distSquaredIJ = autopas::utils::ArrayMath::dot(displacementIJ, displacementIJ);
209 const double distSquaredJK = autopas::utils::ArrayMath::dot(displacementJK, displacementJK);
210 const double distSquaredKI = autopas::utils::ArrayMath::dot(displacementKI, displacementKI);
211
212 // Check cutoff for every distance
213 if (distSquaredIJ > _cutoffSquared or distSquaredJK > _cutoffSquared or distSquaredKI > _cutoffSquared) {
214 return;
215 }
216
217 // Calculate prefactor
218 const double allDistsSquared = distSquaredIJ * distSquaredJK * distSquaredKI;
219 const double allDistsTo5 = allDistsSquared * allDistsSquared * std::sqrt(allDistsSquared);
220 const double factor = 3.0 * nu / allDistsTo5;
221
222 // Dot products of both distance vectors going from one particle
223 const double IJDotKI = autopas::utils::ArrayMath::dot(displacementIJ, displacementKI);
224 const double IJDotJK = autopas::utils::ArrayMath::dot(displacementIJ, displacementJK);
225 const double JKDotKI = autopas::utils::ArrayMath::dot(displacementJK, displacementKI);
226
227 const double allDotProducts = IJDotKI * IJDotJK * JKDotKI;
228
229 const auto forceIDirectionJK = displacementJK * IJDotKI * (IJDotJK - JKDotKI);
230 const auto forceIDirectionIJ =
231 displacementIJ * (IJDotJK * JKDotKI - distSquaredJK * distSquaredKI + 5.0 * allDotProducts / distSquaredIJ);
232 const auto forceIDirectionKI =
233 displacementKI * (-IJDotJK * JKDotKI + distSquaredIJ * distSquaredJK - 5.0 * allDotProducts / distSquaredKI);
234
235 const auto forceI = (forceIDirectionJK + forceIDirectionIJ + forceIDirectionKI) * factor;
236 i.addF(forceI);
237
238 auto forceJ = forceI;
239 auto forceK = forceI;
240 if (newton3) {
241 const auto forceJDirectionKI = displacementKI * IJDotJK * (JKDotKI - IJDotKI);
242 const auto forceJDirectionIJ =
243 displacementIJ * (-IJDotKI * JKDotKI + distSquaredJK * distSquaredKI - 5.0 * allDotProducts / distSquaredIJ);
244 const auto forceJDirectionJK =
245 displacementJK * (IJDotKI * JKDotKI - distSquaredIJ * distSquaredKI + 5.0 * allDotProducts / distSquaredJK);
246
247 forceJ = (forceJDirectionKI + forceJDirectionIJ + forceJDirectionJK) * factor;
248 j.addF(forceJ);
249
250 forceK = (forceI + forceJ) * (-1.0);
251 k.addF(forceK);
252 }
253
254 if constexpr (countFLOPs) {
255 if (newton3) {
256 ++_aosThreadDataFLOPs[threadnum].numKernelCallsN3;
257 } else {
258 ++_aosThreadDataFLOPs[threadnum].numKernelCallsNoN3;
259 }
260 }
261
262 if constexpr (calculateGlobals) {
263 // Add 3 * potential energy to every owned particle of the interaction.
264 // Division to the correct value is handled in endTraversal().
265 const double potentialEnergy3 = factor * (allDistsSquared - 3.0 * allDotProducts);
266
267 // Virial is calculated as f_i * r_i
268 // see Thompson et al.: https://doi.org/10.1063/1.3245303
269 const auto virialI = forceI * i.getR();
270 if (i.isOwned()) {
271 _aosThreadDataGlobals[threadnum].potentialEnergySum += potentialEnergy3;
272 _aosThreadDataGlobals[threadnum].virialSum += virialI;
273 }
274 // for non-newton3 particles j and/or k will be considered in a separate calculation
275 if (newton3 and j.isOwned()) {
276 const auto virialJ = forceJ * j.getR();
277 _aosThreadDataGlobals[threadnum].potentialEnergySum += potentialEnergy3;
278 _aosThreadDataGlobals[threadnum].virialSum += virialJ;
279 }
280 if (newton3 and k.isOwned()) {
281 const auto virialK = forceK * k.getR();
282 _aosThreadDataGlobals[threadnum].potentialEnergySum += potentialEnergy3;
283 _aosThreadDataGlobals[threadnum].virialSum += virialK;
284 }
285 if constexpr (countFLOPs) {
286 if (newton3) {
287 ++_aosThreadDataFLOPs[threadnum].numGlobalCalcsN3;
288 } else {
289 ++_aosThreadDataFLOPs[threadnum].numGlobalCalcsNoN3;
290 }
291 }
292 }
293 }
294
302 void setParticleProperties(SoAFloatPrecision nu) { _nu = nu; }
303
307 constexpr static auto getNeededAttr() {
308 return std::array<typename Particle_T::AttributeNames, 9>{Particle_T::AttributeNames::id,
309 Particle_T::AttributeNames::posX,
310 Particle_T::AttributeNames::posY,
311 Particle_T::AttributeNames::posZ,
312 Particle_T::AttributeNames::forceX,
313 Particle_T::AttributeNames::forceY,
314 Particle_T::AttributeNames::forceZ,
315 Particle_T::AttributeNames::typeId,
316 Particle_T::AttributeNames::ownershipState};
317 }
318
322 constexpr static auto getNeededAttr(std::false_type) {
323 return std::array<typename Particle_T::AttributeNames, 6>{
324 Particle_T::AttributeNames::id, Particle_T::AttributeNames::posX,
325 Particle_T::AttributeNames::posY, Particle_T::AttributeNames::posZ,
326 Particle_T::AttributeNames::typeId, Particle_T::AttributeNames::ownershipState};
327 }
328
332 constexpr static auto getComputedAttr() {
333 return std::array<typename Particle_T::AttributeNames, 3>{
334 Particle_T::AttributeNames::forceX, Particle_T::AttributeNames::forceY, Particle_T::AttributeNames::forceZ};
335 }
336
341 constexpr static bool getMixing() { return useMixing; }
342
347 void initTraversal() final {
348 _potentialEnergySum = 0.;
349 _virialSum = {0., 0., 0.};
350 _postProcessed = false;
351 for (size_t i = 0; i < _aosThreadDataGlobals.size(); ++i) {
352 _aosThreadDataGlobals[i].setZero();
353 }
354 }
355
360 void endTraversal(bool newton3) final {
361 using namespace autopas::utils::ArrayMath::literals;
362
363 if (_postProcessed) {
365 "Already postprocessed, endTraversal(bool newton3) was called twice without calling initTraversal().");
366 }
367 if (calculateGlobals) {
368 // Accumulate potential energy and virial values.
369 for (const auto &data : _aosThreadDataGlobals) {
370 _potentialEnergySum += data.potentialEnergySum;
371 _virialSum += data.virialSum;
372 }
373
374 // For each interaction, we added the full contribution for all three particles. Divide by 3 here, so that each
375 // contribution is only counted once per triplet.
376 _potentialEnergySum /= 3.;
377
378 // Additionally, we have always calculated 3*potentialEnergy, so we divide by 3 again.
379 _potentialEnergySum /= 3.;
380
381 _postProcessed = true;
382
383 AutoPasLog(TRACE, "Final potential energy {}", _potentialEnergySum);
384 AutoPasLog(TRACE, "Final virial {}", _virialSum[0] + _virialSum[1] + _virialSum[2]);
385 }
386 }
387
393 if (not calculateGlobals) {
395 "Trying to get potential energy even though calculateGlobals is false. If you want this functor to calculate "
396 "global "
397 "values, please specify calculateGlobals to be true.");
398 }
399 if (not _postProcessed) {
401 "Cannot get potential energy, because endTraversal was not called.");
402 }
403 return _potentialEnergySum;
404 }
405
410 double getVirial() {
411 if (not calculateGlobals) {
413 "Trying to get virial even though calculateGlobals is false. If you want this functor to calculate global "
414 "values, please specify calculateGlobals to be true.");
415 }
416 if (not _postProcessed) {
418 "Cannot get virial, because endTraversal was not called.");
419 }
420 return _virialSum[0] + _virialSum[1] + _virialSum[2];
421 }
422
458 [[nodiscard]] size_t getNumFLOPs() const override {
459 if constexpr (countFLOPs) {
460 const size_t numDistCallsAcc =
461 std::accumulate(_aosThreadDataFLOPs.begin(), _aosThreadDataFLOPs.end(), 0ul,
462 [](size_t sum, const auto &data) { return sum + data.numDistCalls; });
463 const size_t numKernelCallsN3Acc =
464 std::accumulate(_aosThreadDataFLOPs.begin(), _aosThreadDataFLOPs.end(), 0ul,
465 [](size_t sum, const auto &data) { return sum + data.numKernelCallsN3; });
466 const size_t numKernelCallsNoN3Acc =
467 std::accumulate(_aosThreadDataFLOPs.begin(), _aosThreadDataFLOPs.end(), 0ul,
468 [](size_t sum, const auto &data) { return sum + data.numKernelCallsNoN3; });
469 const size_t numGlobalCalcsN3Acc =
470 std::accumulate(_aosThreadDataFLOPs.begin(), _aosThreadDataFLOPs.end(), 0ul,
471 [](size_t sum, const auto &data) { return sum + data.numGlobalCalcsN3; });
472 const size_t numGlobalCalcsNoN3Acc =
473 std::accumulate(_aosThreadDataFLOPs.begin(), _aosThreadDataFLOPs.end(), 0ul,
474 [](size_t sum, const auto &data) { return sum + data.numGlobalCalcsNoN3; });
475
476 constexpr size_t numFLOPsPerDistanceCall = 24;
477 constexpr size_t numFLOPsPerN3KernelCall = 100;
478 constexpr size_t numFLOPsPerNoN3KernelCall = 59;
479 constexpr size_t numFLOPsPerN3GlobalCalc = 24;
480 constexpr size_t numFLOPsPerNoN3GlobalCalc = 10;
481
482 return numDistCallsAcc * numFLOPsPerDistanceCall + numKernelCallsN3Acc * numFLOPsPerN3KernelCall +
483 numKernelCallsNoN3Acc * numFLOPsPerNoN3KernelCall + numGlobalCalcsN3Acc * numFLOPsPerN3GlobalCalc +
484 numGlobalCalcsNoN3Acc * numFLOPsPerNoN3GlobalCalc;
485 } else {
486 // This is needed because this function still gets called with FLOP logging disabled, just nothing is done with it
487 return std::numeric_limits<size_t>::max();
488 }
489 }
490
491 [[nodiscard]] double getHitRate() const override {
492 if constexpr (countFLOPs) {
493 const size_t numDistCallsAcc =
494 std::accumulate(_aosThreadDataFLOPs.begin(), _aosThreadDataFLOPs.end(), 0ul,
495 [](size_t sum, const auto &data) { return sum + data.numDistCalls; });
496 const size_t numKernelCallsN3Acc =
497 std::accumulate(_aosThreadDataFLOPs.begin(), _aosThreadDataFLOPs.end(), 0ul,
498 [](size_t sum, const auto &data) { return sum + data.numKernelCallsN3; });
499 const size_t numKernelCallsNoN3Acc =
500 std::accumulate(_aosThreadDataFLOPs.begin(), _aosThreadDataFLOPs.end(), 0ul,
501 [](size_t sum, const auto &data) { return sum + data.numKernelCallsNoN3; });
502
503 return (static_cast<double>(numKernelCallsNoN3Acc) + static_cast<double>(numKernelCallsN3Acc)) /
504 (static_cast<double>(numDistCallsAcc));
505 } else {
506 // This is needed because this function still gets called with FLOP logging disabled, just nothing is done with it
507 return std::numeric_limits<double>::quiet_NaN();
508 }
509 }
510
511 private:
512 template <bool newton3>
513 void SoAFunctorVerletImpl(autopas::SoAView<SoAArraysType> soa, const size_t indexFirst,
514 const std::vector<size_t, autopas::AlignedAllocator<size_t>> &neighborList) {
515 autopas::utils::ExceptionHandler::exception("AxilrodTellerMutoFunctor::SoAFunctorVerletImpl() is not implemented.");
516 }
517
521 class AoSThreadDataGlobals {
522 public:
523 AoSThreadDataGlobals() : virialSum{0., 0., 0.}, potentialEnergySum{0.}, __remainingTo64{} {}
524 void setZero() {
525 virialSum = {0., 0., 0.};
526 potentialEnergySum = 0.;
527 }
528
529 // variables
530 std::array<double, 3> virialSum;
531 double potentialEnergySum;
532
533 private:
534 // dummy parameter to get the right size (64 bytes)
535 double __remainingTo64[(64 - 4 * sizeof(double)) / sizeof(double)];
536 };
537
545 class AoSThreadDataFLOPs {
546 public:
547 AoSThreadDataFLOPs() : __remainingTo64{} {}
548
552 void setZero() {
553 numKernelCallsNoN3 = 0;
554 numKernelCallsN3 = 0;
555 numDistCalls = 0;
556 numGlobalCalcsN3 = 0;
557 numGlobalCalcsNoN3 = 0;
558 }
559
564 size_t numKernelCallsNoN3 = 0;
565
570 size_t numKernelCallsN3 = 0;
571
576 size_t numDistCalls = 0;
577
581 size_t numGlobalCalcsN3 = 0;
582
586 size_t numGlobalCalcsNoN3 = 0;
587
588 private:
592 double __remainingTo64[(64 - 5 * sizeof(size_t)) / sizeof(size_t)];
593 };
594
595 // make sure of the size of AoSThreadDataGlobals
596 static_assert(sizeof(AoSThreadDataGlobals) % 64 == 0, "AoSThreadDataGlobals has wrong size");
597 static_assert(sizeof(AoSThreadDataFLOPs) % 64 == 0, "AoSThreadDataFLOPs has wrong size");
598
599 const double _cutoffSquared;
600
601 // Parameter of the Axilrod-Teller-Muto potential
602 // not const because they might be reset through PPL
603 double _nu = 0.0;
604
606
607 // sum of the potential energy, only calculated if calculateGlobals is true
608 double _potentialEnergySum;
609
610 // sum of the virial, only calculated if calculateGlobals is true
611 std::array<double, 3> _virialSum;
612
613 // thread buffer for aos
614 std::vector<AoSThreadDataGlobals> _aosThreadDataGlobals;
615 std::vector<AoSThreadDataFLOPs> _aosThreadDataFLOPs{};
616
617 // defines whether or whether not the global values are already preprocessed
618 bool _postProcessed;
619};
620} // namespace mdLib
#define AutoPasLog(lvl, fmt,...)
Macro for logging providing common meta information without filename.
Definition: Logger.h:24
This class stores the (physical) properties of molecule types, and, in the case of multi-site molecul...
Definition: ParticlePropertiesLibrary.h:28
floatType getMixingNu(intType i, intType j, intType k) const
Returns the precomputed mixed epsilon * 24.
Definition: ParticlePropertiesLibrary.h:283
AlignedAllocator class.
Definition: AlignedAllocator.h:29
View on a fixed part of a SoA between a start index and an end index.
Definition: SoAView.h:23
TriwiseFunctor class.
Definition: TriwiseFunctor.h:28
TriwiseFunctor(double cutoff)
Constructor.
Definition: TriwiseFunctor.h:39
Default exception class for autopas exceptions.
Definition: ExceptionHandler.h:116
static void exception(const Exception e)
Handle an exception derived by std::exception.
Definition: ExceptionHandler.h:64
A functor to handle Axilrod-Teller-Muto interactions between three particles (molecules).
Definition: AxilrodTellerMutoFunctor.h:105
static constexpr auto getComputedAttr()
Get attributes computed by this functor.
Definition: AxilrodTellerMutoFunctor.h:332
void AoSFunctor(Particle_T &i, Particle_T &j, Particle_T &k, bool newton3) final
TriwiseFunctor for arrays of structures (AoS).
Definition: AxilrodTellerMutoFunctor.h:186
static constexpr bool getMixing()
Definition: AxilrodTellerMutoFunctor.h:341
double getHitRate() const override
Get the hit rate.
Definition: AxilrodTellerMutoFunctor.h:491
size_t getNumFLOPs() const override
Gets the number of useful FLOPs.
Definition: AxilrodTellerMutoFunctor.h:458
AxilrodTellerMutoFunctor()=delete
Deleted default constructor.
bool allowsNewton3() final
Specifies whether the functor is capable of Newton3-like functors.
Definition: AxilrodTellerMutoFunctor.h:178
void initTraversal() final
Reset the global values.
Definition: AxilrodTellerMutoFunctor.h:347
static constexpr auto getNeededAttr(std::false_type)
Get attributes needed for computation without N3 optimization.
Definition: AxilrodTellerMutoFunctor.h:322
bool isRelevantForTuning() final
Specifies whether the functor should be considered for the auto-tuning process.
Definition: AxilrodTellerMutoFunctor.h:176
bool allowsNonNewton3() final
Specifies whether the functor is capable of non-Newton3-like functors.
Definition: AxilrodTellerMutoFunctor.h:182
AxilrodTellerMutoFunctor(double cutoff, ParticlePropertiesLibrary< double, size_t > &particlePropertiesLibrary)
Constructor for Functor with mixing active.
Definition: AxilrodTellerMutoFunctor.h:166
double getVirial()
Get the virial.
Definition: AxilrodTellerMutoFunctor.h:410
void setParticleProperties(SoAFloatPrecision nu)
Sets the particle properties constants for this functor.
Definition: AxilrodTellerMutoFunctor.h:302
double getPotentialEnergy()
Get the potential Energy.
Definition: AxilrodTellerMutoFunctor.h:392
std::string getName() final
Returns name of functor.
Definition: AxilrodTellerMutoFunctor.h:174
void endTraversal(bool newton3) final
Accumulates global values, e.g.
Definition: AxilrodTellerMutoFunctor.h:360
AxilrodTellerMutoFunctor(double cutoff)
Constructor for Functor with mixing disabled.
Definition: AxilrodTellerMutoFunctor.h:154
static constexpr auto getNeededAttr()
Get attributes needed for computation.
Definition: AxilrodTellerMutoFunctor.h:307
constexpr T dot(const std::array< T, SIZE > &a, const std::array< T, SIZE > &b)
Generates the dot product of two arrays.
Definition: ArrayMath.h:233
This is the main namespace of AutoPas.
Definition: AutoPasDecl.h:34
int autopas_get_max_threads()
Dummy for omp_get_max_threads() when no OpenMP is available.
Definition: WrapOpenMP.h:144
FunctorN3Modes
Newton 3 modes for the Functor.
Definition: Functor.h:23
int autopas_get_thread_num()
Dummy for omp_set_lock() when no OpenMP is available.
Definition: WrapOpenMP.h:132