AutoPas  3.0.0
Loading...
Searching...
No Matches
LJFunctorHWY.h
Go to the documentation of this file.
1
8#pragma once
9
10#include <hwy/highway.h>
11
12#include <algorithm>
13#include <optional>
14#include <vector>
15
24
25namespace mdLib {
26
27namespace highway = hwy::HWY_NAMESPACE;
29constexpr highway::ScalableTag<double> tag_double;
31constexpr highway::ScalableTag<int64_t> tag_long;
35HWY_LANES_CONSTEXPR inline size_t _vecLengthDouble{highway::Lanes(tag_double)};
39constexpr size_t _maxVecLengthDouble{highway::MaxLanes(tag_double)};
41using VectorDouble = decltype(highway::Zero(tag_double));
43using VectorLong = decltype(highway::Zero(tag_long));
45constexpr highway::Half<highway::DFromV<VectorDouble>> tag_double_half;
47using MaskDouble = decltype(highway::FirstN(tag_double, 1));
49using MaskLong = decltype(highway::FirstN(tag_long, 2));
51using VectorizationPattern = autopas::VectorizationPatternOption::Value;
52
64template <class Particle_T, bool applyShift = false, bool useMixing = false,
65 autopas::FunctorN3Modes useNewton3 = autopas::FunctorN3Modes::Both, bool calculateGlobals = false,
66 bool countFLOPs = false, bool relevantForTuning = true>
67
69 : public autopas::PairwiseFunctor<Particle_T, LJFunctorHWY<Particle_T, applyShift, useMixing, useNewton3,
70 calculateGlobals, countFLOPs, relevantForTuning>> {
71 using SoAArraysType = Particle_T::SoAArraysType;
72
73 public:
77 LJFunctorHWY() = delete;
78
85 explicit LJFunctorHWY(double cutoff, std::optional<std::reference_wrapper<ParticlePropertiesLibrary<double, size_t>>>
86 particlePropertiesLibrary = std::nullopt)
87 : autopas::PairwiseFunctor<Particle_T, LJFunctorHWY>(cutoff),
88 _cutoffSquareAoS{cutoff * cutoff},
89 _PPLibrary{particlePropertiesLibrary} {
90 if (calculateGlobals) {
91 _aosThreadData.resize(autopas::autopas_get_max_threads());
92 }
93 if constexpr (countFLOPs) {
94 AutoPasLog(DEBUG, "Using LJFunctorHWY with countFLOPs but FLOP counting is not implemented.");
95 }
96
97 if constexpr (useMixing) {
98 if (not _PPLibrary.has_value()) {
99 throw std::runtime_error("Mixing is enabled but no ParticlePropertiesLibrary was provided!");
100 }
101 } else {
102 if (_PPLibrary.has_value()) {
103 throw std::runtime_error("Mixing is disabled but a ParticlePropertiesLibrary was provided!");
104 }
105 }
106 }
107
108 std::string getName() final { return "LJFunctorHWY"; }
109
110 bool isRelevantForTuning() final { return relevantForTuning; }
111
112 bool allowsNewton3() final {
113 return useNewton3 == autopas::FunctorN3Modes::Newton3Only or useNewton3 == autopas::FunctorN3Modes::Both;
114 }
115
116 bool allowsNonNewton3() final {
117 return useNewton3 == autopas::FunctorN3Modes::Newton3Off or useNewton3 == autopas::FunctorN3Modes::Both;
118 }
119
127 bool isVecPatternAllowed(const VectorizationPattern vecPattern) final {
128 return std::ranges::find(_vecPatternsAllowed, vecPattern) != _vecPatternsAllowed.end();
129 }
130
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()) {
137 return;
138 }
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());
147 }
148 }
149 const auto dr = i.getR() - j.getR();
150 const double dr2 = autopas::utils::ArrayMath::dot(dr, dr);
151
152 if (dr2 > _cutoffSquareAoS) {
153 return;
154 }
155
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;
163 i.addF(f);
164 if (newton3) {
165 j.subF(f);
166 }
167 if (calculateGlobals) {
168 const auto virial = dr * f;
169 const double potentialEnergy6 = epsilon24 * lj12m6 + shift6;
170
171 const int threadnum = autopas::autopas_get_thread_num();
172
173 if (i.isOwned()) {
174 _aosThreadData[threadnum].potentialEnergySum += potentialEnergy6;
175 _aosThreadData[threadnum].virialSum += virial;
176 }
177 // for non-newton3 the second particle will be considered in a separate calculation
178 if (newton3 and j.isOwned()) {
179 // for non-newton3 the division is in the post-processing step.
180 _aosThreadData[threadnum].potentialEnergySum += potentialEnergy6;
181 _aosThreadData[threadnum].virialSum += virial;
182 }
183 }
184 }
185
190 inline void SoAFunctorSingle(autopas::SoAView<SoAArraysType> soa, const bool newton3) final {
191 if (soa.size() == 0) return;
192
193 // obtain iterators for the various values
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>();
197
198 const auto *const __restrict ownedStatePtr = soa.template begin<Particle_T::AttributeNames::ownershipState>();
199
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>();
203
204 const auto *const __restrict typeIDptr = soa.template begin<Particle_T::AttributeNames::typeId>();
205
206 // initialize and declare vector variables
207 auto virialSumX = highway::Zero(tag_double);
208 auto virialSumY = highway::Zero(tag_double);
209 auto virialSumZ = highway::Zero(tag_double);
210 auto uPotSum = highway::Zero(tag_double);
211
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!");
215
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);
219 }
220
221 if constexpr (calculateGlobals) {
222 computeGlobals(virialSumX, virialSumY, virialSumZ, uPotSum);
223 }
224 }
225
230 bool newton3) final {
231 switch (_vecPattern) {
232 case VectorizationPattern::p1xVec: {
233 if (newton3) {
234 SoAFunctorPairImpl<true, false, VectorizationPattern::p1xVec>(soa1, soa2);
235 } else {
236 SoAFunctorPairImpl<false, false, VectorizationPattern::p1xVec>(soa1, soa2);
237 }
238 break;
239 }
240 case VectorizationPattern::p2xVecDiv2: {
241 if (newton3) {
242 SoAFunctorPairImpl<true, false, VectorizationPattern::p2xVecDiv2>(soa1, soa2);
243 } else {
244 SoAFunctorPairImpl<false, false, VectorizationPattern::p2xVecDiv2>(soa1, soa2);
245 }
246 break;
247 }
248 case VectorizationPattern::pVecDiv2x2: {
249 if (newton3) {
250 SoAFunctorPairImpl<true, false, VectorizationPattern::pVecDiv2x2>(soa1, soa2);
251 } else {
252 SoAFunctorPairImpl<false, false, VectorizationPattern::pVecDiv2x2>(soa1, soa2);
253 }
254 break;
255 }
256 case VectorizationPattern::pVecx1: {
257 if (newton3) {
258 SoAFunctorPairImpl<true, false, VectorizationPattern::pVecx1>(soa1, soa2);
259 } else {
260 SoAFunctorPairImpl<false, false, VectorizationPattern::pVecx1>(soa1, soa2);
261 }
262 break;
263 }
264 default:
265 autopas::utils::ExceptionHandler::exception("Unknown VectorizationPattern!");
266 }
267 }
268
273 const autopas::SoASortingData &sortingData, bool newton3) final {
274 if (soa1.size() == 0 or soa2.size() == 0) {
275 return;
276 }
277 switch (_vecPattern) {
278 case VectorizationPattern::p1xVec: {
279 if (newton3) {
280 SoAFunctorPairImpl<true, true, VectorizationPattern::p1xVec>(soa1, soa2, sortingData);
281 } else {
282 SoAFunctorPairImpl<false, true, VectorizationPattern::p1xVec>(soa1, soa2, sortingData);
283 }
284 break;
285 }
286 case VectorizationPattern::p2xVecDiv2: {
287 if (newton3) {
288 SoAFunctorPairImpl<true, true, VectorizationPattern::p2xVecDiv2>(soa1, soa2, sortingData);
289 } else {
290 SoAFunctorPairImpl<false, true, VectorizationPattern::p2xVecDiv2>(soa1, soa2, sortingData);
291 }
292 break;
293 }
294 case VectorizationPattern::pVecDiv2x2: {
295 if (newton3) {
296 SoAFunctorPairImpl<true, true, VectorizationPattern::pVecDiv2x2>(soa1, soa2, sortingData);
297 } else {
298 SoAFunctorPairImpl<false, true, VectorizationPattern::pVecDiv2x2>(soa1, soa2, sortingData);
299 }
300 break;
301 }
302 case VectorizationPattern::pVecx1: {
303 if (newton3) {
304 SoAFunctorPairImpl<true, true, VectorizationPattern::pVecx1>(soa1, soa2, sortingData);
305 } else {
306 SoAFunctorPairImpl<false, true, VectorizationPattern::pVecx1>(soa1, soa2, sortingData);
307 }
308 break;
309 }
310 default:
311 autopas::utils::ExceptionHandler::exception("Unknown VectorizationPattern!");
312 }
313 }
314
315 private:
320 template <VectorizationPattern vecPattern>
321 static size_t iStepSize() {
322 if constexpr (vecPattern == VectorizationPattern::p1xVec) {
323 return 1;
324 }
325 if constexpr (vecPattern == VectorizationPattern::p2xVecDiv2) {
326 return 2;
327 }
328 if constexpr (vecPattern == VectorizationPattern::pVecDiv2x2) {
329 return _vecLengthDouble / 2;
330 }
331 if constexpr (vecPattern == VectorizationPattern::pVecx1) {
332 return _vecLengthDouble;
333 }
334 autopas::utils::ExceptionHandler::exception("Unknown VectorizationPattern!");
335 return {};
336 }
337
342 template <VectorizationPattern vecPattern>
343 static size_t jStepSize() {
344 if constexpr (vecPattern == VectorizationPattern::p1xVec) {
345 return _vecLengthDouble;
346 }
347 if constexpr (vecPattern == VectorizationPattern::p2xVecDiv2) {
348 return _vecLengthDouble / 2;
349 }
350 if constexpr (vecPattern == VectorizationPattern::pVecDiv2x2) {
351 return 2;
352 }
353 if constexpr (vecPattern == VectorizationPattern::pVecx1) {
354 return 1;
355 }
356 autopas::utils::ExceptionHandler::exception("Unknown VectorizationPattern!");
357 return {};
358 }
359
368 template <VectorizationPattern vecPattern>
369 static constexpr bool checkSecondLoopCondition(std::ptrdiff_t i, size_t j) {
370 // Round i down to the nearest multiple of jStep (the j-lane width) to get the exclusive upper bound.
371 const std::ptrdiff_t jStep = static_cast<std::ptrdiff_t>(jStepSize<vecPattern>());
372 const std::ptrdiff_t limit = i - (i % jStep);
373 return j < static_cast<size_t>(limit);
374 }
393 template <bool remainder, bool reversed, VectorizationPattern vecPattern>
394 static void fillIRegisters(const size_t i, const double *const __restrict xPtr, const double *const __restrict yPtr,
395 const double *const __restrict zPtr,
396 const autopas::OwnershipState *const __restrict ownedStatePtr, VectorDouble &x1,
397 VectorDouble &y1, VectorDouble &z1, MaskDouble &ownedMaskI, const size_t restI) {
398 VectorLong ownedStateILong = highway::Zero(tag_long);
399
400 if constexpr (vecPattern == VectorizationPattern::p1xVec) {
401 const auto owned = static_cast<int64_t>(ownedStatePtr[i]);
402 ownedStateILong = highway::Set(tag_long, owned);
403
404 x1 = highway::Set(tag_double, xPtr[i]);
405 y1 = highway::Set(tag_double, yPtr[i]);
406 z1 = highway::Set(tag_double, zPtr[i]);
407 } else if constexpr (vecPattern == VectorizationPattern::p2xVecDiv2) {
408 const auto ownedFirst = static_cast<int64_t>(ownedStatePtr[i]);
409 ownedStateILong = highway::Set(tag_long, ownedFirst);
410
411 x1 = highway::Set(tag_double, xPtr[i]);
412 y1 = highway::Set(tag_double, yPtr[i]);
413 z1 = highway::Set(tag_double, zPtr[i]);
414
415 VectorLong tmpOwnedI = highway::Zero(tag_long);
416 VectorDouble tmpX1 = highway::Zero(tag_double);
417 VectorDouble tmpY1 = highway::Zero(tag_double);
418 VectorDouble tmpZ1 = highway::Zero(tag_double);
419
420 if constexpr (not remainder) {
421 const auto index = reversed ? i - 1 : i + 1;
422 const auto ownedSecond = static_cast<int64_t>(ownedStatePtr[index]);
423 tmpOwnedI = highway::Set(tag_long, ownedSecond);
424 tmpX1 = highway::Set(tag_double, xPtr[index]);
425 tmpY1 = highway::Set(tag_double, yPtr[index]);
426 tmpZ1 = highway::Set(tag_double, zPtr[index]);
427 }
428
429 ownedStateILong = highway::ConcatLowerLower(tag_long, tmpOwnedI, ownedStateILong);
430 x1 = highway::ConcatLowerLower(tag_double, tmpX1, x1);
431 y1 = highway::ConcatLowerLower(tag_double, tmpY1, y1);
432 z1 = highway::ConcatLowerLower(tag_double, tmpZ1, z1);
433 } else if constexpr (vecPattern == VectorizationPattern::pVecDiv2x2) {
434 const int index = reversed ? (remainder ? 0 : i - _vecLengthDouble / 2 + 1) : i;
435 const int lanes = remainder ? restI : _vecLengthDouble / 2;
436
437 ownedStateILong = highway::LoadN(tag_long, reinterpret_cast<const int64_t *>(&ownedStatePtr[index]), lanes);
438
439 x1 = highway::LoadN(tag_double, &xPtr[index], lanes);
440 y1 = highway::LoadN(tag_double, &yPtr[index], lanes);
441 z1 = highway::LoadN(tag_double, &zPtr[index], lanes);
442
443 ownedStateILong = highway::ConcatLowerLower(tag_long, ownedStateILong, ownedStateILong);
444 x1 = highway::ConcatLowerLower(tag_double, x1, x1);
445 y1 = highway::ConcatLowerLower(tag_double, y1, y1);
446 z1 = highway::ConcatLowerLower(tag_double, z1, z1);
447 } else if constexpr (vecPattern == VectorizationPattern::pVecx1) {
448 const auto index = reversed ? (remainder ? 0 : i - _vecLengthDouble + 1) : i;
449
450 if constexpr (remainder) {
451 x1 = highway::LoadN(tag_double, &xPtr[index], restI);
452 y1 = highway::LoadN(tag_double, &yPtr[index], restI);
453 z1 = highway::LoadN(tag_double, &zPtr[index], restI);
454
455 ownedStateILong = highway::LoadN(tag_long, reinterpret_cast<const int64_t *>(&ownedStatePtr[index]), restI);
456 } else {
457 x1 = highway::LoadU(tag_double, &xPtr[index]);
458 y1 = highway::LoadU(tag_double, &yPtr[index]);
459 z1 = highway::LoadU(tag_double, &zPtr[index]);
460
461 ownedStateILong = highway::LoadU(tag_long, reinterpret_cast<const int64_t *>(&ownedStatePtr[index]));
462 }
463 }
464
465 MaskLong ownedMaskILong = highway::Ne(ownedStateILong, highway::Zero(tag_long));
466
467 // convert to a double mask since we perform logical operations with other double masks in the kernel.
468 ownedMaskI = highway::RebindMask(tag_double, ownedMaskILong);
469 }
470
471 template <bool remainder, VectorizationPattern vecPattern>
472 static void handleNewton3Reduction(const VectorDouble &fx, const VectorDouble &fy, const VectorDouble &fz,
473 double *const __restrict fx2Ptr, double *const __restrict fy2Ptr,
474 double *const __restrict fz2Ptr, const size_t j, const size_t rest) {
475 if constexpr (vecPattern == VectorizationPattern::p1xVec) {
476 const VectorDouble fx2 =
477 remainder ? highway::LoadN(tag_double, &fx2Ptr[j], rest) : highway::LoadU(tag_double, &fx2Ptr[j]);
478 const VectorDouble fy2 =
479 remainder ? highway::LoadN(tag_double, &fy2Ptr[j], rest) : highway::LoadU(tag_double, &fy2Ptr[j]);
480 const VectorDouble fz2 =
481 remainder ? highway::LoadN(tag_double, &fz2Ptr[j], rest) : highway::LoadU(tag_double, &fz2Ptr[j]);
482
483 const VectorDouble fx2New = highway::Sub(fx2, fx);
484 const VectorDouble fy2New = highway::Sub(fy2, fy);
485 const VectorDouble fz2New = highway::Sub(fz2, fz);
486
487 remainder ? highway::StoreN(fx2New, tag_double, &fx2Ptr[j], rest)
488 : highway::StoreU(fx2New, tag_double, &fx2Ptr[j]);
489 remainder ? highway::StoreN(fy2New, tag_double, &fy2Ptr[j], rest)
490 : highway::StoreU(fy2New, tag_double, &fy2Ptr[j]);
491 remainder ? highway::StoreN(fz2New, tag_double, &fz2Ptr[j], rest)
492 : highway::StoreU(fz2New, tag_double, &fz2Ptr[j]);
493 } else if constexpr (vecPattern == VectorizationPattern::p2xVecDiv2) {
494 const auto lowerFx = highway::LowerHalf(tag_double_half, fx);
495 const auto lowerFy = highway::LowerHalf(tag_double_half, fy);
496 const auto lowerFz = highway::LowerHalf(tag_double_half, fz);
497
498 const auto upperFx = highway::UpperHalf(tag_double_half, fx);
499 const auto upperFy = highway::UpperHalf(tag_double_half, fy);
500 const auto upperFz = highway::UpperHalf(tag_double_half, fz);
501
502 const auto fxCombined = highway::Add(lowerFx, upperFx);
503 const auto fyCombined = highway::Add(lowerFy, upperFy);
504 const auto fzCombined = highway::Add(lowerFz, upperFz);
505
506 const int lanes = remainder ? rest : _vecLengthDouble / 2;
507
508 const auto fx2 = highway::LoadN(tag_double_half, &fx2Ptr[j], lanes);
509 const auto fy2 = highway::LoadN(tag_double_half, &fy2Ptr[j], lanes);
510 const auto fz2 = highway::LoadN(tag_double_half, &fz2Ptr[j], lanes);
511
512 const auto newFx = highway::Sub(fx2, fxCombined);
513 const auto newFy = highway::Sub(fy2, fyCombined);
514 const auto newFz = highway::Sub(fz2, fzCombined);
515
516 highway::StoreN(newFx, tag_double_half, &fx2Ptr[j], lanes);
517 highway::StoreN(newFy, tag_double_half, &fy2Ptr[j], lanes);
518 highway::StoreN(newFz, tag_double_half, &fz2Ptr[j], lanes);
519 } else if constexpr (vecPattern == VectorizationPattern::pVecDiv2x2) {
520 const auto lowerFx = highway::LowerHalf(tag_double_half, fx);
521 const auto lowerFy = highway::LowerHalf(tag_double_half, fy);
522 const auto lowerFz = highway::LowerHalf(tag_double_half, fz);
523
524 fx2Ptr[j] -= highway::ReduceSum(tag_double_half, lowerFx);
525 fy2Ptr[j] -= highway::ReduceSum(tag_double_half, lowerFy);
526 fz2Ptr[j] -= highway::ReduceSum(tag_double_half, lowerFz);
527
528 if constexpr (not remainder) {
529 const auto upperFx = highway::UpperHalf(tag_double_half, fx);
530 const auto upperFy = highway::UpperHalf(tag_double_half, fy);
531 const auto upperFz = highway::UpperHalf(tag_double_half, fz);
532
533 fx2Ptr[j + 1] -= highway::ReduceSum(tag_double_half, upperFx);
534 fy2Ptr[j + 1] -= highway::ReduceSum(tag_double_half, upperFy);
535 fz2Ptr[j + 1] -= highway::ReduceSum(tag_double_half, upperFz);
536 }
537 } else if constexpr (vecPattern == VectorizationPattern::pVecx1) {
538 fx2Ptr[j] -= highway::ReduceSum(tag_double, fx);
539 fy2Ptr[j] -= highway::ReduceSum(tag_double, fy);
540 fz2Ptr[j] -= highway::ReduceSum(tag_double, fz);
541 }
542 }
543
544 template <bool reversed, bool remainder, VectorizationPattern vecPattern>
545 static void reduceAccumulatedForce(const size_t i, double *const __restrict fxPtr, double *const __restrict fyPtr,
546 double *const __restrict fzPtr, const VectorDouble &fxAcc,
547 const VectorDouble &fyAcc, const VectorDouble &fzAcc, const int restI) {
548 if constexpr (vecPattern == VectorizationPattern::p1xVec) {
549 fxPtr[i] += highway::ReduceSum(tag_double, fxAcc);
550 fyPtr[i] += highway::ReduceSum(tag_double, fyAcc);
551 fzPtr[i] += highway::ReduceSum(tag_double, fzAcc);
552 } else if constexpr (vecPattern == VectorizationPattern::p2xVecDiv2) {
553 const auto lowerFxAcc = highway::LowerHalf(tag_double_half, fxAcc);
554 const auto lowerFyAcc = highway::LowerHalf(tag_double_half, fyAcc);
555 const auto lowerFzAcc = highway::LowerHalf(tag_double_half, fzAcc);
556
557 fxPtr[i] += highway::ReduceSum(tag_double_half, lowerFxAcc);
558 fyPtr[i] += highway::ReduceSum(tag_double_half, lowerFyAcc);
559 fzPtr[i] += highway::ReduceSum(tag_double_half, lowerFzAcc);
560
561 if constexpr (not remainder) {
562 const auto upperFxAcc = highway::UpperHalf(tag_double_half, fxAcc);
563 const auto upperFyAcc = highway::UpperHalf(tag_double_half, fyAcc);
564 const auto upperFzAcc = highway::UpperHalf(tag_double_half, fzAcc);
565
566 const auto index = reversed ? i - 1 : i + 1;
567 fxPtr[index] += highway::ReduceSum(tag_double_half, upperFxAcc);
568 fyPtr[index] += highway::ReduceSum(tag_double_half, upperFyAcc);
569 fzPtr[index] += highway::ReduceSum(tag_double_half, upperFzAcc);
570 }
571 } else if constexpr (vecPattern == VectorizationPattern::pVecDiv2x2) {
572 const auto lowerFxAcc = highway::LowerHalf(tag_double_half, fxAcc);
573 const auto lowerFyAcc = highway::LowerHalf(tag_double_half, fyAcc);
574 const auto lowerFzAcc = highway::LowerHalf(tag_double_half, fzAcc);
575
576 const auto upperFxAcc = highway::UpperHalf(tag_double_half, fxAcc);
577 const auto upperFyAcc = highway::UpperHalf(tag_double_half, fyAcc);
578 const auto upperFzAcc = highway::UpperHalf(tag_double_half, fzAcc);
579
580 const auto fxAccCombined = highway::Add(lowerFxAcc, upperFxAcc);
581 const auto fyAccCombined = highway::Add(lowerFyAcc, upperFyAcc);
582 const auto fzAccCombined = highway::Add(lowerFzAcc, upperFzAcc);
583
584 const int index = reversed ? (remainder ? 0 : i - _vecLengthDouble / 2 + 1) : i;
585
586 const int lanes = remainder ? restI : _vecLengthDouble / 2;
587
588 const auto oldFx = highway::LoadN(tag_double_half, &fxPtr[index], lanes);
589 const auto oldFy = highway::LoadN(tag_double_half, &fyPtr[index], lanes);
590 const auto oldFz = highway::LoadN(tag_double_half, &fzPtr[index], lanes);
591
592 const auto newFx = highway::Add(oldFx, fxAccCombined);
593 const auto newFy = highway::Add(oldFy, fyAccCombined);
594 const auto newFz = highway::Add(oldFz, fzAccCombined);
595
596 highway::StoreN(newFx, tag_double_half, &fxPtr[index], lanes);
597 highway::StoreN(newFy, tag_double_half, &fyPtr[index], lanes);
598 highway::StoreN(newFz, tag_double_half, &fzPtr[index], lanes);
599 } else if constexpr (vecPattern == VectorizationPattern::pVecx1) {
600 const VectorDouble oldFx =
601 remainder ? highway::LoadN(tag_double, &fxPtr[i], restI) : highway::LoadU(tag_double, &fxPtr[i]);
602 const VectorDouble oldFy =
603 remainder ? highway::LoadN(tag_double, &fyPtr[i], restI) : highway::LoadU(tag_double, &fyPtr[i]);
604 const VectorDouble oldFz =
605 remainder ? highway::LoadN(tag_double, &fzPtr[i], restI) : highway::LoadU(tag_double, &fzPtr[i]);
606
607 const VectorDouble fxNew = highway::Add(oldFx, fxAcc);
608 const VectorDouble fyNew = highway::Add(oldFy, fyAcc);
609 const VectorDouble fzNew = highway::Add(oldFz, fzAcc);
610
611 remainder ? highway::StoreN(fxNew, tag_double, &fxPtr[i], restI) : highway::StoreU(fxNew, tag_double, &fxPtr[i]);
612 remainder ? highway::StoreN(fyNew, tag_double, &fyPtr[i], restI) : highway::StoreU(fyNew, tag_double, &fyPtr[i]);
613 remainder ? highway::StoreN(fzNew, tag_double, &fzPtr[i], restI) : highway::StoreU(fzNew, tag_double, &fzPtr[i]);
614 }
615 }
616
617 inline void computeGlobals(const VectorDouble &virialSumX, const VectorDouble &virialSumY,
618 const VectorDouble &virialSumZ, const VectorDouble &uPotSum) {
619 const int threadnum = autopas::autopas_get_thread_num();
620
621 _aosThreadData[threadnum].virialSum[0] += highway::ReduceSum(tag_double, virialSumX);
622 _aosThreadData[threadnum].virialSum[1] += highway::ReduceSum(tag_double, virialSumY);
623 _aosThreadData[threadnum].virialSum[2] += highway::ReduceSum(tag_double, virialSumZ);
624 _aosThreadData[threadnum].potentialEnergySum += highway::ReduceSum(tag_double, uPotSum);
625 }
626
661 template <bool reversed, bool newton3, bool remainderI, VectorizationPattern vecPattern>
662 inline void handleILoopBody(const size_t i, const double *const __restrict xPtr1,
663 const double *const __restrict yPtr1, const double *const __restrict zPtr1,
664 const autopas::OwnershipState *const __restrict ownedStatePtr1,
665 const double *const __restrict xPtr2, const double *const __restrict yPtr2,
666 const double *const __restrict zPtr2,
667 const autopas::OwnershipState *const __restrict ownedStatePtr2,
668 double *const __restrict fxPtr1, double *const __restrict fyPtr1,
669 double *const __restrict fzPtr1, double *const __restrict fxPtr2,
670 double *const __restrict fyPtr2, double *const __restrict fzPtr2,
671 const size_t *const __restrict typeIDptr1, const size_t *const __restrict typeIDptr2,
672 VectorDouble &virialSumX, VectorDouble &virialSumY, VectorDouble &virialSumZ,
673 VectorDouble &uPotSum, const size_t restI, const size_t jVecStart, const size_t jVecEnd) {
674 VectorDouble fxAcc = highway::Zero(tag_double);
675 VectorDouble fyAcc = highway::Zero(tag_double);
676 VectorDouble fzAcc = highway::Zero(tag_double);
677
678 MaskDouble ownedMaskI;
679
680 VectorDouble x1 = highway::Zero(tag_double);
681 VectorDouble y1 = highway::Zero(tag_double);
682 VectorDouble z1 = highway::Zero(tag_double);
683
684 fillIRegisters<remainderI, reversed, vecPattern>(i, xPtr1, yPtr1, zPtr1, ownedStatePtr1, x1, y1, z1, ownedMaskI,
685 restI);
686 auto j = static_cast<std::ptrdiff_t>(jVecStart);
687 for (; checkSecondLoopCondition<vecPattern>(jVecEnd, j);
688 j += static_cast<std::ptrdiff_t>(jStepSize<vecPattern>())) {
689 SoAKernel<newton3, remainderI, false, reversed, vecPattern>(
690 i, j, ownedMaskI, reinterpret_cast<const int64_t *>(ownedStatePtr2), x1, y1, z1, xPtr2, yPtr2, zPtr2, fxPtr2,
691 fyPtr2, fzPtr2, &typeIDptr1[i], &typeIDptr2[j], fxAcc, fyAcc, fzAcc, virialSumX, virialSumY, virialSumZ,
692 uPotSum, restI, 0);
693 }
694
695 const size_t restJ = jVecEnd & (jStepSize<vecPattern>() - 1);
696 if (restJ > 0) {
697 SoAKernel<newton3, remainderI, true, reversed, vecPattern>(
698 i, j, ownedMaskI, reinterpret_cast<const int64_t *>(ownedStatePtr2), x1, y1, z1, xPtr2, yPtr2, zPtr2, fxPtr2,
699 fyPtr2, fzPtr2, &typeIDptr1[i], &typeIDptr2[j], fxAcc, fyAcc, fzAcc, virialSumX, virialSumY, virialSumZ,
700 uPotSum, restI, restJ);
701 }
702
703 reduceAccumulatedForce<reversed, remainderI, vecPattern>(i, fxPtr1, fyPtr1, fzPtr1, fxAcc, fyAcc, fzAcc, restI);
704 }
705
719 template <bool newton3, bool sorted, VectorizationPattern vecPattern>
720 inline void SoAFunctorPairImpl(autopas::SoAView<SoAArraysType> soa1, autopas::SoAView<SoAArraysType> soa2,
722 if (soa1.size() == 0 || soa2.size() == 0) {
723 return;
724 }
725
726 const size_t n1 = soa1.size();
727 const size_t n2 = soa2.size();
728
729 const auto *const __restrict x1Ptr = soa1.template begin<Particle_T::AttributeNames::posX>();
730 const auto *const __restrict y1Ptr = soa1.template begin<Particle_T::AttributeNames::posY>();
731 const auto *const __restrict z1Ptr = soa1.template begin<Particle_T::AttributeNames::posZ>();
732 const auto *const __restrict x2Ptr = soa2.template begin<Particle_T::AttributeNames::posX>();
733 const auto *const __restrict y2Ptr = soa2.template begin<Particle_T::AttributeNames::posY>();
734 const auto *const __restrict z2Ptr = soa2.template begin<Particle_T::AttributeNames::posZ>();
735 const auto *const __restrict ownedStatePtr1 = soa1.template begin<Particle_T::AttributeNames::ownershipState>();
736 const auto *const __restrict ownedStatePtr2 = soa2.template begin<Particle_T::AttributeNames::ownershipState>();
737 auto *const __restrict fx1Ptr = soa1.template begin<Particle_T::AttributeNames::forceX>();
738 auto *const __restrict fy1Ptr = soa1.template begin<Particle_T::AttributeNames::forceY>();
739 auto *const __restrict fz1Ptr = soa1.template begin<Particle_T::AttributeNames::forceZ>();
740 auto *const __restrict fx2Ptr = soa2.template begin<Particle_T::AttributeNames::forceX>();
741 auto *const __restrict fy2Ptr = soa2.template begin<Particle_T::AttributeNames::forceY>();
742 auto *const __restrict fz2Ptr = soa2.template begin<Particle_T::AttributeNames::forceZ>();
743 const auto *const __restrict typeID1Ptr = soa1.template begin<Particle_T::AttributeNames::typeId>();
744 const auto *const __restrict typeID2Ptr = soa2.template begin<Particle_T::AttributeNames::typeId>();
745
746 const std::ptrdiff_t startI =
747 sorted && sortingData.has_value() ? static_cast<std::ptrdiff_t>(sortingData->get().startI) : 0;
748 // endI bounds the outer loop from above, mirroring startI: i-particles from endI onwards cannot interact
749 // with any j-particle, so the loop stops there instead of running to n1 and relying on the per-block
750 // jVecStart >= jVecEnd skip below.
751 const std::ptrdiff_t endI = sorted && sortingData.has_value() ? static_cast<std::ptrdiff_t>(sortingData->get().endI)
752 : static_cast<std::ptrdiff_t>(n1);
753
754 VectorDouble virialSumX = highway::Zero(tag_double);
755 VectorDouble virialSumY = highway::Zero(tag_double);
756 VectorDouble virialSumZ = highway::Zero(tag_double);
757 VectorDouble uPotSum = highway::Zero(tag_double);
758
759 const size_t iStep = iStepSize<vecPattern>();
760 const size_t jStep = jStepSize<vecPattern>();
761
762 std::ptrdiff_t i = startI;
763 for (; i + static_cast<std::ptrdiff_t>(iStep) <= endI; i += static_cast<std::ptrdiff_t>(iStep)) {
764 size_t jVecEnd{};
765 size_t jVecStart = 0;
766 if constexpr (sorted) {
767 // The get is always safe here since SoAFunctorPairSorted() will never call this with no sortingData.
768 const auto &sd = sortingData->get();
769 // maxIndex is monotonically non-decreasing, so the tightest valid bound for [i, i + iStep - 1] (the i values
770 // handled in one iteration) is maxIndex of the last particle in the block. For p1xVec
771 // (iStep=1) this collapses to maxIndex[i].
772 jVecEnd = sd.maxIndex[i + iStep - 1];
773 // minIndex is monotonically non-decreasing, so the tightest valid lower bound [i, i + iStep - 1] (the i values
774 // handled in one iteration) is always minIndex[i], the minimum across the block.
775 jVecStart = sd.minIndex[i];
776 // If this check is true it means there are no particles in soa2 that can interact with particles in soa1
777 // I.e. the hitrate in this case is 0%.
778 if (jVecStart >= jVecEnd) {
779 continue;
780 }
781 // Round down to the nearest full SIMD lane boundary so the j-loop starts aligned.
782 jVecStart = jVecStart - (jVecStart % jStep);
783 if constexpr (vecPattern == VectorizationPattern::p1xVec) {
784 if (ownedStatePtr1[i] == autopas::OwnershipState::dummy) {
785 continue;
786 }
787 }
788 } else {
789 jVecEnd = n2;
790 }
791 handleILoopBody<false, newton3, false, vecPattern>(
792 i, x1Ptr, y1Ptr, z1Ptr, ownedStatePtr1, x2Ptr, y2Ptr, z2Ptr, ownedStatePtr2, fx1Ptr, fy1Ptr, fz1Ptr, fx2Ptr,
793 fy2Ptr, fz2Ptr, typeID1Ptr, typeID2Ptr, virialSumX, virialSumY, virialSumZ, uPotSum, 0, jVecStart, jVecEnd);
794 }
795 if constexpr (vecPattern != VectorizationPattern::p1xVec) {
796 // Rest I can't occur in 1xVec case. Bounded by endI, not n1: i-particles from endI onwards cannot
797 // interact with any j-particle and are skipped entirely rather than processed as a no-op remainder.
798 const std::ptrdiff_t restI = endI - i;
799 if (restI > 0) {
800 // Remainder block covers [i, i + restI - 1]. Same monotonicity argument as above.
801 size_t jVecEnd = n2;
802 size_t jVecStart = 0;
803 if constexpr (sorted) {
804 // The get is always safe here since SoAFunctorPairSorted() will never call this with no sortingData.
805 const auto &sd = sortingData->get();
806 jVecEnd = sd.maxIndex[i + restI - 1];
807 jVecStart = sd.minIndex[i];
808 if (jVecStart < jVecEnd) {
809 // Round down to nearest full SIMD lane boundary.
810 jVecStart = jVecStart - (jVecStart % jStep);
811 }
812 }
813 // If this check is false it means there are no particles in soa2 that can interact with particles in soa1
814 // I.e. the hitrate in this case is 0%.
815 if (jVecStart < jVecEnd) {
816 handleILoopBody<false, newton3, true, vecPattern>(
817 i, x1Ptr, y1Ptr, z1Ptr, ownedStatePtr1, x2Ptr, y2Ptr, z2Ptr, ownedStatePtr2, fx1Ptr, fy1Ptr, fz1Ptr,
818 fx2Ptr, fy2Ptr, fz2Ptr, typeID1Ptr, typeID2Ptr, virialSumX, virialSumY, virialSumZ, uPotSum,
819 static_cast<size_t>(restI), jVecStart, jVecEnd);
820 }
821 }
822 }
823
824 if constexpr (calculateGlobals) {
825 computeGlobals(virialSumX, virialSumY, virialSumZ, uPotSum);
826 }
827 }
828
846 template <bool remainder, VectorizationPattern vecPattern>
847 static void fillJRegisters(const size_t j, const double *const __restrict x2Ptr, const double *const __restrict y2Ptr,
848 const double *const __restrict z2Ptr, const int64_t *const __restrict ownedStatePtr2,
849 VectorDouble &x2, VectorDouble &y2, VectorDouble &z2, MaskDouble &ownedMaskJ,
850 const unsigned int rest) {
851 VectorLong ownedStateJLong = highway::Zero(tag_long);
852
853 if constexpr (vecPattern == VectorizationPattern::p1xVec) {
854 if constexpr (remainder) {
855 x2 = highway::LoadN(tag_double, &x2Ptr[j], rest);
856 y2 = highway::LoadN(tag_double, &y2Ptr[j], rest);
857 z2 = highway::LoadN(tag_double, &z2Ptr[j], rest);
858
859 ownedStateJLong = highway::LoadN(tag_long, &ownedStatePtr2[j], rest);
860 } else {
861 x2 = highway::LoadU(tag_double, &x2Ptr[j]);
862 y2 = highway::LoadU(tag_double, &y2Ptr[j]);
863 z2 = highway::LoadU(tag_double, &z2Ptr[j]);
864
865 ownedStateJLong = highway::LoadU(tag_long, &ownedStatePtr2[j]);
866 }
867 } else if constexpr (vecPattern == VectorizationPattern::p2xVecDiv2) {
868 const int lanes = remainder ? rest : _vecLengthDouble / 2;
869
870 VectorLong ownedStateJ = highway::LoadN(tag_long, &ownedStatePtr2[j], lanes);
871 x2 = highway::LoadN(tag_double, &x2Ptr[j], lanes);
872 y2 = highway::LoadN(tag_double, &y2Ptr[j], lanes);
873 z2 = highway::LoadN(tag_double, &z2Ptr[j], lanes);
874
875 // "broadcast" lower half to upper half
876 ownedStateJLong = highway::ConcatLowerLower(tag_long, ownedStateJ, ownedStateJ);
877 x2 = highway::ConcatLowerLower(tag_double, x2, x2);
878 y2 = highway::ConcatLowerLower(tag_double, y2, y2);
879 z2 = highway::ConcatLowerLower(tag_double, z2, z2);
880 } else if constexpr (vecPattern == VectorizationPattern::pVecDiv2x2) {
881 VectorLong ownedStateJ = highway::Set(tag_long, ownedStatePtr2[j]);
882 x2 = highway::Set(tag_double, x2Ptr[j]);
883 y2 = highway::Set(tag_double, y2Ptr[j]);
884 z2 = highway::Set(tag_double, z2Ptr[j]);
885
886 if constexpr (remainder) {
887 ownedStateJLong = highway::ConcatLowerLower(tag_long, highway::Zero(tag_long), ownedStateJ);
888 x2 = highway::ConcatLowerLower(tag_double, highway::Zero(tag_double), x2);
889 y2 = highway::ConcatLowerLower(tag_double, highway::Zero(tag_double), y2);
890 z2 = highway::ConcatLowerLower(tag_double, highway::Zero(tag_double), z2);
891 } else {
892 const auto tmpOwnedJ = highway::Set(tag_long, ownedStatePtr2[j + 1]);
893 const auto tmpX2 = highway::Set(tag_double, x2Ptr[j + 1]);
894 const auto tmpY2 = highway::Set(tag_double, y2Ptr[j + 1]);
895 const auto tmpZ2 = highway::Set(tag_double, z2Ptr[j + 1]);
896
897 ownedStateJLong = highway::ConcatLowerLower(tag_long, tmpOwnedJ, ownedStateJ);
898 x2 = highway::ConcatLowerLower(tag_double, tmpX2, x2);
899 y2 = highway::ConcatLowerLower(tag_double, tmpY2, y2);
900 z2 = highway::ConcatLowerLower(tag_double, tmpZ2, z2);
901 }
902 } else if constexpr (vecPattern == VectorizationPattern::pVecx1) {
903 ownedStateJLong = highway::Set(tag_long, ownedStatePtr2[j]);
904 x2 = highway::Set(tag_double, x2Ptr[j]);
905 y2 = highway::Set(tag_double, y2Ptr[j]);
906 z2 = highway::Set(tag_double, z2Ptr[j]);
907 }
908
909 MaskLong ownedMaskJLong = highway::Ne(ownedStateJLong, highway::Zero(tag_long));
910
911 // convert to a double mask since we perform logical operations with other double masks in the kernel.
912 ownedMaskJ = highway::RebindMask(tag_double, ownedMaskJLong);
913 }
914
915 template <bool remainderI, bool remainderJ, bool reversed, VectorizationPattern vecPattern>
916 inline void fillPhysicsRegisters(const size_t *const typeID1Ptr, const size_t *const typeID2Ptr,
917 VectorDouble &epsilon24s, VectorDouble &sigmaSquareds, VectorDouble &shift6s,
918 const unsigned int restI, const unsigned int restJ) const {
919 // We overestimate the array size. This should be a tight/perfect upper bound on x86, and should never be large
920 // enough on e.g. ARM/RISC-V to cause issues.
921 HWY_ALIGN std::array<double, _maxVecLengthDouble> epsilons{};
922 HWY_ALIGN std::array<double, _maxVecLengthDouble> sigmas{};
923 HWY_ALIGN std::array<double, _maxVecLengthDouble> shifts{};
924
925 if constexpr (vecPattern == VectorizationPattern::p1xVec) {
926 for (int j = 0; j < (remainderJ ? restJ : _vecLengthDouble); ++j) {
927 epsilons[j] = _PPLibrary->get().getMixing24Epsilon(*typeID1Ptr, *(typeID2Ptr + j));
928 sigmas[j] = _PPLibrary->get().getMixingSigmaSquared(*typeID1Ptr, *(typeID2Ptr + j));
929 if constexpr (applyShift) {
930 shifts[j] = _PPLibrary->get().getMixingShift6(*typeID1Ptr, *(typeID2Ptr + j));
931 }
932 }
933 } else if constexpr (vecPattern == VectorizationPattern::p2xVecDiv2) {
934 for (int i = 0; i < (remainderI ? 1 : 2); ++i) {
935 for (int j = 0; j < (remainderJ ? restJ : _vecLengthDouble / 2); ++j) {
936 const auto index = i * (_vecLengthDouble / 2) + j;
937 const auto typeID1 = reversed ? typeID1Ptr - i : typeID1Ptr + i;
938 epsilons[index] = _PPLibrary->get().getMixing24Epsilon(*typeID1, *(typeID2Ptr + j));
939 sigmas[index] = _PPLibrary->get().getMixingSigmaSquared(*typeID1, *(typeID2Ptr + j));
940
941 if constexpr (applyShift) {
942 shifts[index] = _PPLibrary->get().getMixingShift6(*typeID1, *(typeID2Ptr + j));
943 }
944 }
945 }
946 } else if constexpr (vecPattern == VectorizationPattern::pVecDiv2x2) {
947 for (int i = 0; i < (remainderI ? restI : _vecLengthDouble / 2); ++i) {
948 for (int j = 0; j < (remainderJ ? 1 : 2); ++j) {
949 const auto index = i + _vecLengthDouble / 2 * j;
950 const auto typeID1 = reversed ? typeID1Ptr - i : typeID1Ptr + i;
951
952 epsilons[index] = _PPLibrary->get().getMixing24Epsilon(*typeID1, *(typeID2Ptr + j));
953 sigmas[index] = _PPLibrary->get().getMixingSigmaSquared(*typeID1, *(typeID2Ptr + j));
954
955 if constexpr (applyShift) {
956 shifts[index] = _PPLibrary->get().getMixingShift6(*typeID1, *(typeID2Ptr + j));
957 }
958 }
959 }
960 } else if constexpr (vecPattern == VectorizationPattern::pVecx1) {
961 for (int i = 0; i < (remainderI ? restI : _vecLengthDouble); ++i) {
962 auto typeID1 = reversed ? typeID1Ptr - i : typeID1Ptr + i;
963 epsilons[i] = _PPLibrary->get().getMixing24Epsilon(*typeID1, *typeID2Ptr);
964 sigmas[i] = _PPLibrary->get().getMixingSigmaSquared(*typeID1, *typeID2Ptr);
965
966 if constexpr (applyShift) {
967 shifts[i] = _PPLibrary->get().getMixingShift6(*typeID1, *typeID2Ptr);
968 }
969 }
970 }
971
972 epsilon24s = highway::Load(tag_double, epsilons.data());
973 sigmaSquareds = highway::Load(tag_double, sigmas.data());
974 if constexpr (applyShift) {
975 shift6s = highway::Load(tag_double, shifts.data());
976 }
977 }
978
1012 template <bool newton3, bool remainderI, bool remainderJ, bool reversed, VectorizationPattern vecPattern>
1013 inline void SoAKernel(const size_t i, const size_t j, const MaskDouble &ownedMaskI,
1014 const int64_t *const __restrict ownedStatePtr2, const VectorDouble &x1, const VectorDouble &y1,
1015 const VectorDouble &z1, const double *const __restrict x2Ptr,
1016 const double *const __restrict y2Ptr, const double *const __restrict z2Ptr,
1017 double *const __restrict fx2Ptr, double *const __restrict fy2Ptr,
1018 double *const __restrict fz2Ptr, const size_t *const typeID1Ptr, const size_t *const typeID2Ptr,
1019 VectorDouble &fxAcc, VectorDouble &fyAcc, VectorDouble &fzAcc, VectorDouble &virialSumX,
1020 VectorDouble &virialSumY, VectorDouble &virialSumZ, VectorDouble &uPotSum,
1021 const unsigned int restI, const unsigned int restJ) {
1022 VectorDouble epsilon24s = highway::Undefined(tag_double);
1023 VectorDouble sigmaSquareds = highway::Undefined(tag_double);
1024 VectorDouble shift6s = highway::Undefined(tag_double);
1025
1026 if constexpr (useMixing) {
1027 fillPhysicsRegisters<remainderI, remainderJ, reversed, vecPattern>(typeID1Ptr, typeID2Ptr, epsilon24s,
1028 sigmaSquareds, shift6s, restI, restJ);
1029 } else {
1030 epsilon24s = highway::Set(tag_double, _epsilon24AoS);
1031 sigmaSquareds = highway::Set(tag_double, _sigmaSquareAoS);
1032 if constexpr (applyShift) {
1033 shift6s = highway::Set(tag_double, _shift6AoS);
1034 } else {
1035 shift6s = highway::Zero(tag_double);
1036 }
1037 }
1038
1039 VectorDouble x2;
1040 VectorDouble y2;
1041 VectorDouble z2;
1042 MaskDouble ownedMaskJ;
1043
1044 fillJRegisters<remainderJ, vecPattern>(j, x2Ptr, y2Ptr, z2Ptr, ownedStatePtr2, x2, y2, z2, ownedMaskJ, restJ);
1045
1046 // distance calculations
1047 const auto drX = highway::Sub(x1, x2);
1048 const auto drY = highway::Sub(y1, y2);
1049 const auto drZ = highway::Sub(z1, z2);
1050
1051 const auto drX2 = highway::Mul(drX, drX);
1052 const auto drY2 = highway::Mul(drY, drY);
1053 const auto drZ2 = highway::Mul(drZ, drZ);
1054
1055 const auto dr2 = highway::Add(highway::Add(drX2, drY2), drZ2);
1056
1057 VectorDouble cutoffSquared = highway::Set(tag_double, _cutoffSquareAoS);
1058
1059 const auto dummyMask = highway::And(ownedMaskI, ownedMaskJ);
1060 const auto cutoffDummyMask = highway::MaskedLe(dummyMask, dr2, cutoffSquared);
1061
1062 if (highway::AllFalse(tag_double, cutoffDummyMask)) {
1063 return;
1064 }
1065
1066 // compute LJ Potential
1067 const auto invDr2 = highway::Div(highway::Set(tag_double, 1.0), dr2);
1068 const auto lj2 = highway::Mul(sigmaSquareds, invDr2);
1069 const auto lj4 = highway::Mul(lj2, lj2);
1070 const auto lj6 = highway::Mul(lj2, lj4);
1071 const auto lj12 = highway::Mul(lj6, lj6);
1072 const auto lj12m6 = highway::Sub(lj12, lj6);
1073 const auto lj12m6alj12 = highway::Add(lj12m6, lj12);
1074 const auto lj12m6alj12e = highway::Mul(lj12m6alj12, epsilon24s);
1075 const auto fac = highway::Mul(lj12m6alj12e, invDr2);
1076
1077 const auto facMasked = highway::IfThenElseZero(cutoffDummyMask, fac);
1078
1079 const VectorDouble fx = highway::Mul(drX, facMasked);
1080 const VectorDouble fy = highway::Mul(drY, facMasked);
1081 const VectorDouble fz = highway::Mul(drZ, facMasked);
1082
1083 fxAcc = highway::Add(fxAcc, fx);
1084 fyAcc = highway::Add(fyAcc, fy);
1085 fzAcc = highway::Add(fzAcc, fz);
1086
1087 if constexpr (newton3) {
1088 handleNewton3Reduction<remainderJ, vecPattern>(fx, fy, fz, fx2Ptr, fy2Ptr, fz2Ptr, j, restJ);
1089 }
1090
1091 if constexpr (calculateGlobals) {
1092 auto virialX = highway::Mul(fx, drX);
1093 auto virialY = highway::Mul(fy, drY);
1094 auto virialZ = highway::Mul(fz, drZ);
1095
1096 auto uPot = highway::MulAdd(epsilon24s, lj12m6, shift6s);
1097 auto uPotMasked = highway::IfThenElseZero(cutoffDummyMask, uPot);
1098
1099 auto energyFactor = highway::MaskedSet(tag_double, dummyMask, 1.0);
1100
1101 if constexpr (newton3) {
1102 energyFactor = highway::Add(energyFactor, highway::MaskedSet(tag_double, dummyMask, 1.0));
1103 }
1104
1105 uPotSum = highway::MulAdd(energyFactor, uPotMasked, uPotSum);
1106 virialSumX = highway::MulAdd(energyFactor, virialX, virialSumX);
1107 virialSumY = highway::MulAdd(energyFactor, virialY, virialSumY);
1108 virialSumZ = highway::MulAdd(energyFactor, virialZ, virialSumZ);
1109 }
1110 }
1111
1112 template <bool newton3, bool remainder = false>
1113 inline void SoAKernelVerlet(const size_t i, const size_t j, const MaskDouble &ownedMaskI, const VectorDouble &x1,
1114 const VectorDouble &y1, const VectorDouble &z1, const double *const __restrict xPtr,
1115 const double *const __restrict yPtr, const double *const __restrict zPtr,
1116 const int64_t *const __restrict ownedStatePtr, double *const __restrict fxPtr,
1117 double *const __restrict fyPtr, double *const __restrict fzPtr,
1118 const size_t *const typeID1Ptr, const size_t *const typeIDPtr,
1119 const size_t *const __restrict neighborList, VectorDouble &fxAcc, VectorDouble &fyAcc,
1120 VectorDouble &fzAcc, VectorDouble &virialSumX, VectorDouble &virialSumY,
1121 VectorDouble &virialSumZ, VectorDouble &uPotSum,
1122 [[maybe_unused]] const size_t rest = 0) const {
1123 VectorDouble epsilon24s = highway::Undefined(tag_double);
1124 VectorDouble sigmaSquareds = highway::Undefined(tag_double);
1125 VectorDouble shift6s = highway::Undefined(tag_double);
1126
1127 [[maybe_unused]] MaskDouble restMaskDouble;
1128 [[maybe_unused]] MaskLong restMaskLong;
1129 VectorLong indices;
1130
1131 if constexpr (remainder) {
1132 restMaskDouble = highway::FirstN(tag_double, rest);
1133 restMaskLong = highway::FirstN(tag_long, rest);
1134 indices = highway::LoadN(tag_long, reinterpret_cast<const int64_t *>(neighborList + j), rest);
1135 } else {
1136 indices = highway::LoadU(tag_long, reinterpret_cast<const int64_t *>(neighborList + j));
1137 }
1138
1139 if constexpr (useMixing) {
1140 HWY_ALIGN std::array<double, _maxVecLengthDouble> epsilons{};
1141 HWY_ALIGN std::array<double, _maxVecLengthDouble> sigmas{};
1142 HWY_ALIGN std::array<double, _maxVecLengthDouble> shifts{};
1143 const size_t kMax = remainder ? rest : _vecLengthDouble;
1144 for (size_t k = 0; k < kMax; ++k) {
1145 epsilons[k] = _PPLibrary->get().getMixing24Epsilon(*typeID1Ptr, typeIDPtr[neighborList[j + k]]);
1146 sigmas[k] = _PPLibrary->get().getMixingSigmaSquared(*typeID1Ptr, typeIDPtr[neighborList[j + k]]);
1147 if constexpr (applyShift) {
1148 shifts[k] = _PPLibrary->get().getMixingShift6(*typeID1Ptr, typeIDPtr[neighborList[j + k]]);
1149 }
1150 }
1151 epsilon24s = highway::Load(tag_double, epsilons.data());
1152 sigmaSquareds = highway::Load(tag_double, sigmas.data());
1153 if constexpr (applyShift) {
1154 shift6s = highway::Load(tag_double, shifts.data());
1155 } else {
1156 shift6s = highway::Zero(tag_double);
1157 }
1158 } else {
1159 epsilon24s = highway::Set(tag_double, _epsilon24AoS);
1160 sigmaSquareds = highway::Set(tag_double, _sigmaSquareAoS);
1161 if constexpr (applyShift) {
1162 shift6s = highway::Set(tag_double, _shift6AoS);
1163 } else {
1164 shift6s = highway::Zero(tag_double);
1165 }
1166 }
1167
1168 VectorDouble x2;
1169 VectorDouble y2;
1170 VectorDouble z2;
1171 VectorLong ownedState2;
1172
1173 if constexpr (remainder) {
1174 x2 = highway::MaskedGatherIndex(restMaskDouble, tag_double, xPtr, indices);
1175 y2 = highway::MaskedGatherIndex(restMaskDouble, tag_double, yPtr, indices);
1176 z2 = highway::MaskedGatherIndex(restMaskDouble, tag_double, zPtr, indices);
1177 ownedState2 = highway::MaskedGatherIndex(restMaskLong, tag_long, ownedStatePtr, indices);
1178 } else {
1179 x2 = highway::GatherIndex(tag_double, xPtr, indices);
1180 y2 = highway::GatherIndex(tag_double, yPtr, indices);
1181 z2 = highway::GatherIndex(tag_double, zPtr, indices);
1182 ownedState2 = highway::GatherIndex(tag_long, ownedStatePtr, indices);
1183 }
1184
1185 const MaskLong ownedMaskJLong = highway::Ne(ownedState2, highway::Zero(tag_long));
1186 const MaskDouble ownedMaskJ = highway::RebindMask(tag_double, ownedMaskJLong);
1187
1188 const auto drX = highway::Sub(x1, x2);
1189 const auto drY = highway::Sub(y1, y2);
1190 const auto drZ = highway::Sub(z1, z2);
1191
1192 const auto drX2 = highway::Mul(drX, drX);
1193 const auto drY2 = highway::Mul(drY, drY);
1194 const auto drZ2 = highway::Mul(drZ, drZ);
1195
1196 const auto dr2 = highway::Add(highway::Add(drX2, drY2), drZ2);
1197
1198 VectorDouble cutoffSquared = highway::Set(tag_double, _cutoffSquareAoS);
1199
1200 const auto dummyMask = highway::And(ownedMaskI, ownedMaskJ);
1201 const auto cutoffDummyMask = highway::MaskedLe(dummyMask, dr2, cutoffSquared);
1202
1203 if (highway::AllFalse(tag_double, cutoffDummyMask)) {
1204 return;
1205 }
1206
1207 const auto invDr2 = highway::Div(highway::Set(tag_double, 1.0), dr2);
1208 const auto lj2 = highway::Mul(sigmaSquareds, invDr2);
1209 const auto lj4 = highway::Mul(lj2, lj2);
1210 const auto lj6 = highway::Mul(lj2, lj4);
1211 const auto lj12 = highway::Mul(lj6, lj6);
1212 const auto lj12m6 = highway::Sub(lj12, lj6);
1213 const auto lj12m6alj12 = highway::Add(lj12m6, lj12);
1214 const auto lj12m6alj12e = highway::Mul(lj12m6alj12, epsilon24s);
1215 const auto fac = highway::Mul(lj12m6alj12e, invDr2);
1216
1217 const auto facMasked = highway::IfThenElseZero(cutoffDummyMask, fac);
1218
1219 const VectorDouble fx = highway::Mul(drX, facMasked);
1220 const VectorDouble fy = highway::Mul(drY, facMasked);
1221 const VectorDouble fz = highway::Mul(drZ, facMasked);
1222
1223 fxAcc = highway::Add(fxAcc, fx);
1224 fyAcc = highway::Add(fyAcc, fy);
1225 fzAcc = highway::Add(fzAcc, fz);
1226
1227 if constexpr (newton3) {
1228 if constexpr (remainder) {
1229 const auto fx2Old = highway::MaskedGatherIndex(restMaskDouble, tag_double, fxPtr, indices);
1230 const auto fy2Old = highway::MaskedGatherIndex(restMaskDouble, tag_double, fyPtr, indices);
1231 const auto fz2Old = highway::MaskedGatherIndex(restMaskDouble, tag_double, fzPtr, indices);
1232
1233 const auto fx2New = highway::Sub(fx2Old, fx);
1234 const auto fy2New = highway::Sub(fy2Old, fy);
1235 const auto fz2New = highway::Sub(fz2Old, fz);
1236
1237 highway::MaskedScatterIndex(fx2New, restMaskDouble, tag_double, fxPtr, indices);
1238 highway::MaskedScatterIndex(fy2New, restMaskDouble, tag_double, fyPtr, indices);
1239 highway::MaskedScatterIndex(fz2New, restMaskDouble, tag_double, fzPtr, indices);
1240 } else {
1241 const auto fx2Old = highway::GatherIndex(tag_double, fxPtr, indices);
1242 const auto fy2Old = highway::GatherIndex(tag_double, fyPtr, indices);
1243 const auto fz2Old = highway::GatherIndex(tag_double, fzPtr, indices);
1244
1245 const auto fx2New = highway::Sub(fx2Old, fx);
1246 const auto fy2New = highway::Sub(fy2Old, fy);
1247 const auto fz2New = highway::Sub(fz2Old, fz);
1248
1249 highway::ScatterIndex(fx2New, tag_double, fxPtr, indices);
1250 highway::ScatterIndex(fy2New, tag_double, fyPtr, indices);
1251 highway::ScatterIndex(fz2New, tag_double, fzPtr, indices);
1252 }
1253 }
1254
1255 if constexpr (calculateGlobals) {
1256 auto virialX = highway::Mul(fx, drX);
1257 auto virialY = highway::Mul(fy, drY);
1258 auto virialZ = highway::Mul(fz, drZ);
1259
1260 auto uPot = highway::MulAdd(epsilon24s, lj12m6, shift6s);
1261 auto uPotMasked = highway::IfThenElseZero(cutoffDummyMask, uPot);
1262
1263 auto energyFactor = highway::MaskedSet(tag_double, dummyMask, 1.0);
1264
1265 if constexpr (newton3) {
1266 energyFactor = highway::Add(energyFactor, highway::MaskedSet(tag_double, dummyMask, 1.0));
1267 }
1268
1269 uPotSum = highway::MulAdd(energyFactor, uPotMasked, uPotSum);
1270 virialSumX = highway::MulAdd(energyFactor, virialX, virialSumX);
1271 virialSumY = highway::MulAdd(energyFactor, virialY, virialSumY);
1272 virialSumZ = highway::MulAdd(energyFactor, virialZ, virialSumZ);
1273 }
1274 }
1275
1276 public:
1280 inline void SoAFunctorVerlet(autopas::SoAView<SoAArraysType> soa, const size_t indexFirst,
1281 const std::span<const size_t> neighborList, const bool newton3) final {
1282 if (soa.size() == 0 or neighborList.empty()) return;
1283 if (newton3) {
1284 SoAFunctorVerletImpl<true>(soa, indexFirst, neighborList);
1285 } else {
1286 SoAFunctorVerletImpl<false>(soa, indexFirst, neighborList);
1287 }
1288 }
1289
1290 private:
1291 template <bool newton3>
1292 inline void SoAFunctorVerletImpl(autopas::SoAView<SoAArraysType> soa, const size_t indexFirst,
1293 std::span<const size_t> neighborList) {
1294 const auto *const __restrict ownedStatePtr = soa.template begin<Particle_T::AttributeNames::ownershipState>();
1295 if (ownedStatePtr[indexFirst] == autopas::OwnershipState::dummy) {
1296 return;
1297 }
1298
1299 const auto *const __restrict xPtr = soa.template begin<Particle_T::AttributeNames::posX>();
1300 const auto *const __restrict yPtr = soa.template begin<Particle_T::AttributeNames::posY>();
1301 const auto *const __restrict zPtr = soa.template begin<Particle_T::AttributeNames::posZ>();
1302
1303 auto *const __restrict fxPtr = soa.template begin<Particle_T::AttributeNames::forceX>();
1304 auto *const __restrict fyPtr = soa.template begin<Particle_T::AttributeNames::forceY>();
1305 auto *const __restrict fzPtr = soa.template begin<Particle_T::AttributeNames::forceZ>();
1306
1307 const auto *const __restrict typeIDPtr = soa.template begin<Particle_T::AttributeNames::typeId>();
1308
1309 VectorDouble virialSumX = highway::Zero(tag_double);
1310 VectorDouble virialSumY = highway::Zero(tag_double);
1311 VectorDouble virialSumZ = highway::Zero(tag_double);
1312 VectorDouble uPotSum = highway::Zero(tag_double);
1313 VectorDouble fxAcc = highway::Zero(tag_double);
1314 VectorDouble fyAcc = highway::Zero(tag_double);
1315 VectorDouble fzAcc = highway::Zero(tag_double);
1316
1317 const VectorDouble x1 = highway::Set(tag_double, xPtr[indexFirst]);
1318 const VectorDouble y1 = highway::Set(tag_double, yPtr[indexFirst]);
1319 const VectorDouble z1 = highway::Set(tag_double, zPtr[indexFirst]);
1320 const auto ownedI = static_cast<int64_t>(ownedStatePtr[indexFirst]);
1321 const VectorDouble ownedStateI = highway::Set(tag_double, static_cast<double>(ownedI));
1322 const MaskDouble ownedMaskI = highway::Ne(ownedStateI, highway::Zero(tag_double));
1323
1324 size_t j = 0;
1325 const size_t neighborListSize = neighborList.size();
1326 const size_t vecEnd = (neighborListSize / _vecLengthDouble) * _vecLengthDouble;
1327
1328 for (; j < vecEnd; j += _vecLengthDouble) {
1329 SoAKernelVerlet<newton3, false>(indexFirst, j, ownedMaskI, x1, y1, z1, xPtr, yPtr, zPtr,
1330 reinterpret_cast<const int64_t *>(ownedStatePtr), fxPtr, fyPtr, fzPtr,
1331 &typeIDPtr[indexFirst], typeIDPtr, neighborList.data(), fxAcc, fyAcc, fzAcc,
1332 virialSumX, virialSumY, virialSumZ, uPotSum);
1333 }
1334
1335 const size_t rest = neighborListSize & (_vecLengthDouble - 1);
1336
1337 if (rest > 0) {
1338 SoAKernelVerlet<newton3, true>(indexFirst, j, ownedMaskI, x1, y1, z1, xPtr, yPtr, zPtr,
1339 reinterpret_cast<const int64_t *>(ownedStatePtr), fxPtr, fyPtr, fzPtr,
1340 &typeIDPtr[indexFirst], typeIDPtr, neighborList.data(), fxAcc, fyAcc, fzAcc,
1341 virialSumX, virialSumY, virialSumZ, uPotSum, rest);
1342 }
1343
1344 fxPtr[indexFirst] += highway::ReduceSum(tag_double, fxAcc);
1345 fyPtr[indexFirst] += highway::ReduceSum(tag_double, fyAcc);
1346 fzPtr[indexFirst] += highway::ReduceSum(tag_double, fzAcc);
1347
1348 if constexpr (calculateGlobals) {
1349 computeGlobals(virialSumX, virialSumY, virialSumZ, uPotSum);
1350 }
1351 }
1352
1353 public:
1357 constexpr static auto getNeededAttr() {
1358 return std::array<typename Particle_T::AttributeNames, 9>{Particle_T::AttributeNames::id,
1359 Particle_T::AttributeNames::posX,
1360 Particle_T::AttributeNames::posY,
1361 Particle_T::AttributeNames::posZ,
1362 Particle_T::AttributeNames::forceX,
1363 Particle_T::AttributeNames::forceY,
1364 Particle_T::AttributeNames::forceZ,
1365 Particle_T::AttributeNames::typeId,
1366 Particle_T::AttributeNames::ownershipState};
1367 }
1368
1372 constexpr static auto getNeededAttr(std::false_type) {
1373 return std::array<typename Particle_T::AttributeNames, 6>{
1374 Particle_T::AttributeNames::id, Particle_T::AttributeNames::posX,
1375 Particle_T::AttributeNames::posY, Particle_T::AttributeNames::posZ,
1376 Particle_T::AttributeNames::typeId, Particle_T::AttributeNames::ownershipState};
1377 }
1378
1382 constexpr static auto getComputedAttr() {
1383 return std::array<typename Particle_T::AttributeNames, 3>{
1384 Particle_T::AttributeNames::forceX, Particle_T::AttributeNames::forceY, Particle_T::AttributeNames::forceZ};
1385 }
1386
1390 static constexpr bool supportsSoASorting = true;
1391
1396 constexpr static bool getMixing() { return useMixing; }
1397
1402 void initTraversal() final {
1403 _potentialEnergySum = 0.;
1404 _virialSum = {0., 0., 0.};
1405 _postProcessed = false;
1406 for (size_t i = 0; i < _aosThreadData.size(); ++i) {
1407 _aosThreadData[i].setZero();
1408 }
1409 }
1410
1415 void endTraversal(const bool newton3) final {
1416 using namespace autopas::utils::ArrayMath::literals;
1417
1418 if (_postProcessed) {
1420 "Already postprocessed, endTraversal(bool newton3) was called twice without calling initTraversal().");
1421 }
1422
1423 if (calculateGlobals) {
1424 for (size_t i = 0; i < _aosThreadData.size(); ++i) {
1425 _potentialEnergySum += _aosThreadData[i].potentialEnergySum;
1426 _virialSum += _aosThreadData[i].virialSum;
1427 }
1428 // For each interaction, we added the full contribution for both particles. Divide by 2 here, so that each
1429 // contribution is only counted once per pair.
1430 _potentialEnergySum *= 0.5;
1431 _virialSum *= 0.5;
1432
1433 // We have always calculated 6*potentialEnergy, so we divide by 6 here!
1434 _potentialEnergySum /= 6.;
1435 _postProcessed = true;
1436
1437 AutoPasLog(DEBUG, "Final potential energy {}", _potentialEnergySum);
1438 AutoPasLog(DEBUG, "Final virial {}", _virialSum[0] + _virialSum[1] + _virialSum[2]);
1439 }
1440 }
1441
1446 double getPotentialEnergy() const {
1447 if (not calculateGlobals) {
1449 "Trying to get upot even though calculateGlobals is false. If you want this functor to calculate global "
1450 "values, please specify calculateGlobals to be true.");
1451 }
1452 if (not _postProcessed) {
1453 throw autopas::utils::ExceptionHandler::AutoPasException("Cannot get upot, because endTraversal was not called.");
1454 }
1455 return _potentialEnergySum;
1456 }
1457
1462 double getVirial() const {
1463 if (not calculateGlobals) {
1465 "Trying to get virial even though calculateGlobals is false. If you want this functor to calculate global "
1466 "values, please specify calculateGlobals to be true.");
1467 }
1468 if (not _postProcessed) {
1470 "Cannot get virial, because endTraversal was not called.");
1471 }
1472 return _virialSum[0] + _virialSum[1] + _virialSum[2];
1473 }
1474
1483 void setParticleProperties(const double epsilon24, const double sigmaSquare) {
1484 _epsilon24AoS = epsilon24;
1485 _sigmaSquareAoS = sigmaSquare;
1486 if constexpr (applyShift) {
1487 _shift6AoS = ParticlePropertiesLibrary<double, size_t>::calcShift6(epsilon24, sigmaSquare, _cutoffSquareAoS);
1488 } else {
1489 _shift6AoS = 0.;
1490 }
1491 }
1492
1496 void setVecPattern(const VectorizationPattern vecPattern) final { _vecPattern = vecPattern; }
1497
1498 private:
1502 class AoSThreadData {
1503 public:
1504 AoSThreadData() : virialSum{0., 0., 0.}, potentialEnergySum{0.} {}
1505
1506 void setZero() {
1507 virialSum = {0., 0., 0.};
1508 potentialEnergySum = 0.;
1509 }
1510
1511 std::array<double, 3> virialSum{};
1512 double potentialEnergySum{};
1513
1514 private:
1515 double __remainingTo64[(64 - 4 * sizeof(double)) / sizeof(double)];
1516 };
1517 static_assert(sizeof(AoSThreadData) % 64 == 0, "AoSThreadData has wrong size");
1518
1519 // cutoff squared used in the AoS functor.
1520 const double _cutoffSquareAoS{0.};
1521 // epsilon, sigma and shift6 used in the AoS functor.
1522 double _epsilon24AoS{0.}, _sigmaSquareAoS{0.}, _shift6AoS{0.};
1523
1524 // optional to hold a reference to the ParticlePropertiesLibrary. If a ParticlePropertiesLibrary is not used the
1525 // optional is empty.
1526 std::optional<std::reference_wrapper<ParticlePropertiesLibrary<double, size_t>>> _PPLibrary;
1527
1528 // accumulators for the globals (potential energy and virial).
1529 double _potentialEnergySum{0.};
1530 std::array<double, 3> _virialSum{0., 0., 0.};
1531 std::vector<AoSThreadData> _aosThreadData{};
1532
1533 // flag to indicate whether post-processing has been performed.
1534 bool _postProcessed{false};
1535
1536 // The Vectorization Pattern currently used in the SoA functor.
1537 VectorizationPattern _vecPattern{};
1538
1539 // Vectorization Pattern that the functor can handle.
1540 static constexpr std::array<VectorizationPattern, 4> _vecPatternsAllowed = {
1541 VectorizationPattern::p1xVec, VectorizationPattern::p2xVecDiv2, VectorizationPattern::pVecDiv2x2,
1542 VectorizationPattern::pVecx1};
1543};
1544} // namespace mdLib
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:74
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
PairwiseFunctor class.
Definition: PairwiseFunctor.h:66
PairwiseFunctor(double cutoff)
Constructor.
Definition: PairwiseFunctor.h:77
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:1462
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:229
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:1496
void initTraversal() final
Reset the global values.
Definition: LJFunctorHWY.h:1402
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:272
static constexpr auto getNeededAttr()
Get attributes needed for computation.
Definition: LJFunctorHWY.h:1357
static constexpr auto getNeededAttr(std::false_type)
Get attributes needed for computation without N3 optimization.
Definition: LJFunctorHWY.h:1372
static constexpr bool supportsSoASorting
Whether this functor supports the SortedSoAView optimization path (SoAFunctorPairSorted).
Definition: LJFunctorHWY.h:1390
LJFunctorHWY()=delete
Deleted default constructor.
static constexpr bool getMixing()
Definition: LJFunctorHWY.h:1396
std::string getName() final
Returns name of functor.
Definition: LJFunctorHWY.h:108
void SoAFunctorVerlet(autopas::SoAView< SoAArraysType > soa, const size_t indexFirst, const std::span< const size_t > neighborList, const bool newton3) final
PairwiseFunctor for structure of arrays (SoA) for neighbor lists.
Definition: LJFunctorHWY.h:1280
static constexpr auto getComputedAttr()
Get attributes computed by this functor.
Definition: LJFunctorHWY.h:1382
bool allowsNewton3() final
Specifies whether the functor is capable of Newton3-like functors.
Definition: LJFunctorHWY.h:112
double getPotentialEnergy() const
Get the potential Energy.
Definition: LJFunctorHWY.h:1446
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:1483
void endTraversal(const bool newton3) final
Accumulates global values, e.g.
Definition: LJFunctorHWY.h:1415
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:33
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 pair of SoA buffers, soa1 as the outer (i) loop a...
Definition: PairwiseFunctor.h:33