10#include <hwy/highway.h>
27namespace highway = hwy::HWY_NAMESPACE;
31constexpr highway::ScalableTag<int64_t>
tag_long;
47using MaskDouble =
decltype(highway::FirstN(tag_double, 1));
49using MaskLong =
decltype(highway::FirstN(tag_long, 2));
64template <
class Particle_T,
bool applyShift =
false,
bool useMixing =
false,
66 bool countFLOPs =
false,
bool relevantForTuning =
true>
70 calculateGlobals, countFLOPs, relevantForTuning>> {
71 using SoAArraysType = Particle_T::SoAArraysType;
86 particlePropertiesLibrary = std::nullopt)
88 _cutoffSquareAoS{cutoff * cutoff},
89 _PPLibrary{particlePropertiesLibrary} {
90 if (calculateGlobals) {
93 if constexpr (countFLOPs) {
94 AutoPasLog(DEBUG,
"Using LJFunctorHWY with countFLOPs but FLOP counting is not implemented.");
97 if constexpr (useMixing) {
98 if (not _PPLibrary.has_value()) {
99 throw std::runtime_error(
"Mixing is enabled but no ParticlePropertiesLibrary was provided!");
102 if (_PPLibrary.has_value()) {
103 throw std::runtime_error(
"Mixing is disabled but a ParticlePropertiesLibrary was provided!");
108 std::string
getName() final {
return "LJFunctorHWY"; }
113 return useNewton3 == autopas::FunctorN3Modes::Newton3Only or useNewton3 == autopas::FunctorN3Modes::Both;
117 return useNewton3 == autopas::FunctorN3Modes::Newton3Off or useNewton3 == autopas::FunctorN3Modes::Both;
128 return std::ranges::find(_vecPatternsAllowed, vecPattern) != _vecPatternsAllowed.end();
134 inline void AoSFunctor(Particle_T &i, Particle_T &j,
bool newton3)
final {
135 using namespace autopas::utils::ArrayMath::literals;
136 if (i.isDummy() or j.isDummy()) {
139 auto sigmaSquare = _sigmaSquareAoS;
140 auto epsilon24 = _epsilon24AoS;
141 auto shift6 = _shift6AoS;
142 if constexpr (useMixing) {
143 sigmaSquare = _PPLibrary->get().getMixingSigmaSquared(i.getTypeId(), j.getTypeId());
144 epsilon24 = _PPLibrary->get().getMixing24Epsilon(i.getTypeId(), j.getTypeId());
145 if constexpr (applyShift) {
146 shift6 = _PPLibrary->get().getMixingShift6(i.getTypeId(), j.getTypeId());
149 const auto dr = i.getR() - j.getR();
152 if (dr2 > _cutoffSquareAoS) {
156 const double invdr2 = 1. / dr2;
157 double lj6 = sigmaSquare * invdr2;
158 lj6 = lj6 * lj6 * lj6;
159 const double lj12 = lj6 * lj6;
160 const double lj12m6 = lj12 - lj6;
161 const double fac = epsilon24 * (lj12 + lj12m6) * invdr2;
162 const auto f = dr * fac;
167 if (calculateGlobals) {
168 const auto virial = dr * f;
169 const double potentialEnergy6 = epsilon24 * lj12m6 + shift6;
174 _aosThreadData[threadnum].potentialEnergySum += potentialEnergy6;
175 _aosThreadData[threadnum].virialSum += virial;
178 if (newton3 and j.isOwned()) {
180 _aosThreadData[threadnum].potentialEnergySum += potentialEnergy6;
181 _aosThreadData[threadnum].virialSum += virial;
191 if (soa.size() == 0)
return;
194 const auto *
const __restrict xPtr = soa.template begin<Particle_T::AttributeNames::posX>();
195 const auto *
const __restrict yPtr = soa.template begin<Particle_T::AttributeNames::posY>();
196 const auto *
const __restrict zPtr = soa.template begin<Particle_T::AttributeNames::posZ>();
198 const auto *
const __restrict ownedStatePtr = soa.template begin<Particle_T::AttributeNames::ownershipState>();
200 auto *
const __restrict fxPtr = soa.template begin<Particle_T::AttributeNames::forceX>();
201 auto *
const __restrict fyPtr = soa.template begin<Particle_T::AttributeNames::forceY>();
202 auto *
const __restrict fzPtr = soa.template begin<Particle_T::AttributeNames::forceZ>();
204 const auto *
const __restrict typeIDptr = soa.template begin<Particle_T::AttributeNames::typeId>();
212 for (std::ptrdiff_t i =
static_cast<std::ptrdiff_t
>(soa.size()) - 1; i >= 0; i -= 1) {
213 static_assert(std::is_same_v<std::underlying_type_t<autopas::OwnershipState>, int64_t>,
214 "OwnershipStates underlying type should be int64_t!");
216 handleILoopBody<true, true, false, VectorizationPattern::p1xVec>(
217 i, xPtr, yPtr, zPtr, ownedStatePtr, xPtr, yPtr, zPtr, ownedStatePtr, fxPtr, fyPtr, fzPtr, fxPtr, fyPtr, fzPtr,
218 typeIDptr, typeIDptr, virialSumX, virialSumY, virialSumZ, uPotSum, 0, 0, i);
221 if constexpr (calculateGlobals) {
222 computeGlobals(virialSumX, virialSumY, virialSumZ, uPotSum);
232 bool newton3)
final {
233 switch (_vecPattern) {
234 case VectorizationPattern::p1xVec: {
236 SoAFunctorPairImpl<true, false, VectorizationPattern::p1xVec>(soa1, soa2);
238 SoAFunctorPairImpl<false, false, VectorizationPattern::p1xVec>(soa1, soa2);
242 case VectorizationPattern::p2xVecDiv2: {
244 SoAFunctorPairImpl<true, false, VectorizationPattern::p2xVecDiv2>(soa1, soa2);
246 SoAFunctorPairImpl<false, false, VectorizationPattern::p2xVecDiv2>(soa1, soa2);
250 case VectorizationPattern::pVecDiv2x2: {
252 SoAFunctorPairImpl<true, false, VectorizationPattern::pVecDiv2x2>(soa1, soa2);
254 SoAFunctorPairImpl<false, false, VectorizationPattern::pVecDiv2x2>(soa1, soa2);
258 case VectorizationPattern::pVecx1: {
260 SoAFunctorPairImpl<true, false, VectorizationPattern::pVecx1>(soa1, soa2);
262 SoAFunctorPairImpl<false, false, VectorizationPattern::pVecx1>(soa1, soa2);
276 if (soa1.size() == 0 or soa2.size() == 0) {
279 switch (_vecPattern) {
280 case VectorizationPattern::p1xVec: {
282 SoAFunctorPairImpl<true, true, VectorizationPattern::p1xVec>(soa1, soa2, sortingData);
284 SoAFunctorPairImpl<false, true, VectorizationPattern::p1xVec>(soa1, soa2, sortingData);
288 case VectorizationPattern::p2xVecDiv2: {
290 SoAFunctorPairImpl<true, true, VectorizationPattern::p2xVecDiv2>(soa1, soa2, sortingData);
292 SoAFunctorPairImpl<false, true, VectorizationPattern::p2xVecDiv2>(soa1, soa2, sortingData);
296 case VectorizationPattern::pVecDiv2x2: {
298 SoAFunctorPairImpl<true, true, VectorizationPattern::pVecDiv2x2>(soa1, soa2, sortingData);
300 SoAFunctorPairImpl<false, true, VectorizationPattern::pVecDiv2x2>(soa1, soa2, sortingData);
304 case VectorizationPattern::pVecx1: {
306 SoAFunctorPairImpl<true, true, VectorizationPattern::pVecx1>(soa1, soa2, sortingData);
308 SoAFunctorPairImpl<false, true, VectorizationPattern::pVecx1>(soa1, soa2, sortingData);
322 template <VectorizationPattern vecPattern>
323 static size_t iStepSize() {
324 if constexpr (vecPattern == VectorizationPattern::p1xVec) {
327 if constexpr (vecPattern == VectorizationPattern::p2xVecDiv2) {
330 if constexpr (vecPattern == VectorizationPattern::pVecDiv2x2) {
333 if constexpr (vecPattern == VectorizationPattern::pVecx1) {
344 template <VectorizationPattern vecPattern>
345 static size_t jStepSize() {
346 if constexpr (vecPattern == VectorizationPattern::p1xVec) {
349 if constexpr (vecPattern == VectorizationPattern::p2xVecDiv2) {
352 if constexpr (vecPattern == VectorizationPattern::pVecDiv2x2) {
355 if constexpr (vecPattern == VectorizationPattern::pVecx1) {
370 template <VectorizationPattern vecPattern>
371 static constexpr bool checkSecondLoopCondition(std::ptrdiff_t i,
size_t j) {
373 const std::ptrdiff_t jStep =
static_cast<std::ptrdiff_t
>(jStepSize<vecPattern>());
374 const std::ptrdiff_t limit = i - (i % jStep);
375 return j < static_cast<size_t>(limit);
395 template <
bool remainder,
bool reversed, VectorizationPattern vecPattern>
396 static void fillIRegisters(
const size_t i,
const double *
const __restrict xPtr,
const double *
const __restrict yPtr,
397 const double *
const __restrict zPtr,
399 VectorDouble &y1, VectorDouble &z1, MaskDouble &ownedMaskI,
const size_t restI) {
400 VectorLong ownedStateILong = highway::Zero(tag_long);
402 if constexpr (vecPattern == VectorizationPattern::p1xVec) {
403 const auto owned =
static_cast<int64_t
>(ownedStatePtr[i]);
404 ownedStateILong = highway::Set(tag_long, owned);
406 x1 = highway::Set(tag_double, xPtr[i]);
407 y1 = highway::Set(tag_double, yPtr[i]);
408 z1 = highway::Set(tag_double, zPtr[i]);
409 }
else if constexpr (vecPattern == VectorizationPattern::p2xVecDiv2) {
410 const auto ownedFirst =
static_cast<int64_t
>(ownedStatePtr[i]);
411 ownedStateILong = highway::Set(tag_long, ownedFirst);
413 x1 = highway::Set(tag_double, xPtr[i]);
414 y1 = highway::Set(tag_double, yPtr[i]);
415 z1 = highway::Set(tag_double, zPtr[i]);
417 VectorLong tmpOwnedI = highway::Zero(tag_long);
422 if constexpr (not remainder) {
423 const auto index = reversed ? i - 1 : i + 1;
424 const auto ownedSecond =
static_cast<int64_t
>(ownedStatePtr[index]);
425 tmpOwnedI = highway::Set(tag_long, ownedSecond);
426 tmpX1 = highway::Set(tag_double, xPtr[index]);
427 tmpY1 = highway::Set(tag_double, yPtr[index]);
428 tmpZ1 = highway::Set(tag_double, zPtr[index]);
431 ownedStateILong = highway::ConcatLowerLower(tag_long, tmpOwnedI, ownedStateILong);
432 x1 = highway::ConcatLowerLower(tag_double, tmpX1, x1);
433 y1 = highway::ConcatLowerLower(tag_double, tmpY1, y1);
434 z1 = highway::ConcatLowerLower(tag_double, tmpZ1, z1);
435 }
else if constexpr (vecPattern == VectorizationPattern::pVecDiv2x2) {
436 const int index = reversed ? (remainder ? 0 : i -
_vecLengthDouble / 2 + 1) : i;
439 ownedStateILong = highway::LoadN(tag_long,
reinterpret_cast<const int64_t *
>(&ownedStatePtr[index]), lanes);
441 x1 = highway::LoadN(tag_double, &xPtr[index], lanes);
442 y1 = highway::LoadN(tag_double, &yPtr[index], lanes);
443 z1 = highway::LoadN(tag_double, &zPtr[index], lanes);
445 ownedStateILong = highway::ConcatLowerLower(tag_long, ownedStateILong, ownedStateILong);
446 x1 = highway::ConcatLowerLower(tag_double, x1, x1);
447 y1 = highway::ConcatLowerLower(tag_double, y1, y1);
448 z1 = highway::ConcatLowerLower(tag_double, z1, z1);
449 }
else if constexpr (vecPattern == VectorizationPattern::pVecx1) {
450 const auto index = reversed ? (remainder ? 0 : i -
_vecLengthDouble + 1) : i;
452 if constexpr (remainder) {
453 x1 = highway::LoadN(tag_double, &xPtr[index], restI);
454 y1 = highway::LoadN(tag_double, &yPtr[index], restI);
455 z1 = highway::LoadN(tag_double, &zPtr[index], restI);
457 ownedStateILong = highway::LoadN(tag_long,
reinterpret_cast<const int64_t *
>(&ownedStatePtr[index]), restI);
459 x1 = highway::LoadU(tag_double, &xPtr[index]);
460 y1 = highway::LoadU(tag_double, &yPtr[index]);
461 z1 = highway::LoadU(tag_double, &zPtr[index]);
463 ownedStateILong = highway::LoadU(tag_long,
reinterpret_cast<const int64_t *
>(&ownedStatePtr[index]));
467 MaskLong ownedMaskILong = highway::Ne(ownedStateILong, highway::Zero(tag_long));
470 ownedMaskI = highway::RebindMask(tag_double, ownedMaskILong);
473 template <
bool remainder, VectorizationPattern vecPattern>
474 static void handleNewton3Reduction(
const VectorDouble &fx,
const VectorDouble &fy,
const VectorDouble &fz,
475 double *
const __restrict fx2Ptr,
double *
const __restrict fy2Ptr,
476 double *
const __restrict fz2Ptr,
const size_t j,
const size_t rest) {
477 if constexpr (vecPattern == VectorizationPattern::p1xVec) {
479 remainder ? highway::LoadN(tag_double, &fx2Ptr[j], rest) : highway::LoadU(
tag_double, &fx2Ptr[j]);
481 remainder ? highway::LoadN(tag_double, &fy2Ptr[j], rest) : highway::LoadU(
tag_double, &fy2Ptr[j]);
483 remainder ? highway::LoadN(tag_double, &fz2Ptr[j], rest) : highway::LoadU(
tag_double, &fz2Ptr[j]);
489 remainder ? highway::StoreN(fx2New, tag_double, &fx2Ptr[j], rest)
490 : highway::StoreU(fx2New,
tag_double, &fx2Ptr[j]);
491 remainder ? highway::StoreN(fy2New, tag_double, &fy2Ptr[j], rest)
492 : highway::StoreU(fy2New,
tag_double, &fy2Ptr[j]);
493 remainder ? highway::StoreN(fz2New, tag_double, &fz2Ptr[j], rest)
494 : highway::StoreU(fz2New,
tag_double, &fz2Ptr[j]);
495 }
else if constexpr (vecPattern == VectorizationPattern::p2xVecDiv2) {
496 const auto lowerFx = highway::LowerHalf(tag_double_half, fx);
497 const auto lowerFy = highway::LowerHalf(tag_double_half, fy);
498 const auto lowerFz = highway::LowerHalf(tag_double_half, fz);
500 const auto upperFx = highway::UpperHalf(tag_double_half, fx);
501 const auto upperFy = highway::UpperHalf(tag_double_half, fy);
502 const auto upperFz = highway::UpperHalf(tag_double_half, fz);
504 const auto fxCombined = highway::Add(lowerFx, upperFx);
505 const auto fyCombined = highway::Add(lowerFy, upperFy);
506 const auto fzCombined = highway::Add(lowerFz, upperFz);
510 const auto fx2 = highway::LoadN(tag_double_half, &fx2Ptr[j], lanes);
511 const auto fy2 = highway::LoadN(tag_double_half, &fy2Ptr[j], lanes);
512 const auto fz2 = highway::LoadN(tag_double_half, &fz2Ptr[j], lanes);
514 const auto newFx = highway::Sub(fx2, fxCombined);
515 const auto newFy = highway::Sub(fy2, fyCombined);
516 const auto newFz = highway::Sub(fz2, fzCombined);
518 highway::StoreN(newFx, tag_double_half, &fx2Ptr[j], lanes);
519 highway::StoreN(newFy, tag_double_half, &fy2Ptr[j], lanes);
520 highway::StoreN(newFz, tag_double_half, &fz2Ptr[j], lanes);
521 }
else if constexpr (vecPattern == VectorizationPattern::pVecDiv2x2) {
522 const auto lowerFx = highway::LowerHalf(tag_double_half, fx);
523 const auto lowerFy = highway::LowerHalf(tag_double_half, fy);
524 const auto lowerFz = highway::LowerHalf(tag_double_half, fz);
526 fx2Ptr[j] -= highway::ReduceSum(tag_double_half, lowerFx);
527 fy2Ptr[j] -= highway::ReduceSum(tag_double_half, lowerFy);
528 fz2Ptr[j] -= highway::ReduceSum(tag_double_half, lowerFz);
530 if constexpr (not remainder) {
531 const auto upperFx = highway::UpperHalf(tag_double_half, fx);
532 const auto upperFy = highway::UpperHalf(tag_double_half, fy);
533 const auto upperFz = highway::UpperHalf(tag_double_half, fz);
535 fx2Ptr[j + 1] -= highway::ReduceSum(tag_double_half, upperFx);
536 fy2Ptr[j + 1] -= highway::ReduceSum(tag_double_half, upperFy);
537 fz2Ptr[j + 1] -= highway::ReduceSum(tag_double_half, upperFz);
539 }
else if constexpr (vecPattern == VectorizationPattern::pVecx1) {
540 fx2Ptr[j] -= highway::ReduceSum(tag_double, fx);
541 fy2Ptr[j] -= highway::ReduceSum(tag_double, fy);
542 fz2Ptr[j] -= highway::ReduceSum(tag_double, fz);
546 template <
bool reversed,
bool remainder, VectorizationPattern vecPattern>
547 static void reduceAccumulatedForce(
const size_t i,
double *
const __restrict fxPtr,
double *
const __restrict fyPtr,
548 double *
const __restrict fzPtr,
const VectorDouble &fxAcc,
549 const VectorDouble &fyAcc,
const VectorDouble &fzAcc,
const int restI) {
550 if constexpr (vecPattern == VectorizationPattern::p1xVec) {
551 fxPtr[i] += highway::ReduceSum(tag_double, fxAcc);
552 fyPtr[i] += highway::ReduceSum(tag_double, fyAcc);
553 fzPtr[i] += highway::ReduceSum(tag_double, fzAcc);
554 }
else if constexpr (vecPattern == VectorizationPattern::p2xVecDiv2) {
555 const auto lowerFxAcc = highway::LowerHalf(tag_double_half, fxAcc);
556 const auto lowerFyAcc = highway::LowerHalf(tag_double_half, fyAcc);
557 const auto lowerFzAcc = highway::LowerHalf(tag_double_half, fzAcc);
559 fxPtr[i] += highway::ReduceSum(tag_double_half, lowerFxAcc);
560 fyPtr[i] += highway::ReduceSum(tag_double_half, lowerFyAcc);
561 fzPtr[i] += highway::ReduceSum(tag_double_half, lowerFzAcc);
563 if constexpr (not remainder) {
564 const auto upperFxAcc = highway::UpperHalf(tag_double_half, fxAcc);
565 const auto upperFyAcc = highway::UpperHalf(tag_double_half, fyAcc);
566 const auto upperFzAcc = highway::UpperHalf(tag_double_half, fzAcc);
568 const auto index = reversed ? i - 1 : i + 1;
569 fxPtr[index] += highway::ReduceSum(tag_double_half, upperFxAcc);
570 fyPtr[index] += highway::ReduceSum(tag_double_half, upperFyAcc);
571 fzPtr[index] += highway::ReduceSum(tag_double_half, upperFzAcc);
573 }
else if constexpr (vecPattern == VectorizationPattern::pVecDiv2x2) {
574 const auto lowerFxAcc = highway::LowerHalf(tag_double_half, fxAcc);
575 const auto lowerFyAcc = highway::LowerHalf(tag_double_half, fyAcc);
576 const auto lowerFzAcc = highway::LowerHalf(tag_double_half, fzAcc);
578 const auto upperFxAcc = highway::UpperHalf(tag_double_half, fxAcc);
579 const auto upperFyAcc = highway::UpperHalf(tag_double_half, fyAcc);
580 const auto upperFzAcc = highway::UpperHalf(tag_double_half, fzAcc);
582 const auto fxAccCombined = highway::Add(lowerFxAcc, upperFxAcc);
583 const auto fyAccCombined = highway::Add(lowerFyAcc, upperFyAcc);
584 const auto fzAccCombined = highway::Add(lowerFzAcc, upperFzAcc);
586 const int index = reversed ? (remainder ? 0 : i -
_vecLengthDouble / 2 + 1) : i;
590 const auto oldFx = highway::LoadN(tag_double_half, &fxPtr[index], lanes);
591 const auto oldFy = highway::LoadN(tag_double_half, &fyPtr[index], lanes);
592 const auto oldFz = highway::LoadN(tag_double_half, &fzPtr[index], lanes);
594 const auto newFx = highway::Add(oldFx, fxAccCombined);
595 const auto newFy = highway::Add(oldFy, fyAccCombined);
596 const auto newFz = highway::Add(oldFz, fzAccCombined);
598 highway::StoreN(newFx, tag_double_half, &fxPtr[index], lanes);
599 highway::StoreN(newFy, tag_double_half, &fyPtr[index], lanes);
600 highway::StoreN(newFz, tag_double_half, &fzPtr[index], lanes);
601 }
else if constexpr (vecPattern == VectorizationPattern::pVecx1) {
603 remainder ? highway::LoadN(tag_double, &fxPtr[i], restI) : highway::LoadU(
tag_double, &fxPtr[i]);
605 remainder ? highway::LoadN(tag_double, &fyPtr[i], restI) : highway::LoadU(
tag_double, &fyPtr[i]);
607 remainder ? highway::LoadN(tag_double, &fzPtr[i], restI) : highway::LoadU(
tag_double, &fzPtr[i]);
613 remainder ? highway::StoreN(fxNew, tag_double, &fxPtr[i], restI) : highway::StoreU(fxNew,
tag_double, &fxPtr[i]);
614 remainder ? highway::StoreN(fyNew, tag_double, &fyPtr[i], restI) : highway::StoreU(fyNew,
tag_double, &fyPtr[i]);
615 remainder ? highway::StoreN(fzNew, tag_double, &fzPtr[i], restI) : highway::StoreU(fzNew,
tag_double, &fzPtr[i]);
619 inline void computeGlobals(
const VectorDouble &virialSumX,
const VectorDouble &virialSumY,
620 const VectorDouble &virialSumZ,
const VectorDouble &uPotSum) {
623 _aosThreadData[threadnum].virialSum[0] += highway::ReduceSum(tag_double, virialSumX);
624 _aosThreadData[threadnum].virialSum[1] += highway::ReduceSum(tag_double, virialSumY);
625 _aosThreadData[threadnum].virialSum[2] += highway::ReduceSum(tag_double, virialSumZ);
626 _aosThreadData[threadnum].potentialEnergySum += highway::ReduceSum(tag_double, uPotSum);
663 template <
bool reversed,
bool newton3,
bool remainderI, VectorizationPattern vecPattern>
664 inline void handleILoopBody(
const size_t i,
const double *
const __restrict xPtr1,
665 const double *
const __restrict yPtr1,
const double *
const __restrict zPtr1,
667 const double *
const __restrict xPtr2,
const double *
const __restrict yPtr2,
668 const double *
const __restrict zPtr2,
670 double *
const __restrict fxPtr1,
double *
const __restrict fyPtr1,
671 double *
const __restrict fzPtr1,
double *
const __restrict fxPtr2,
672 double *
const __restrict fyPtr2,
double *
const __restrict fzPtr2,
673 const size_t *
const __restrict typeIDptr1,
const size_t *
const __restrict typeIDptr2,
674 VectorDouble &virialSumX, VectorDouble &virialSumY, VectorDouble &virialSumZ,
675 VectorDouble &uPotSum,
const size_t restI,
const size_t jVecStart,
const size_t jVecEnd) {
686 fillIRegisters<remainderI, reversed, vecPattern>(i, xPtr1, yPtr1, zPtr1, ownedStatePtr1, x1, y1, z1, ownedMaskI,
688 auto j =
static_cast<std::ptrdiff_t
>(jVecStart);
689 for (; checkSecondLoopCondition<vecPattern>(jVecEnd, j);
690 j +=
static_cast<std::ptrdiff_t
>(jStepSize<vecPattern>())) {
691 SoAKernel<newton3, remainderI, false, reversed, vecPattern>(
692 i, j, ownedMaskI,
reinterpret_cast<const int64_t *
>(ownedStatePtr2), x1, y1, z1, xPtr2, yPtr2, zPtr2, fxPtr2,
693 fyPtr2, fzPtr2, &typeIDptr1[i], &typeIDptr2[j], fxAcc, fyAcc, fzAcc, virialSumX, virialSumY, virialSumZ,
697 const size_t restJ = jVecEnd & (jStepSize<vecPattern>() - 1);
699 SoAKernel<newton3, remainderI, true, reversed, vecPattern>(
700 i, j, ownedMaskI,
reinterpret_cast<const int64_t *
>(ownedStatePtr2), x1, y1, z1, xPtr2, yPtr2, zPtr2, fxPtr2,
701 fyPtr2, fzPtr2, &typeIDptr1[i], &typeIDptr2[j], fxAcc, fyAcc, fzAcc, virialSumX, virialSumY, virialSumZ,
702 uPotSum, restI, restJ);
705 reduceAccumulatedForce<reversed, remainderI, vecPattern>(i, fxPtr1, fyPtr1, fzPtr1, fxAcc, fyAcc, fzAcc, restI);
721 template <
bool newton3,
bool sorted, VectorizationPattern vecPattern>
724 if (soa1.
size() == 0 || soa2.
size() == 0) {
728 const size_t n1 = soa1.
size();
729 const size_t n2 = soa2.
size();
731 const auto *
const __restrict x1Ptr = soa1.template begin<Particle_T::AttributeNames::posX>();
732 const auto *
const __restrict y1Ptr = soa1.template begin<Particle_T::AttributeNames::posY>();
733 const auto *
const __restrict z1Ptr = soa1.template begin<Particle_T::AttributeNames::posZ>();
734 const auto *
const __restrict x2Ptr = soa2.template begin<Particle_T::AttributeNames::posX>();
735 const auto *
const __restrict y2Ptr = soa2.template begin<Particle_T::AttributeNames::posY>();
736 const auto *
const __restrict z2Ptr = soa2.template begin<Particle_T::AttributeNames::posZ>();
737 const auto *
const __restrict ownedStatePtr1 = soa1.template begin<Particle_T::AttributeNames::ownershipState>();
738 const auto *
const __restrict ownedStatePtr2 = soa2.template begin<Particle_T::AttributeNames::ownershipState>();
739 auto *
const __restrict fx1Ptr = soa1.template begin<Particle_T::AttributeNames::forceX>();
740 auto *
const __restrict fy1Ptr = soa1.template begin<Particle_T::AttributeNames::forceY>();
741 auto *
const __restrict fz1Ptr = soa1.template begin<Particle_T::AttributeNames::forceZ>();
742 auto *
const __restrict fx2Ptr = soa2.template begin<Particle_T::AttributeNames::forceX>();
743 auto *
const __restrict fy2Ptr = soa2.template begin<Particle_T::AttributeNames::forceY>();
744 auto *
const __restrict fz2Ptr = soa2.template begin<Particle_T::AttributeNames::forceZ>();
745 const auto *
const __restrict typeID1Ptr = soa1.template begin<Particle_T::AttributeNames::typeId>();
746 const auto *
const __restrict typeID2Ptr = soa2.template begin<Particle_T::AttributeNames::typeId>();
748 const std::ptrdiff_t startI =
749 sorted && sortingData.has_value() ?
static_cast<std::ptrdiff_t
>(sortingData->get().startI) : 0;
756 const size_t iStep = iStepSize<vecPattern>();
757 const size_t jStep = jStepSize<vecPattern>();
759 std::ptrdiff_t i = startI;
760 for (; i +
static_cast<std::ptrdiff_t
>(iStep) <=
static_cast<std::ptrdiff_t
>(n1);
761 i +=
static_cast<std::ptrdiff_t
>(iStep)) {
763 size_t jVecStart = 0;
764 if constexpr (sorted) {
766 const auto &sd = sortingData->get();
770 jVecEnd = sd.maxIndex[i + iStep - 1];
773 jVecStart = sd.minIndex[i];
776 if (jVecStart >= jVecEnd) {
780 jVecStart = jVecStart - (jVecStart % jStep);
781 if constexpr (vecPattern == VectorizationPattern::p1xVec) {
789 handleILoopBody<false, newton3, false, vecPattern>(
790 i, x1Ptr, y1Ptr, z1Ptr, ownedStatePtr1, x2Ptr, y2Ptr, z2Ptr, ownedStatePtr2, fx1Ptr, fy1Ptr, fz1Ptr, fx2Ptr,
791 fy2Ptr, fz2Ptr, typeID1Ptr, typeID2Ptr, virialSumX, virialSumY, virialSumZ, uPotSum, 0, jVecStart, jVecEnd);
793 if constexpr (vecPattern != VectorizationPattern::p1xVec) {
795 const size_t restI = n1 - i;
799 size_t jVecStart = 0;
800 if constexpr (sorted) {
802 const auto &sd = sortingData->get();
803 jVecEnd = sd.maxIndex[i + restI - 1];
804 jVecStart = sd.minIndex[i];
805 if (jVecStart < jVecEnd) {
807 jVecStart = jVecStart - (jVecStart % jStep);
812 if (jVecStart < jVecEnd) {
813 handleILoopBody<false, newton3, true, vecPattern>(i, x1Ptr, y1Ptr, z1Ptr, ownedStatePtr1, x2Ptr, y2Ptr, z2Ptr,
814 ownedStatePtr2, fx1Ptr, fy1Ptr, fz1Ptr, fx2Ptr, fy2Ptr,
815 fz2Ptr, typeID1Ptr, typeID2Ptr, virialSumX, virialSumY,
816 virialSumZ, uPotSum, restI, jVecStart, jVecEnd);
821 if constexpr (calculateGlobals) {
822 computeGlobals(virialSumX, virialSumY, virialSumZ, uPotSum);
843 template <
bool remainder, VectorizationPattern vecPattern>
844 static void fillJRegisters(
const size_t j,
const double *
const __restrict x2Ptr,
const double *
const __restrict y2Ptr,
845 const double *
const __restrict z2Ptr,
const int64_t *
const __restrict ownedStatePtr2,
846 VectorDouble &x2, VectorDouble &y2, VectorDouble &z2, MaskDouble &ownedMaskJ,
847 const unsigned int rest) {
848 VectorLong ownedStateJLong = highway::Zero(tag_long);
850 if constexpr (vecPattern == VectorizationPattern::p1xVec) {
851 if constexpr (remainder) {
852 x2 = highway::LoadN(tag_double, &x2Ptr[j], rest);
853 y2 = highway::LoadN(tag_double, &y2Ptr[j], rest);
854 z2 = highway::LoadN(tag_double, &z2Ptr[j], rest);
856 ownedStateJLong = highway::LoadN(tag_long, &ownedStatePtr2[j], rest);
858 x2 = highway::LoadU(tag_double, &x2Ptr[j]);
859 y2 = highway::LoadU(tag_double, &y2Ptr[j]);
860 z2 = highway::LoadU(tag_double, &z2Ptr[j]);
862 ownedStateJLong = highway::LoadU(tag_long, &ownedStatePtr2[j]);
864 }
else if constexpr (vecPattern == VectorizationPattern::p2xVecDiv2) {
867 VectorLong ownedStateJ = highway::LoadN(tag_long, &ownedStatePtr2[j], lanes);
868 x2 = highway::LoadN(tag_double, &x2Ptr[j], lanes);
869 y2 = highway::LoadN(tag_double, &y2Ptr[j], lanes);
870 z2 = highway::LoadN(tag_double, &z2Ptr[j], lanes);
873 ownedStateJLong = highway::ConcatLowerLower(tag_long, ownedStateJ, ownedStateJ);
874 x2 = highway::ConcatLowerLower(tag_double, x2, x2);
875 y2 = highway::ConcatLowerLower(tag_double, y2, y2);
876 z2 = highway::ConcatLowerLower(tag_double, z2, z2);
877 }
else if constexpr (vecPattern == VectorizationPattern::pVecDiv2x2) {
878 VectorLong ownedStateJ = highway::Set(tag_long, ownedStatePtr2[j]);
879 x2 = highway::Set(tag_double, x2Ptr[j]);
880 y2 = highway::Set(tag_double, y2Ptr[j]);
881 z2 = highway::Set(tag_double, z2Ptr[j]);
883 if constexpr (remainder) {
884 ownedStateJLong = highway::ConcatLowerLower(tag_long, highway::Zero(tag_long), ownedStateJ);
885 x2 = highway::ConcatLowerLower(tag_double, highway::Zero(tag_double), x2);
886 y2 = highway::ConcatLowerLower(tag_double, highway::Zero(tag_double), y2);
887 z2 = highway::ConcatLowerLower(tag_double, highway::Zero(tag_double), z2);
889 const auto tmpOwnedJ = highway::Set(tag_long, ownedStatePtr2[j + 1]);
890 const auto tmpX2 = highway::Set(tag_double, x2Ptr[j + 1]);
891 const auto tmpY2 = highway::Set(tag_double, y2Ptr[j + 1]);
892 const auto tmpZ2 = highway::Set(tag_double, z2Ptr[j + 1]);
894 ownedStateJLong = highway::ConcatLowerLower(tag_long, tmpOwnedJ, ownedStateJ);
895 x2 = highway::ConcatLowerLower(tag_double, tmpX2, x2);
896 y2 = highway::ConcatLowerLower(tag_double, tmpY2, y2);
897 z2 = highway::ConcatLowerLower(tag_double, tmpZ2, z2);
899 }
else if constexpr (vecPattern == VectorizationPattern::pVecx1) {
900 ownedStateJLong = highway::Set(tag_long, ownedStatePtr2[j]);
901 x2 = highway::Set(tag_double, x2Ptr[j]);
902 y2 = highway::Set(tag_double, y2Ptr[j]);
903 z2 = highway::Set(tag_double, z2Ptr[j]);
906 MaskLong ownedMaskJLong = highway::Ne(ownedStateJLong, highway::Zero(tag_long));
909 ownedMaskJ = highway::RebindMask(tag_double, ownedMaskJLong);
912 template <
bool remainderI,
bool remainderJ,
bool reversed, VectorizationPattern vecPattern>
913 inline void fillPhysicsRegisters(
const size_t *
const typeID1Ptr,
const size_t *
const typeID2Ptr,
914 VectorDouble &epsilon24s, VectorDouble &sigmaSquareds, VectorDouble &shift6s,
915 const unsigned int restI,
const unsigned int restJ)
const {
918 HWY_ALIGN std::array<double, _maxVecLengthDouble> epsilons{};
919 HWY_ALIGN std::array<double, _maxVecLengthDouble> sigmas{};
920 HWY_ALIGN std::array<double, _maxVecLengthDouble> shifts{};
922 if constexpr (vecPattern == VectorizationPattern::p1xVec) {
924 epsilons[j] = _PPLibrary->get().getMixing24Epsilon(*typeID1Ptr, *(typeID2Ptr + j));
925 sigmas[j] = _PPLibrary->get().getMixingSigmaSquared(*typeID1Ptr, *(typeID2Ptr + j));
926 if constexpr (applyShift) {
927 shifts[j] = _PPLibrary->get().getMixingShift6(*typeID1Ptr, *(typeID2Ptr + j));
930 }
else if constexpr (vecPattern == VectorizationPattern::p2xVecDiv2) {
931 for (
int i = 0; i < (remainderI ? 1 : 2); ++i) {
934 const auto typeID1 = reversed ? typeID1Ptr - i : typeID1Ptr + i;
935 epsilons[index] = _PPLibrary->get().getMixing24Epsilon(*typeID1, *(typeID2Ptr + j));
936 sigmas[index] = _PPLibrary->get().getMixingSigmaSquared(*typeID1, *(typeID2Ptr + j));
938 if constexpr (applyShift) {
939 shifts[index] = _PPLibrary->get().getMixingShift6(*typeID1, *(typeID2Ptr + j));
943 }
else if constexpr (vecPattern == VectorizationPattern::pVecDiv2x2) {
945 for (
int j = 0; j < (remainderJ ? 1 : 2); ++j) {
947 const auto typeID1 = reversed ? typeID1Ptr - i : typeID1Ptr + i;
949 epsilons[index] = _PPLibrary->get().getMixing24Epsilon(*typeID1, *(typeID2Ptr + j));
950 sigmas[index] = _PPLibrary->get().getMixingSigmaSquared(*typeID1, *(typeID2Ptr + j));
952 if constexpr (applyShift) {
953 shifts[index] = _PPLibrary->get().getMixingShift6(*typeID1, *(typeID2Ptr + j));
957 }
else if constexpr (vecPattern == VectorizationPattern::pVecx1) {
959 auto typeID1 = reversed ? typeID1Ptr - i : typeID1Ptr + i;
960 epsilons[i] = _PPLibrary->get().getMixing24Epsilon(*typeID1, *typeID2Ptr);
961 sigmas[i] = _PPLibrary->get().getMixingSigmaSquared(*typeID1, *typeID2Ptr);
963 if constexpr (applyShift) {
964 shifts[i] = _PPLibrary->get().getMixingShift6(*typeID1, *typeID2Ptr);
969 epsilon24s = highway::Load(tag_double, epsilons.data());
970 sigmaSquareds = highway::Load(tag_double, sigmas.data());
971 if constexpr (applyShift) {
972 shift6s = highway::Load(tag_double, shifts.data());
1009 template <
bool newton3,
bool remainderI,
bool remainderJ,
bool reversed, VectorizationPattern vecPattern>
1010 inline void SoAKernel(
const size_t i,
const size_t j,
const MaskDouble &ownedMaskI,
1011 const int64_t *
const __restrict ownedStatePtr2,
const VectorDouble &x1,
const VectorDouble &y1,
1012 const VectorDouble &z1,
const double *
const __restrict x2Ptr,
1013 const double *
const __restrict y2Ptr,
const double *
const __restrict z2Ptr,
1014 double *
const __restrict fx2Ptr,
double *
const __restrict fy2Ptr,
1015 double *
const __restrict fz2Ptr,
const size_t *
const typeID1Ptr,
const size_t *
const typeID2Ptr,
1016 VectorDouble &fxAcc, VectorDouble &fyAcc, VectorDouble &fzAcc, VectorDouble &virialSumX,
1017 VectorDouble &virialSumY, VectorDouble &virialSumZ, VectorDouble &uPotSum,
1018 const unsigned int restI,
const unsigned int restJ) {
1019 VectorDouble epsilon24s = highway::Undefined(tag_double);
1020 VectorDouble sigmaSquareds = highway::Undefined(tag_double);
1023 if constexpr (useMixing) {
1024 fillPhysicsRegisters<remainderI, remainderJ, reversed, vecPattern>(typeID1Ptr, typeID2Ptr, epsilon24s,
1025 sigmaSquareds, shift6s, restI, restJ);
1027 epsilon24s = highway::Set(tag_double, _epsilon24AoS);
1028 sigmaSquareds = highway::Set(tag_double, _sigmaSquareAoS);
1029 if constexpr (applyShift) {
1030 shift6s = highway::Set(tag_double, _shift6AoS);
1032 shift6s = highway::Zero(tag_double);
1041 fillJRegisters<remainderJ, vecPattern>(j, x2Ptr, y2Ptr, z2Ptr, ownedStatePtr2, x2, y2, z2, ownedMaskJ, restJ);
1044 const auto drX = highway::Sub(x1, x2);
1045 const auto drY = highway::Sub(y1, y2);
1046 const auto drZ = highway::Sub(z1, z2);
1048 const auto drX2 = highway::Mul(drX, drX);
1049 const auto drY2 = highway::Mul(drY, drY);
1050 const auto drZ2 = highway::Mul(drZ, drZ);
1052 const auto dr2 = highway::Add(highway::Add(drX2, drY2), drZ2);
1054 VectorDouble cutoffSquared = highway::Set(tag_double, _cutoffSquareAoS);
1056 const auto dummyMask = highway::And(ownedMaskI, ownedMaskJ);
1057 const auto cutoffDummyMask = highway::MaskedLe(dummyMask, dr2, cutoffSquared);
1059 if (highway::AllFalse(tag_double, cutoffDummyMask)) {
1064 const auto invDr2 = highway::Div(highway::Set(tag_double, 1.0), dr2);
1065 const auto lj2 = highway::Mul(sigmaSquareds, invDr2);
1066 const auto lj4 = highway::Mul(lj2, lj2);
1067 const auto lj6 = highway::Mul(lj2, lj4);
1068 const auto lj12 = highway::Mul(lj6, lj6);
1069 const auto lj12m6 = highway::Sub(lj12, lj6);
1070 const auto lj12m6alj12 = highway::Add(lj12m6, lj12);
1071 const auto lj12m6alj12e = highway::Mul(lj12m6alj12, epsilon24s);
1072 const auto fac = highway::Mul(lj12m6alj12e, invDr2);
1074 const auto facMasked = highway::IfThenElseZero(cutoffDummyMask, fac);
1080 fxAcc = highway::Add(fxAcc, fx);
1081 fyAcc = highway::Add(fyAcc, fy);
1082 fzAcc = highway::Add(fzAcc, fz);
1084 if constexpr (newton3) {
1085 handleNewton3Reduction<remainderJ, vecPattern>(fx, fy, fz, fx2Ptr, fy2Ptr, fz2Ptr, j, restJ);
1088 if constexpr (calculateGlobals) {
1089 auto virialX = highway::Mul(fx, drX);
1090 auto virialY = highway::Mul(fy, drY);
1091 auto virialZ = highway::Mul(fz, drZ);
1093 auto uPot = highway::MulAdd(epsilon24s, lj12m6, shift6s);
1094 auto uPotMasked = highway::IfThenElseZero(cutoffDummyMask, uPot);
1096 auto energyFactor = highway::MaskedSet(tag_double, dummyMask, 1.0);
1098 if constexpr (newton3) {
1099 energyFactor = highway::Add(energyFactor, highway::MaskedSet(tag_double, dummyMask, 1.0));
1102 uPotSum = highway::MulAdd(energyFactor, uPotMasked, uPotSum);
1103 virialSumX = highway::MulAdd(energyFactor, virialX, virialSumX);
1104 virialSumY = highway::MulAdd(energyFactor, virialY, virialSumY);
1105 virialSumZ = highway::MulAdd(energyFactor, virialZ, virialSumZ);
1119 bool newton3)
final {
1120 if (soa.size() == 0 or neighborList.empty())
return;
1122 SoAFunctorVerletImpl<true>(soa, indexFirst, neighborList);
1124 SoAFunctorVerletImpl<false>(soa, indexFirst, neighborList);
1129 template <
bool newton3>
1132 const auto *
const __restrict ownedStatePtr = soa.template begin<Particle_T::AttributeNames::ownershipState>();
1137 const auto *
const __restrict xPtr = soa.template begin<Particle_T::AttributeNames::posX>();
1138 const auto *
const __restrict yPtr = soa.template begin<Particle_T::AttributeNames::posY>();
1139 const auto *
const __restrict zPtr = soa.template begin<Particle_T::AttributeNames::posZ>();
1141 auto *
const __restrict fxPtr = soa.template begin<Particle_T::AttributeNames::forceX>();
1142 auto *
const __restrict fyPtr = soa.template begin<Particle_T::AttributeNames::forceY>();
1143 auto *
const __restrict fzPtr = soa.template begin<Particle_T::AttributeNames::forceZ>();
1145 const auto *
const __restrict typeIDPtr = soa.template begin<Particle_T::AttributeNames::typeId>();
1147 VectorDouble virialSumX = highway::Zero(tag_double);
1148 VectorDouble virialSumY = highway::Zero(tag_double);
1149 VectorDouble virialSumZ = highway::Zero(tag_double);
1150 VectorDouble uPotSum = highway::Zero(tag_double);
1151 VectorDouble fxAcc = highway::Zero(tag_double);
1152 VectorDouble fyAcc = highway::Zero(tag_double);
1153 VectorDouble fzAcc = highway::Zero(tag_double);
1155 const VectorDouble x1 = highway::Set(tag_double, xPtr[indexFirst]);
1156 const VectorDouble y1 = highway::Set(tag_double, yPtr[indexFirst]);
1157 const VectorDouble z1 = highway::Set(tag_double, zPtr[indexFirst]);
1158 const auto ownedI =
static_cast<int64_t
>(ownedStatePtr[indexFirst]);
1159 const VectorDouble ownedStateI = highway::Set(tag_double,
static_cast<double>(ownedI));
1160 const MaskDouble ownedMaskI = highway::Ne(ownedStateI, highway::Zero(tag_double));
1164 HWY_ALIGN std::array<double, _maxVecLengthDouble> x2Tmp{};
1165 HWY_ALIGN std::array<double, _maxVecLengthDouble> y2Tmp{};
1166 HWY_ALIGN std::array<double, _maxVecLengthDouble> z2Tmp{};
1167 HWY_ALIGN std::array<double, _maxVecLengthDouble> fx2Tmp{};
1168 HWY_ALIGN std::array<double, _maxVecLengthDouble> fy2Tmp{};
1169 HWY_ALIGN std::array<double, _maxVecLengthDouble> fz2Tmp{};
1170 HWY_ALIGN std::array<size_t, _maxVecLengthDouble> typeID2Tmp{};
1173 HWY_ALIGN std::array<int64_t, _maxVecLengthDouble> ownedStates2Tmp;
1177 const size_t vecEnd = (neighborList.size() /
_vecLengthDouble) * _vecLengthDouble;
1182 x2Tmp[vecIndex] = xPtr[neighborList[j + vecIndex]];
1183 y2Tmp[vecIndex] = yPtr[neighborList[j + vecIndex]];
1184 z2Tmp[vecIndex] = zPtr[neighborList[j + vecIndex]];
1185 if constexpr (newton3) {
1186 fx2Tmp[vecIndex] = fxPtr[neighborList[j + vecIndex]];
1187 fy2Tmp[vecIndex] = fyPtr[neighborList[j + vecIndex]];
1188 fz2Tmp[vecIndex] = fzPtr[neighborList[j + vecIndex]];
1190 typeID2Tmp[vecIndex] = typeIDPtr[neighborList[j + vecIndex]];
1191 const auto ownedState = ownedStatePtr[neighborList[j + vecIndex]];
1192 ownedStates2Tmp[vecIndex] =
static_cast<int64_t
>(ownedState);
1195 SoAKernel<newton3, false, false, false, VectorizationPattern::p1xVec>(
1196 0, 0, ownedMaskI, ownedStates2Tmp.data(), x1, y1, z1, x2Tmp.data(), y2Tmp.data(), z2Tmp.data(), fx2Tmp.data(),
1197 fy2Tmp.data(), fz2Tmp.data(), &typeIDPtr[indexFirst], typeID2Tmp.data(), fxAcc, fyAcc, fzAcc, virialSumX,
1198 virialSumY, virialSumZ, uPotSum, 0, 0);
1200 if constexpr (newton3) {
1202 fxPtr[neighborList[j + vecIndex]] = fx2Tmp[vecIndex];
1203 fyPtr[neighborList[j + vecIndex]] = fy2Tmp[vecIndex];
1204 fzPtr[neighborList[j + vecIndex]] = fz2Tmp[vecIndex];
1209 const int rest =
static_cast<int>(neighborList.size() & (
_vecLengthDouble - 1));
1212 for (
size_t vecIndex = 0; vecIndex < rest; ++vecIndex) {
1213 x2Tmp[vecIndex] = xPtr[neighborList[j + vecIndex]];
1214 y2Tmp[vecIndex] = yPtr[neighborList[j + vecIndex]];
1215 z2Tmp[vecIndex] = zPtr[neighborList[j + vecIndex]];
1216 if constexpr (newton3) {
1217 fx2Tmp[vecIndex] = fxPtr[neighborList[j + vecIndex]];
1218 fy2Tmp[vecIndex] = fyPtr[neighborList[j + vecIndex]];
1219 fz2Tmp[vecIndex] = fzPtr[neighborList[j + vecIndex]];
1221 typeID2Tmp[vecIndex] = typeIDPtr[neighborList[j + vecIndex]];
1222 const auto ownedState = ownedStatePtr[neighborList[j + vecIndex]];
1223 ownedStates2Tmp[vecIndex] =
static_cast<int64_t
>(ownedState);
1226 SoAKernel<newton3, false, true, false, VectorizationPattern::p1xVec>(
1227 0, 0, ownedMaskI, ownedStates2Tmp.data(), x1, y1, z1, x2Tmp.data(), y2Tmp.data(), z2Tmp.data(), fx2Tmp.data(),
1228 fy2Tmp.data(), fz2Tmp.data(), &typeIDPtr[indexFirst], typeID2Tmp.data(), fxAcc, fyAcc, fzAcc, virialSumX,
1229 virialSumY, virialSumZ, uPotSum, 0, rest);
1231 if constexpr (newton3) {
1232 for (
long vecIndex = 0; vecIndex <
_vecLengthDouble && vecIndex < rest; ++vecIndex) {
1233 fxPtr[neighborList[j + vecIndex]] = fx2Tmp[vecIndex];
1234 fyPtr[neighborList[j + vecIndex]] = fy2Tmp[vecIndex];
1235 fzPtr[neighborList[j + vecIndex]] = fz2Tmp[vecIndex];
1240 fxPtr[indexFirst] += highway::ReduceSum(tag_double, fxAcc);
1241 fyPtr[indexFirst] += highway::ReduceSum(tag_double, fyAcc);
1242 fzPtr[indexFirst] += highway::ReduceSum(tag_double, fzAcc);
1244 if constexpr (calculateGlobals) {
1245 computeGlobals(virialSumX, virialSumY, virialSumZ, uPotSum);
1254 return std::array<typename Particle_T::AttributeNames, 9>{Particle_T::AttributeNames::id,
1255 Particle_T::AttributeNames::posX,
1256 Particle_T::AttributeNames::posY,
1257 Particle_T::AttributeNames::posZ,
1258 Particle_T::AttributeNames::forceX,
1259 Particle_T::AttributeNames::forceY,
1260 Particle_T::AttributeNames::forceZ,
1261 Particle_T::AttributeNames::typeId,
1262 Particle_T::AttributeNames::ownershipState};
1269 return std::array<typename Particle_T::AttributeNames, 6>{
1270 Particle_T::AttributeNames::id, Particle_T::AttributeNames::posX,
1271 Particle_T::AttributeNames::posY, Particle_T::AttributeNames::posZ,
1272 Particle_T::AttributeNames::typeId, Particle_T::AttributeNames::ownershipState};
1279 return std::array<typename Particle_T::AttributeNames, 3>{
1280 Particle_T::AttributeNames::forceX, Particle_T::AttributeNames::forceY, Particle_T::AttributeNames::forceZ};
1299 _potentialEnergySum = 0.;
1300 _virialSum = {0., 0., 0.};
1301 _postProcessed =
false;
1302 for (
size_t i = 0; i < _aosThreadData.size(); ++i) {
1303 _aosThreadData[i].setZero();
1312 using namespace autopas::utils::ArrayMath::literals;
1314 if (_postProcessed) {
1316 "Already postprocessed, endTraversal(bool newton3) was called twice without calling initTraversal().");
1319 if (calculateGlobals) {
1320 for (
size_t i = 0; i < _aosThreadData.size(); ++i) {
1321 _potentialEnergySum += _aosThreadData[i].potentialEnergySum;
1322 _virialSum += _aosThreadData[i].virialSum;
1326 _potentialEnergySum *= 0.5;
1330 _potentialEnergySum /= 6.;
1331 _postProcessed =
true;
1333 AutoPasLog(DEBUG,
"Final potential energy {}", _potentialEnergySum);
1334 AutoPasLog(DEBUG,
"Final virial {}", _virialSum[0] + _virialSum[1] + _virialSum[2]);
1343 if (not calculateGlobals) {
1345 "Trying to get upot even though calculateGlobals is false. If you want this functor to calculate global "
1346 "values, please specify calculateGlobals to be true.");
1348 if (not _postProcessed) {
1351 return _potentialEnergySum;
1359 if (not calculateGlobals) {
1361 "Trying to get virial even though calculateGlobals is false. If you want this functor to calculate global "
1362 "values, please specify calculateGlobals to be true.");
1364 if (not _postProcessed) {
1366 "Cannot get virial, because endTraversal was not called.");
1368 return _virialSum[0] + _virialSum[1] + _virialSum[2];
1380 _epsilon24AoS = epsilon24;
1381 _sigmaSquareAoS = sigmaSquare;
1382 if constexpr (applyShift) {
1398 class AoSThreadData {
1400 AoSThreadData() : virialSum{0., 0., 0.}, potentialEnergySum{0.} {}
1403 virialSum = {0., 0., 0.};
1404 potentialEnergySum = 0.;
1407 std::array<double, 3> virialSum{};
1408 double potentialEnergySum{};
1411 double __remainingTo64[(64 - 4 *
sizeof(double)) /
sizeof(double)];
1413 static_assert(
sizeof(AoSThreadData) % 64 == 0,
"AoSThreadData has wrong size");
1416 const double _cutoffSquareAoS{0.};
1418 double _epsilon24AoS{0.}, _sigmaSquareAoS{0.}, _shift6AoS{0.};
1422 std::optional<std::reference_wrapper<ParticlePropertiesLibrary<double, size_t>>> _PPLibrary;
1425 double _potentialEnergySum{0.};
1426 std::array<double, 3> _virialSum{0., 0., 0.};
1427 std::vector<AoSThreadData> _aosThreadData{};
1430 bool _postProcessed{
false};
1436 static constexpr std::array<VectorizationPattern, 4> _vecPatternsAllowed = {
1437 VectorizationPattern::p1xVec, VectorizationPattern::p2xVecDiv2, VectorizationPattern::pVecDiv2x2,
1438 VectorizationPattern::pVecx1};
decltype(highway::FirstN(tag_long, 2)) MaskLong
Type for a Long Mask.
Definition: LJFunctorHWY.h:49
constexpr highway::Half< highway::DFromV< VectorDouble > > tag_double_half
Highway tag for a half-filled double register.
Definition: LJFunctorHWY.h:45
decltype(highway::Zero(tag_double)) VectorDouble
Type for a Double vector register.
Definition: LJFunctorHWY.h:41
constexpr highway::ScalableTag< double > tag_double
Highway tag for full double register.
Definition: LJFunctorHWY.h:29
constexpr size_t _maxVecLengthDouble
Upper bound on the number of double values in a full register.
Definition: LJFunctorHWY.h:39
autopas::VectorizationPatternOption::Value VectorizationPattern
Vectorization Pattern Type.
Definition: LJFunctorHWY.h:51
decltype(highway::Zero(tag_long)) VectorLong
Type for a Long vector register.
Definition: LJFunctorHWY.h:43
HWY_LANES_CONSTEXPR size_t _vecLengthDouble
Number of double values in a full register.
Definition: LJFunctorHWY.h:35
constexpr highway::ScalableTag< int64_t > tag_long
Highway tag for full long register.
Definition: LJFunctorHWY.h:31
decltype(highway::FirstN(tag_double, 1)) MaskDouble
Type for a Double Mask.
Definition: LJFunctorHWY.h:47
#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
static double calcShift6(double epsilon24, double sigmaSquared, double cutoffSquared)
Calculate the shift multiplied 6 of the lennard jones potential from given cutoff,...
Definition: ParticlePropertiesLibrary.h:576
AlignedAllocator class.
Definition: AlignedAllocator.h:29
PairwiseFunctor class.
Definition: PairwiseFunctor.h:45
PairwiseFunctor(double cutoff)
Constructor.
Definition: PairwiseFunctor.h:56
View on a fixed part of a SoA between a start index and an end index.
Definition: SoAView.h:25
size_t size() const
Returns the number of particles in the view.
Definition: SoAView.h:85
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 lennard-jones interactions between two particles (molecules) This functor uses th...
Definition: LJFunctorHWY.h:70
double getVirial() const
Get the virial.
Definition: LJFunctorHWY.h:1358
bool isRelevantForTuning() final
Specifies whether the functor should be considered for the auto-tuning process.
Definition: LJFunctorHWY.h:110
void SoAFunctorPair(autopas::SoAView< SoAArraysType > soa1, autopas::SoAView< SoAArraysType > soa2, bool newton3) final
PairwiseFunctor for structure of arrays (SoA)
Definition: LJFunctorHWY.h:231
LJFunctorHWY(double cutoff, std::optional< std::reference_wrapper< ParticlePropertiesLibrary< double, size_t > > > particlePropertiesLibrary=std::nullopt)
Constructor for Functor with mixing enabled/disabled.
Definition: LJFunctorHWY.h:85
void setVecPattern(const VectorizationPattern vecPattern) final
Setter for the vectorization pattern to be used.
Definition: LJFunctorHWY.h:1392
void initTraversal() final
Reset the global values.
Definition: LJFunctorHWY.h:1298
void SoAFunctorSingle(autopas::SoAView< SoAArraysType > soa, const bool newton3) final
PairwiseFunctor for structure of arrays (SoA)
Definition: LJFunctorHWY.h:190
void AoSFunctor(Particle_T &i, Particle_T &j, bool newton3) final
PairwiseFunctor for arrays of structures (AoS).
Definition: LJFunctorHWY.h:134
bool allowsNonNewton3() final
Specifies whether the functor is capable of non-Newton3-like functors.
Definition: LJFunctorHWY.h:116
void SoAFunctorPairSorted(autopas::SoAView< SoAArraysType > soa1, autopas::SoAView< SoAArraysType > soa2, const autopas::SoASortingData &sortingData, bool newton3) final
SoAFunctorPair on pre-sorted, pre-packed SoA views.
Definition: LJFunctorHWY.h:274
static constexpr auto getNeededAttr()
Get attributes needed for computation.
Definition: LJFunctorHWY.h:1253
static constexpr auto getNeededAttr(std::false_type)
Get attributes needed for computation without N3 optimization.
Definition: LJFunctorHWY.h:1268
static constexpr bool supportsSoASorting
Whether this functor supports the SortedSoAView optimization path (SoAFunctorPairSorted).
Definition: LJFunctorHWY.h:1286
LJFunctorHWY()=delete
Deleted default constructor.
static constexpr bool getMixing()
Definition: LJFunctorHWY.h:1292
std::string getName() final
Returns name of functor.
Definition: LJFunctorHWY.h:108
static constexpr auto getComputedAttr()
Get attributes computed by this functor.
Definition: LJFunctorHWY.h:1278
bool allowsNewton3() final
Specifies whether the functor is capable of Newton3-like functors.
Definition: LJFunctorHWY.h:112
void SoAFunctorVerlet(autopas::SoAView< SoAArraysType > soa, const size_t indexFirst, const std::vector< size_t, autopas::AlignedAllocator< size_t > > &neighborList, bool newton3) final
PairwiseFunctor for structure of arrays (SoA) for neighbor lists.
Definition: LJFunctorHWY.h:1117
double getPotentialEnergy() const
Get the potential Energy.
Definition: LJFunctorHWY.h:1342
bool isVecPatternAllowed(const VectorizationPattern vecPattern) final
Specifies whether the functor is capable of using the specified Vectorization Pattern in the SoA func...
Definition: LJFunctorHWY.h:127
void setParticleProperties(const double epsilon24, const double sigmaSquare)
Sets the particle properties constants for this functor.
Definition: LJFunctorHWY.h:1379
void endTraversal(const bool newton3) final
Accumulates global values, e.g.
Definition: LJFunctorHWY.h:1311
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
std::optional< std::reference_wrapper< T > > optRef
Short alias for std::optional<std::reference_wrapper<T>>
Definition: optRef.h:16
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
OwnershipState
Enum that specifies the state of ownership.
Definition: OwnershipState.h:20
@ dummy
Dummy or deleted state, a particle with this state is not an actual particle!
@ owned
Owned state, a particle with this state is an actual particle and owned by the current AutoPas object...
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
Precomputed index bounds for iterating a pre-sorted SoA pair.
Definition: PairwiseFunctor.h:30