AutoPas  3.0.0
Loading...
Searching...
No Matches
LJMultisiteFunctor.h
Go to the documentation of this file.
1
7#pragma once
8
9#include "MoleculeLJ.h"
10#include "MultisiteMoleculeLJ.h"
17#include "autopas/utils/Math.h"
19#include "autopas/utils/SoA.h"
22#include "autopas/utils/inBox.h"
23
24namespace mdLib {
25
42template <class Particle_T, bool applyShift = false, bool useMixing = false,
43 autopas::FunctorN3Modes useNewton3 = autopas::FunctorN3Modes::Both, bool calculateGlobals = false,
44 bool countFLOPs = false, bool relevantForTuning = true>
46 : public autopas::PairwiseFunctor<Particle_T, LJMultisiteFunctor<Particle_T, applyShift, useMixing, useNewton3,
47 calculateGlobals, relevantForTuning, countFLOPs>> {
51 using SoAArraysType = typename Particle_T::SoAArraysType;
52
56 using SoAFloatPrecision = typename Particle_T::ParticleSoAFloatPrecision;
57
61 const double _cutoffSquared;
62
66 double _epsilon24;
67
71 double _sigmaSquared;
72
76 double _shift6 = 0;
77
81 const std::vector<std::array<double, 3>> _sitePositionsLJ{};
82
87
91 double _potentialEnergySum;
92
96 std::array<double, 3> _virialSum;
97
101 bool _postProcessed;
102
103 public:
108
109 private:
115 explicit LJMultisiteFunctor(SoAFloatPrecision cutoff, void * /*dummy*/)
116 : autopas::PairwiseFunctor<Particle_T, LJMultisiteFunctor<Particle_T, applyShift, useMixing, useNewton3,
117 calculateGlobals, relevantForTuning, countFLOPs>>(
118 cutoff),
119 _cutoffSquared{cutoff * cutoff},
120 _potentialEnergySum{0.},
121 _virialSum{0., 0., 0.},
122 _aosThreadData(),
123 _postProcessed{false} {
124 if constexpr (calculateGlobals) {
125 _aosThreadData.resize(autopas::autopas_get_max_threads());
126 }
127 if constexpr (countFLOPs) {
128 AutoPasLog(DEBUG, "FLOP counting is enabled but is not supported for multi-site functors yet!");
129 }
130 }
131
132 public:
138 explicit LJMultisiteFunctor(double cutoff) : LJMultisiteFunctor(cutoff, nullptr) {
139 static_assert(not useMixing,
140 "Mixing without a ParticlePropertiesLibrary is not possible! Use a different constructor or set "
141 "mixing to false.");
142 AutoPasLog(WARN, "Using LJMultisiteFunctor with mixing disabled is untested!");
143 }
144
152 explicit LJMultisiteFunctor(double cutoff, ParticlePropertiesLibrary<double, size_t> &particlePropertiesLibrary)
153 : LJMultisiteFunctor(cutoff, nullptr) {
154 static_assert(useMixing,
155 "Not using Mixing but using a ParticlePropertiesLibrary is not allowed! Use a different constructor "
156 "or set mixing to true.");
157 _PPLibrary = &particlePropertiesLibrary;
158 }
159
160 std::string getName() final { return "LJMultisiteFunctor"; }
161
162 bool isRelevantForTuning() final { return relevantForTuning; }
163
164 bool allowsNewton3() final {
165 return useNewton3 == autopas::FunctorN3Modes::Newton3Only or useNewton3 == autopas::FunctorN3Modes::Both;
166 }
167
168 bool allowsNonNewton3() final {
169 return useNewton3 == autopas::FunctorN3Modes::Newton3Off or useNewton3 == autopas::FunctorN3Modes::Both;
170 }
171
179 void AoSFunctor(Particle_T &particleA, Particle_T &particleB, bool newton3) final {
180 using namespace autopas::utils::ArrayMath::literals;
181 if (particleA.isDummy() or particleB.isDummy()) {
182 return;
183 }
184
185 // Don't calculate force if particleB outside cutoff of particleA
186 const auto displacementCoM = autopas::utils::ArrayMath::sub(particleA.getR(), particleB.getR());
187 const auto distanceSquaredCoM = autopas::utils::ArrayMath::dot(displacementCoM, displacementCoM);
188
189 if (distanceSquaredCoM > _cutoffSquared) {
190 return;
191 }
192
193 // get number of sites
194 const size_t numSitesA = useMixing ? _PPLibrary->getNumSites(particleA.getTypeId()) : _sitePositionsLJ.size();
195 const size_t numSitesB = useMixing ? _PPLibrary->getNumSites(particleB.getTypeId()) : _sitePositionsLJ.size();
196
197 // get siteIds
198 const std::vector<size_t> siteIdsA =
199 useMixing ? _PPLibrary->getSiteTypes(particleA.getTypeId()) : std::vector<unsigned long>();
200 const std::vector<size_t> siteIdsB =
201 useMixing ? _PPLibrary->getSiteTypes(particleB.getTypeId()) : std::vector<unsigned long>();
202
203 // get unrotated relative site positions
204 const std::vector<std::array<double, 3>> unrotatedSitePositionsA =
205 useMixing ? _PPLibrary->getSitePositions(particleA.getTypeId()) : _sitePositionsLJ;
206 const std::vector<std::array<double, 3>> unrotatedSitePositionsB =
207 useMixing ? _PPLibrary->getSitePositions(particleB.getTypeId()) : _sitePositionsLJ;
208
209 // calculate correctly rotated relative site positions
210 const auto rotatedSitePositionsA =
211 autopas::utils::quaternion::rotateVectorOfPositions(particleA.getQuaternion(), unrotatedSitePositionsA);
212 const auto rotatedSitePositionsB =
213 autopas::utils::quaternion::rotateVectorOfPositions(particleB.getQuaternion(), unrotatedSitePositionsB);
214
215 for (int i = 0; i < numSitesA; i++) {
216 for (int j = 0; j < numSitesB; j++) {
217 const auto displacement = autopas::utils::ArrayMath::add(
218 autopas::utils::ArrayMath::sub(displacementCoM, rotatedSitePositionsB[j]), rotatedSitePositionsA[i]);
219 const auto distanceSquared = autopas::utils::ArrayMath::dot(displacement, displacement);
220
221 const auto sigmaSquared =
222 useMixing ? _PPLibrary->getMixingSigmaSquared(siteIdsA[i], siteIdsB[j]) : _sigmaSquared;
223 const auto epsilon24 = useMixing ? _PPLibrary->getMixing24Epsilon(siteIdsA[i], siteIdsB[j]) : _epsilon24;
224 const auto shift6 =
225 applyShift ? (useMixing ? _PPLibrary->getMixingShift6(siteIdsA[i], siteIdsB[j]) : _shift6) : 0;
226
227 // clang-format off
228 // Calculate potential between sites and thus force
229 // Force = 24 * epsilon * (2*(sigma/distance)^12 - (sigma/distance)^6) * (1/distance)^2 * [x_displacement, y_displacement, z_displacement]
230 // { scalarMultiple } * { displacement }
231 // clang-format on
232 const auto invDistSquared = 1. / distanceSquared;
233 const auto lj2 = sigmaSquared * invDistSquared;
234 const auto lj6 = lj2 * lj2 * lj2;
235 const auto lj12 = lj6 * lj6;
236 const auto lj12m6 = lj12 - lj6; // = LJ potential / (4x epsilon)
237 const auto scalarMultiple = epsilon24 * (lj12 + lj12m6) * invDistSquared;
238 const auto force = autopas::utils::ArrayMath::mulScalar(displacement, scalarMultiple);
239
240 // Add force on site to net force
241 particleA.addF(force);
242 if (newton3) {
243 particleB.subF(force);
244 }
245
246 // Add torque applied by force
247 particleA.addTorque(autopas::utils::ArrayMath::cross(rotatedSitePositionsA[i], force));
248 if (newton3) {
249 particleB.subTorque(autopas::utils::ArrayMath::cross(rotatedSitePositionsB[j], force));
250 }
251
252 if (calculateGlobals) {
253 // We always add the full contribution for each owned particle and divide the sums by 2 in endTraversal().
254 // Potential energy has an additional factor of 6, which is also handled in endTraversal().
255 const auto potentialEnergy6 = epsilon24 * lj12m6 + shift6;
256 const auto virial = displacement * force;
257
258 const auto threadNum = autopas::autopas_get_thread_num();
259
260 if (particleA.isOwned()) {
261 _aosThreadData[threadNum].potentialEnergySum += potentialEnergy6;
262 _aosThreadData[threadNum].virialSum += virial;
263 }
264 // for non-newton3 the second particle will be considered in a separate calculation
265 if (newton3 and particleB.isOwned()) {
266 _aosThreadData[threadNum].potentialEnergySum += potentialEnergy6;
267 _aosThreadData[threadNum].virialSum += virial;
268 }
269 }
270 }
271 }
272 }
273
279 void SoAFunctorSingle(autopas::SoAView<SoAArraysType> soa, bool newton3) final {
280 if (soa.size() == 0) return;
281
282 const auto *const __restrict xptr = soa.template begin<Particle_T::AttributeNames::posX>();
283 const auto *const __restrict yptr = soa.template begin<Particle_T::AttributeNames::posY>();
284 const auto *const __restrict zptr = soa.template begin<Particle_T::AttributeNames::posZ>();
285
286 const auto *const __restrict ownedStatePtr = soa.template begin<Particle_T::AttributeNames::ownershipState>();
287
288 const auto *const __restrict q0ptr = soa.template begin<Particle_T::AttributeNames::quaternion0>();
289 const auto *const __restrict q1ptr = soa.template begin<Particle_T::AttributeNames::quaternion1>();
290 const auto *const __restrict q2ptr = soa.template begin<Particle_T::AttributeNames::quaternion2>();
291 const auto *const __restrict q3ptr = soa.template begin<Particle_T::AttributeNames::quaternion3>();
292
293 SoAFloatPrecision *const __restrict fxptr = soa.template begin<Particle_T::AttributeNames::forceX>();
294 SoAFloatPrecision *const __restrict fyptr = soa.template begin<Particle_T::AttributeNames::forceY>();
295 SoAFloatPrecision *const __restrict fzptr = soa.template begin<Particle_T::AttributeNames::forceZ>();
296
297 SoAFloatPrecision *const __restrict txptr = soa.template begin<Particle_T::AttributeNames::torqueX>();
298 SoAFloatPrecision *const __restrict typtr = soa.template begin<Particle_T::AttributeNames::torqueY>();
299 SoAFloatPrecision *const __restrict tzptr = soa.template begin<Particle_T::AttributeNames::torqueZ>();
300
301 [[maybe_unused]] auto *const __restrict typeptr = soa.template begin<Particle_T::AttributeNames::typeId>();
302
303 SoAFloatPrecision potentialEnergySum = 0.;
304 SoAFloatPrecision virialSumX = 0.;
305 SoAFloatPrecision virialSumY = 0.;
306 SoAFloatPrecision virialSumZ = 0.;
307
308 // the local redeclaration of the following values helps the SoAFloatPrecision-generation of various compilers.
309 const SoAFloatPrecision cutoffSquared = _cutoffSquared;
310
311 std::vector<SoAFloatPrecision, autopas::AlignedAllocator<SoAFloatPrecision>> sigmaSquareds;
312 std::vector<SoAFloatPrecision, autopas::AlignedAllocator<SoAFloatPrecision>> epsilon24s;
313 std::vector<SoAFloatPrecision, autopas::AlignedAllocator<SoAFloatPrecision>> shift6s;
314
315 std::vector<SoAFloatPrecision, autopas::AlignedAllocator<SoAFloatPrecision>> exactSitePositionX;
316 std::vector<SoAFloatPrecision, autopas::AlignedAllocator<SoAFloatPrecision>> exactSitePositionY;
317 std::vector<SoAFloatPrecision, autopas::AlignedAllocator<SoAFloatPrecision>> exactSitePositionZ;
318
319 // we require arrays for forces for sites to maintain SIMD in site-site calculations
320 std::vector<SoAFloatPrecision, autopas::AlignedAllocator<SoAFloatPrecision>> siteForceX;
321 std::vector<SoAFloatPrecision, autopas::AlignedAllocator<SoAFloatPrecision>> siteForceY;
322 std::vector<SoAFloatPrecision, autopas::AlignedAllocator<SoAFloatPrecision>> siteForceZ;
323
324 std::vector<size_t, autopas::AlignedAllocator<size_t>> siteTypes;
325 std::vector<char, autopas::AlignedAllocator<char>> isSiteOwned;
326
327 const SoAFloatPrecision const_sigmaSquared = _sigmaSquared;
328 const SoAFloatPrecision const_epsilon24 = _epsilon24;
329 const SoAFloatPrecision const_shift6 = _shift6;
330
331 const auto const_unrotatedSitePositions = _sitePositionsLJ;
332
333 // count number of sites in SoA
334 size_t siteCount = 0;
335 if constexpr (useMixing) {
336 for (size_t mol = 0; mol < soa.size(); ++mol) {
337 siteCount += _PPLibrary->getNumSites(typeptr[mol]);
338 }
339 } else {
340 siteCount = const_unrotatedSitePositions.size() * soa.size();
341 }
342
343 // pre-reserve site std::vectors
344 exactSitePositionX.reserve(siteCount);
345 exactSitePositionY.reserve(siteCount);
346 exactSitePositionZ.reserve(siteCount);
347
348 if constexpr (useMixing) {
349 siteTypes.reserve(siteCount);
350 }
351
352 siteForceX.reserve((siteCount));
353 siteForceY.reserve((siteCount));
354 siteForceZ.reserve((siteCount));
355
356 if constexpr (calculateGlobals) {
357 // this is only needed for vectorization when calculating globals
358 isSiteOwned.reserve(siteCount);
359 }
360
361 // Fill site-wise std::vectors for SIMD
362 if constexpr (useMixing) {
363 size_t siteIndex = 0;
364 for (size_t mol = 0; mol < soa.size(); ++mol) {
365 const auto rotatedSitePositions = autopas::utils::quaternion::rotateVectorOfPositions(
366 {q0ptr[mol], q1ptr[mol], q2ptr[mol], q3ptr[mol]}, _PPLibrary->getSitePositions(typeptr[mol]));
367 const auto siteTypesOfMol = _PPLibrary->getSiteTypes(typeptr[mol]);
368
369 for (size_t site = 0; site < _PPLibrary->getNumSites(typeptr[mol]); ++site) {
370 exactSitePositionX[siteIndex] = rotatedSitePositions[site][0] + xptr[mol];
371 exactSitePositionY[siteIndex] = rotatedSitePositions[site][1] + yptr[mol];
372 exactSitePositionZ[siteIndex] = rotatedSitePositions[site][2] + zptr[mol];
373 siteTypes[siteIndex] = siteTypesOfMol[site];
374 siteForceX[siteIndex] = 0.;
375 siteForceY[siteIndex] = 0.;
376 siteForceZ[siteIndex] = 0.;
377 if (calculateGlobals) {
378 isSiteOwned[siteIndex] = ownedStatePtr[mol] == autopas::OwnershipState::owned;
379 }
380 ++siteIndex;
381 }
382 }
383 } else {
384 size_t siteIndex = 0;
385 for (size_t mol = 0; mol < soa.size(); mol++) {
386 const auto rotatedSitePositions = autopas::utils::quaternion::rotateVectorOfPositions(
387 {q0ptr[mol], q1ptr[mol], q2ptr[mol], q3ptr[mol]}, const_unrotatedSitePositions);
388 for (size_t site = 0; site < const_unrotatedSitePositions.size(); ++site) {
389 exactSitePositionX[siteIndex] = rotatedSitePositions[site][0] + xptr[mol];
390 exactSitePositionY[siteIndex] = rotatedSitePositions[site][1] + yptr[mol];
391 exactSitePositionZ[siteIndex] = rotatedSitePositions[site][2] + zptr[mol];
392 siteForceX[siteIndex] = 0.;
393 siteForceY[siteIndex] = 0.;
394 siteForceZ[siteIndex] = 0.;
395 if (calculateGlobals) {
396 isSiteOwned[siteIndex] = ownedStatePtr[mol] == autopas::OwnershipState::owned;
397 }
398 ++siteIndex;
399 }
400 }
401 }
402
403 // main force calculation loop
404 size_t siteIndexMolA = 0; // index of first site in molA
405 for (size_t molA = 0; molA < soa.size(); ++molA) {
406 const size_t noSitesInMolA = useMixing ? _PPLibrary->getNumSites(typeptr[molA])
407 : const_unrotatedSitePositions.size(); // Number of sites in molecule A
408
409 const auto ownedStateA = ownedStatePtr[molA];
410 if (ownedStateA == autopas::OwnershipState::dummy) {
411 siteIndexMolA += noSitesInMolA;
412 continue;
413 }
414
415 const size_t siteIndexMolB = siteIndexMolA + noSitesInMolA; // index of first site in molB
416 const size_t noSitesB = (siteCount - siteIndexMolB); // Number of sites in molecules that A interacts with
417
418 // create mask over every mol 'above' molA (char to keep arrays aligned)
419 std::vector<char, autopas::AlignedAllocator<char>> molMask;
420 molMask.reserve(soa.size() - (molA + 1));
421
422#pragma omp simd
423 for (size_t molB = molA + 1; molB < soa.size(); ++molB) {
424 const auto ownedStateB = ownedStatePtr[molB];
425
426 const auto displacementCoMX = xptr[molA] - xptr[molB];
427 const auto displacementCoMY = yptr[molA] - yptr[molB];
428 const auto displacementCoMZ = zptr[molA] - zptr[molB];
429
430 const auto distanceSquaredCoMX = displacementCoMX * displacementCoMX;
431 const auto distanceSquaredCoMY = displacementCoMY * displacementCoMY;
432 const auto distanceSquaredCoMZ = displacementCoMZ * displacementCoMZ;
433
434 const auto distanceSquaredCoM = distanceSquaredCoMX + distanceSquaredCoMY + distanceSquaredCoMZ;
435
436 // mask sites of molecules beyond cutoff or if molecule is a dummy
437 molMask[molB - (molA + 1)] =
438 distanceSquaredCoM <= cutoffSquared and ownedStateB != autopas::OwnershipState::dummy;
439 }
440
441 // generate mask for each site in the mols 'above' molA from molecular mask
442 std::vector<char, autopas::AlignedAllocator<char>> siteMask;
443 siteMask.reserve(noSitesB);
444
445 for (size_t molB = molA + 1; molB < soa.size(); ++molB) {
446 for (size_t siteB = 0; siteB < _PPLibrary->getNumSites(typeptr[molB]); ++siteB) {
447 siteMask.emplace_back(molMask[molB - (molA + 1)]);
448 }
449 }
450
451 // calculate LJ forces
452 for (size_t siteA = siteIndexMolA; siteA < siteIndexMolB; ++siteA) {
453 if (useMixing) {
454 // preload sigmas, epsilons, and shifts
455 sigmaSquareds.reserve(noSitesB);
456 epsilon24s.reserve(noSitesB);
457 if constexpr (applyShift) {
458 shift6s.reserve(noSitesB);
459 }
460
461 for (size_t siteB = 0; siteB < siteCount - (siteIndexMolB); ++siteB) {
462 const auto mixingData = _PPLibrary->getLJMixingData(siteTypes[siteA], siteTypes[siteIndexMolB + siteB]);
463 sigmaSquareds[siteB] = mixingData.sigmaSquared;
464 epsilon24s[siteB] = mixingData.epsilon24;
465 if (applyShift) {
466 shift6s[siteB] = mixingData.shift6;
467 }
468 }
469 }
470 // sums used for siteA
471 SoAFloatPrecision forceSumX = 0.;
472 SoAFloatPrecision forceSumY = 0.;
473 SoAFloatPrecision forceSumZ = 0.;
474 SoAFloatPrecision torqueSumX = 0.;
475 SoAFloatPrecision torqueSumY = 0.;
476 SoAFloatPrecision torqueSumZ = 0.;
477
478#pragma omp simd reduction (+ : forceSumX, forceSumY, forceSumZ, torqueSumX, torqueSumY, torqueSumZ, potentialEnergySum, virialSumX, virialSumY, virialSumZ)
479 for (size_t siteB = 0; siteB < noSitesB; ++siteB) {
480 const size_t globalSiteBIndex = siteB + siteIndexMolB;
481
482 const SoAFloatPrecision sigmaSquared = useMixing ? sigmaSquareds[siteB] : const_sigmaSquared;
483 const SoAFloatPrecision epsilon24 = useMixing ? epsilon24s[siteB] : const_epsilon24;
484 const SoAFloatPrecision shift6 = applyShift ? (useMixing ? shift6s[siteB] : const_shift6) : 0;
485
486 const auto isSiteBOwned = !calculateGlobals || isSiteOwned[globalSiteBIndex];
487
488 const auto displacementX = exactSitePositionX[siteA] - exactSitePositionX[globalSiteBIndex];
489 const auto displacementY = exactSitePositionY[siteA] - exactSitePositionY[globalSiteBIndex];
490 const auto displacementZ = exactSitePositionZ[siteA] - exactSitePositionZ[globalSiteBIndex];
491
492 const auto distanceSquaredX = displacementX * displacementX;
493 const auto distanceSquaredY = displacementY * displacementY;
494 const auto distanceSquaredZ = displacementZ * displacementZ;
495
496 const auto distanceSquared = distanceSquaredX + distanceSquaredY + distanceSquaredZ;
497
498 const auto invDistSquared = 1. / distanceSquared;
499 const auto lj2 = sigmaSquared * invDistSquared;
500 const auto lj6 = lj2 * lj2 * lj2;
501 const auto lj12 = lj6 * lj6;
502 const auto lj12m6 = lj12 - lj6;
503 const auto scalarMultiple = siteMask[siteB] ? epsilon24 * (lj12 + lj12m6) * invDistSquared : 0.;
504
505 // calculate forces
506 const auto forceX = scalarMultiple * displacementX;
507 const auto forceY = scalarMultiple * displacementY;
508 const auto forceZ = scalarMultiple * displacementZ;
509
510 forceSumX += forceX;
511 forceSumY += forceY;
512 forceSumZ += forceZ;
513
514 // newton's third law
515 siteForceX[globalSiteBIndex] -= forceX;
516 siteForceY[globalSiteBIndex] -= forceY;
517 siteForceZ[globalSiteBIndex] -= forceZ;
518
519 if constexpr (calculateGlobals) {
520 const auto virialX = displacementX * forceX;
521 const auto virialY = displacementY * forceY;
522 const auto virialZ = displacementZ * forceZ;
523 const auto potentialEnergy6 = siteMask[siteB] ? (epsilon24 * lj12m6 + shift6) : 0.;
524
525 // We add 6 times the potential energy for each owned particle. The total sum is corrected in
526 // endTraversal().
527 const auto ownershipMask =
528 (ownedStateA == autopas::OwnershipState::owned ? 1. : 0.) + (isSiteBOwned ? 1. : 0.);
529 potentialEnergySum += potentialEnergy6 * ownershipMask;
530 virialSumX += virialX * ownershipMask;
531 virialSumY += virialY * ownershipMask;
532 virialSumZ += virialZ * ownershipMask;
533 }
534 }
535 // sum forces on single site in mol A
536 siteForceX[siteA] += forceSumX;
537 siteForceY[siteA] += forceSumY;
538 siteForceZ[siteA] += forceSumZ;
539 }
540 siteIndexMolA += noSitesInMolA;
541 }
542
543 // reduce the forces on individual sites to forces & torques on whole molecules.
544 if constexpr (useMixing) {
545 size_t siteIndex = 0;
546 for (size_t mol = 0; mol < soa.size(); ++mol) {
547 const auto rotatedSitePositions = autopas::utils::quaternion::rotateVectorOfPositions(
548 {q0ptr[mol], q1ptr[mol], q2ptr[mol], q3ptr[mol]}, _PPLibrary->getSitePositions(typeptr[mol]));
549 for (size_t site = 0; site < _PPLibrary->getNumSites(typeptr[mol]); ++site) {
550 fxptr[mol] += siteForceX[siteIndex];
551 fyptr[mol] += siteForceY[siteIndex];
552 fzptr[mol] += siteForceZ[siteIndex];
553 txptr[mol] += rotatedSitePositions[site][1] * siteForceZ[siteIndex] -
554 rotatedSitePositions[site][2] * siteForceY[siteIndex];
555 typtr[mol] += rotatedSitePositions[site][2] * siteForceX[siteIndex] -
556 rotatedSitePositions[site][0] * siteForceZ[siteIndex];
557 tzptr[mol] += rotatedSitePositions[site][0] * siteForceY[siteIndex] -
558 rotatedSitePositions[site][1] * siteForceX[siteIndex];
559 ++siteIndex;
560 }
561 }
562 } else {
563 size_t siteIndex = 0;
564 for (size_t mol = 0; mol < soa.size(); mol++) {
565 const auto rotatedSitePositions = autopas::utils::quaternion::rotateVectorOfPositions(
566 {q0ptr[mol], q1ptr[mol], q2ptr[mol], q3ptr[mol]}, const_unrotatedSitePositions);
567 for (size_t site = 0; site < const_unrotatedSitePositions.size(); ++site) {
568 fxptr[mol] += siteForceX[siteIndex];
569 fyptr[mol] += siteForceY[siteIndex];
570 fzptr[mol] += siteForceZ[siteIndex];
571 txptr[mol] += rotatedSitePositions[site][1] * siteForceZ[siteIndex] -
572 rotatedSitePositions[site][2] * siteForceY[siteIndex];
573 typtr[mol] += rotatedSitePositions[site][2] * siteForceX[siteIndex] -
574 rotatedSitePositions[site][0] * siteForceZ[siteIndex];
575 tzptr[mol] += rotatedSitePositions[site][0] * siteForceY[siteIndex] -
576 rotatedSitePositions[site][1] * siteForceX[siteIndex];
577 ++siteIndex;
578 }
579 }
580 }
581
582 if constexpr (calculateGlobals) {
583 const auto threadNum = autopas::autopas_get_thread_num();
584
585 _aosThreadData[threadNum].potentialEnergySum += potentialEnergySum;
586 _aosThreadData[threadNum].virialSum[0] += virialSumX;
587 _aosThreadData[threadNum].virialSum[1] += virialSumY;
588 _aosThreadData[threadNum].virialSum[2] += virialSumZ;
589 }
590 }
595 const bool newton3) final {
596 if (newton3) {
597 SoAFunctorPairImpl<true>(soa1, soa2);
598 } else {
599 SoAFunctorPairImpl<false>(soa1, soa2);
600 }
601 }
602
603 // clang-format off
607 // clang-format on
608 void SoAFunctorVerlet(autopas::SoAView<SoAArraysType> soa, const size_t indexFirst,
609 const std::vector<size_t, autopas::AlignedAllocator<size_t>> &neighborList,
610 bool newton3) final {
611 if (soa.size() == 0 or neighborList.empty()) return;
612 if (newton3) {
613 SoAFunctorVerletImpl<true>(soa, indexFirst, neighborList);
614 } else {
615 SoAFunctorVerletImpl<false>(soa, indexFirst, neighborList);
616 }
617 }
618
627 void setParticleProperties(SoAFloatPrecision epsilon24, SoAFloatPrecision sigmaSquared,
628 std::vector<std::array<SoAFloatPrecision, 3>> sitePositionsLJ) {
629 _epsilon24 = epsilon24;
630 _sigmaSquared = sigmaSquared;
631 if (applyShift) {
632 _shift6 = ParticlePropertiesLibrary<double, size_t>::calcShift6(_epsilon24, _sigmaSquared, _cutoffSquared);
633 } else {
634 _shift6 = 0;
635 }
636 _sitePositionsLJ = sitePositionsLJ;
637 }
638
642 constexpr static auto getNeededAttr() {
643 return std::array<typename Particle_T::AttributeNames, 16>{
644 Particle_T::AttributeNames::id, Particle_T::AttributeNames::posX,
645 Particle_T::AttributeNames::posY, Particle_T::AttributeNames::posZ,
646 Particle_T::AttributeNames::forceX, Particle_T::AttributeNames::forceY,
647 Particle_T::AttributeNames::forceZ, Particle_T::AttributeNames::quaternion0,
648 Particle_T::AttributeNames::quaternion1, Particle_T::AttributeNames::quaternion2,
649 Particle_T::AttributeNames::quaternion3, Particle_T::AttributeNames::torqueX,
650 Particle_T::AttributeNames::torqueY, Particle_T::AttributeNames::torqueZ,
651 Particle_T::AttributeNames::typeId, Particle_T::AttributeNames::ownershipState};
652 }
653
657 constexpr static auto getNeededAttr(std::false_type) {
658 return std::array<typename Particle_T::AttributeNames, 16>{
659 Particle_T::AttributeNames::id, Particle_T::AttributeNames::posX,
660 Particle_T::AttributeNames::posY, Particle_T::AttributeNames::posZ,
661 Particle_T::AttributeNames::forceX, Particle_T::AttributeNames::forceY,
662 Particle_T::AttributeNames::forceZ, Particle_T::AttributeNames::quaternion0,
663 Particle_T::AttributeNames::quaternion1, Particle_T::AttributeNames::quaternion2,
664 Particle_T::AttributeNames::quaternion3, Particle_T::AttributeNames::torqueX,
665 Particle_T::AttributeNames::torqueY, Particle_T::AttributeNames::torqueZ,
666 Particle_T::AttributeNames::typeId, Particle_T::AttributeNames::ownershipState};
667 }
668
672 constexpr static auto getComputedAttr() {
673 return std::array<typename Particle_T::AttributeNames, 6>{
674 Particle_T::AttributeNames::forceX, Particle_T::AttributeNames::forceY, Particle_T::AttributeNames::forceZ,
675 Particle_T::AttributeNames::torqueX, Particle_T::AttributeNames::torqueY, Particle_T::AttributeNames::torqueZ};
676 }
677
681 constexpr static bool getMixing() { return useMixing; }
682
693 unsigned long getNumFlopsPerKernelCall(size_t molAType, size_t molBType, bool newton3) {
694 // Site-to-site displacement: 6 (3 in the SoA case, but this requires O(N) precomputing site positions)
695 // Site-to-site distance squared: 4
696 // Compute scale: 9
697 // Apply scale to force: With newton3: 6, Without: 3
698 // Apply scale to torque: With newton3 18, Without: 9 (0 in SoA case, with O(N) post computing)
699 // Site-to-site total: With newton3: 33, Without: 26
700 // (SoA total: With N3L: 22, Without N3L: 19)
701 // Above multiplied by number sites of i * number sites of j
702 const unsigned long siteToSiteFlops = newton3 ? 33ul : 26ul;
703 return _PPLibrary->getNumSites(molAType) * _PPLibrary->getNumSites(molBType) * siteToSiteFlops;
704 }
705
710 void initTraversal() final {
711 _potentialEnergySum = 0;
712 _virialSum = {0., 0., 0.};
713 _postProcessed = false;
714 for (size_t i = 0; i < _aosThreadData.size(); i++) {
715 _aosThreadData[i].setZero();
716 }
717 }
718
723 void endTraversal(bool newton3) final {
724 using namespace autopas::utils::ArrayMath::literals;
725
726 if (_postProcessed) {
728 "Already postprocessed, endTraversal(bool newton3) was called twice without calling initTraversal().");
729 }
730 if (calculateGlobals) {
731 for (size_t i = 0; i < _aosThreadData.size(); ++i) {
732 _potentialEnergySum += _aosThreadData[i].potentialEnergySum;
733 _virialSum += _aosThreadData[i].virialSum;
734 }
735
736 // For each interaction, we added the full contribution for both particles. Divide by 2 here, so that each
737 // contribution is only counted once per pair.
738 _potentialEnergySum *= 0.5;
739 _virialSum *= 0.5;
740
741 // We have always calculated 6*potentialEnergy, so we divide by 6 here!
742 _potentialEnergySum /= 6.;
743 _postProcessed = true;
744
745 AutoPasLog(DEBUG, "Final potential energy {}", _potentialEnergySum);
746 AutoPasLog(DEBUG, "Final virial {}", _virialSum[0] + _virialSum[1] + _virialSum[2]);
747 }
748 }
749
756 if (not calculateGlobals) {
758 "Trying to get potential energy even though calculateGlobals is false. If you want this functor to calculate "
759 "global "
760 "values, please specify calculateGlobals to be true.");
761 }
762 if (not _postProcessed) {
764 "Cannot get potential energy, because endTraversal was not called.");
765 }
766 return _potentialEnergySum;
767 }
768
773 double getVirial() {
774 if (not calculateGlobals) {
776 "Trying to get virial even though calculateGlobals is false. If you want this functor to calculate global "
777 "values, please specify calculateGlobals to be true.");
778 }
779 if (not _postProcessed) {
781 "Cannot get virial, because endTraversal was not called.");
782 }
783 return _virialSum[0] + _virialSum[1] + _virialSum[2];
784 }
785
786 private:
793 template <bool newton3>
794 void SoAFunctorPairImpl(autopas::SoAView<SoAArraysType> soaA, autopas::SoAView<SoAArraysType> soaB) {
795 if (soaA.size() == 0 || soaB.size() == 0) return;
796
797 const auto *const __restrict xAptr = soaA.template begin<Particle_T::AttributeNames::posX>();
798 const auto *const __restrict yAptr = soaA.template begin<Particle_T::AttributeNames::posY>();
799 const auto *const __restrict zAptr = soaA.template begin<Particle_T::AttributeNames::posZ>();
800 const auto *const __restrict xBptr = soaB.template begin<Particle_T::AttributeNames::posX>();
801 const auto *const __restrict yBptr = soaB.template begin<Particle_T::AttributeNames::posY>();
802 const auto *const __restrict zBptr = soaB.template begin<Particle_T::AttributeNames::posZ>();
803
804 const auto *const __restrict ownedStatePtrA = soaA.template begin<Particle_T::AttributeNames::ownershipState>();
805 const auto *const __restrict ownedStatePtrB = soaB.template begin<Particle_T::AttributeNames::ownershipState>();
806
807 const auto *const __restrict q0Aptr = soaA.template begin<Particle_T::AttributeNames::quaternion0>();
808 const auto *const __restrict q1Aptr = soaA.template begin<Particle_T::AttributeNames::quaternion1>();
809 const auto *const __restrict q2Aptr = soaA.template begin<Particle_T::AttributeNames::quaternion2>();
810 const auto *const __restrict q3Aptr = soaA.template begin<Particle_T::AttributeNames::quaternion3>();
811 const auto *const __restrict q0Bptr = soaB.template begin<Particle_T::AttributeNames::quaternion0>();
812 const auto *const __restrict q1Bptr = soaB.template begin<Particle_T::AttributeNames::quaternion1>();
813 const auto *const __restrict q2Bptr = soaB.template begin<Particle_T::AttributeNames::quaternion2>();
814 const auto *const __restrict q3Bptr = soaB.template begin<Particle_T::AttributeNames::quaternion3>();
815
816 SoAFloatPrecision *const __restrict fxAptr = soaA.template begin<Particle_T::AttributeNames::forceX>();
817 SoAFloatPrecision *const __restrict fyAptr = soaA.template begin<Particle_T::AttributeNames::forceY>();
818 SoAFloatPrecision *const __restrict fzAptr = soaA.template begin<Particle_T::AttributeNames::forceZ>();
819 SoAFloatPrecision *const __restrict fxBptr = soaB.template begin<Particle_T::AttributeNames::forceX>();
820 SoAFloatPrecision *const __restrict fyBptr = soaB.template begin<Particle_T::AttributeNames::forceY>();
821 SoAFloatPrecision *const __restrict fzBptr = soaB.template begin<Particle_T::AttributeNames::forceZ>();
822
823 SoAFloatPrecision *const __restrict txAptr = soaA.template begin<Particle_T::AttributeNames::torqueX>();
824 SoAFloatPrecision *const __restrict tyAptr = soaA.template begin<Particle_T::AttributeNames::torqueY>();
825 SoAFloatPrecision *const __restrict tzAptr = soaA.template begin<Particle_T::AttributeNames::torqueZ>();
826 SoAFloatPrecision *const __restrict txBptr = soaB.template begin<Particle_T::AttributeNames::torqueX>();
827 SoAFloatPrecision *const __restrict tyBptr = soaB.template begin<Particle_T::AttributeNames::torqueY>();
828 SoAFloatPrecision *const __restrict tzBptr = soaB.template begin<Particle_T::AttributeNames::torqueZ>();
829
830 [[maybe_unused]] auto *const __restrict typeptrA = soaA.template begin<Particle_T::AttributeNames::typeId>();
831 [[maybe_unused]] auto *const __restrict typeptrB = soaB.template begin<Particle_T::AttributeNames::typeId>();
832
833 SoAFloatPrecision potentialEnergySum = 0.;
834 SoAFloatPrecision virialSumX = 0.;
835 SoAFloatPrecision virialSumY = 0.;
836 SoAFloatPrecision virialSumZ = 0.;
837
838 // local redeclarations to help compilers
839 const SoAFloatPrecision cutoffSquared = _cutoffSquared;
840
841 std::vector<SoAFloatPrecision, autopas::AlignedAllocator<SoAFloatPrecision>> sigmaSquareds;
842 std::vector<SoAFloatPrecision, autopas::AlignedAllocator<SoAFloatPrecision>> epsilon24s;
843 std::vector<SoAFloatPrecision, autopas::AlignedAllocator<SoAFloatPrecision>> shift6s;
844
845 std::vector<SoAFloatPrecision, autopas::AlignedAllocator<SoAFloatPrecision>> exactSitePositionBx;
846 std::vector<SoAFloatPrecision, autopas::AlignedAllocator<SoAFloatPrecision>> exactSitePositionBy;
847 std::vector<SoAFloatPrecision, autopas::AlignedAllocator<SoAFloatPrecision>> exactSitePositionBz;
848
849 // we require arrays for forces for sites to maintain SIMD in site-site calculations
850 std::vector<SoAFloatPrecision, autopas::AlignedAllocator<SoAFloatPrecision>> siteForceBx;
851 std::vector<SoAFloatPrecision, autopas::AlignedAllocator<SoAFloatPrecision>> siteForceBy;
852 std::vector<SoAFloatPrecision, autopas::AlignedAllocator<SoAFloatPrecision>> siteForceBz;
853
854 std::vector<size_t, autopas::AlignedAllocator<size_t>> siteTypesB;
855 std::vector<char, autopas::AlignedAllocator<char>> isSiteOwnedBArr;
856
857 const SoAFloatPrecision const_sigmaSquared = _sigmaSquared;
858 const SoAFloatPrecision const_epsilon24 = _epsilon24;
859 const SoAFloatPrecision const_shift6 = _shift6;
860
861 const auto const_unrotatedSitePositions = _sitePositionsLJ;
862
863 // count number of sites in both SoAs
864 size_t siteCountB = 0;
865 if constexpr (useMixing) {
866 for (size_t mol = 0; mol < soaB.size(); ++mol) {
867 siteCountB += _PPLibrary->getNumSites(typeptrB[mol]);
868 }
869 } else {
870 siteCountB = const_unrotatedSitePositions.size() * soaB.size();
871 }
872
873 // pre-reserve std::vectors
874 exactSitePositionBx.reserve(siteCountB);
875 exactSitePositionBy.reserve(siteCountB);
876 exactSitePositionBz.reserve(siteCountB);
877
878 if constexpr (useMixing) {
879 siteTypesB.reserve(siteCountB);
880 }
881
882 siteForceBx.reserve(siteCountB);
883 siteForceBy.reserve(siteCountB);
884 siteForceBz.reserve(siteCountB);
885
886 if constexpr (calculateGlobals) {
887 // this is only needed for vectorization when calculating globals
888 isSiteOwnedBArr.reserve(siteCountB);
889 }
890
891 if constexpr (useMixing) {
892 siteTypesB.reserve(siteCountB);
893 sigmaSquareds.reserve(siteCountB);
894 epsilon24s.reserve(siteCountB);
895 if constexpr (applyShift) {
896 shift6s.reserve(siteCountB);
897 }
898 }
899
900 // Fill site-wise std::vectors for SIMD
901 if constexpr (useMixing) {
902 size_t siteIndex = 0;
903 for (size_t mol = 0; mol < soaB.size(); ++mol) {
904 const auto rotatedSitePositions = autopas::utils::quaternion::rotateVectorOfPositions(
905 {q0Bptr[mol], q1Bptr[mol], q2Bptr[mol], q3Bptr[mol]}, _PPLibrary->getSitePositions(typeptrB[mol]));
906 const auto siteTypesOfMol = _PPLibrary->getSiteTypes(typeptrB[mol]);
907
908 for (size_t site = 0; site < _PPLibrary->getNumSites(typeptrB[mol]); ++site) {
909 exactSitePositionBx[siteIndex] = rotatedSitePositions[site][0] + xBptr[mol];
910 exactSitePositionBy[siteIndex] = rotatedSitePositions[site][1] + yBptr[mol];
911 exactSitePositionBz[siteIndex] = rotatedSitePositions[site][2] + zBptr[mol];
912 siteTypesB[siteIndex] = siteTypesOfMol[site];
913 siteForceBx[siteIndex] = 0.;
914 siteForceBy[siteIndex] = 0.;
915 siteForceBz[siteIndex] = 0.;
916 if (calculateGlobals) {
917 isSiteOwnedBArr[siteIndex] = ownedStatePtrB[mol] == autopas::OwnershipState::owned;
918 }
919 ++siteIndex;
920 }
921 }
922 } else {
923 size_t siteIndex = 0;
924 for (size_t mol = 0; mol < soaB.size(); mol++) {
925 const auto rotatedSitePositions = autopas::utils::quaternion::rotateVectorOfPositions(
926 {q0Bptr[mol], q1Bptr[mol], q2Bptr[mol], q3Bptr[mol]}, const_unrotatedSitePositions);
927 for (size_t site = 0; site < const_unrotatedSitePositions.size(); ++site) {
928 exactSitePositionBx[siteIndex] = rotatedSitePositions[site][0] + xBptr[mol];
929 exactSitePositionBy[siteIndex] = rotatedSitePositions[site][1] + yBptr[mol];
930 exactSitePositionBz[siteIndex] = rotatedSitePositions[site][2] + zBptr[mol];
931 siteForceBx[siteIndex] = 0.;
932 siteForceBy[siteIndex] = 0.;
933 siteForceBz[siteIndex] = 0.;
934 if (calculateGlobals) {
935 isSiteOwnedBArr[siteIndex] = ownedStatePtrB[mol] == autopas::OwnershipState::owned;
936 }
937 ++siteIndex;
938 }
939 }
940 }
941
942 // main force calculation loop
943 for (size_t molA = 0; molA < soaA.size(); ++molA) {
944 const auto ownedStateA = ownedStatePtrA[molA];
945 if (ownedStateA == autopas::OwnershipState::dummy) {
946 continue;
947 }
948
949 const auto noSitesInMolA =
950 useMixing ? _PPLibrary->getNumSites(typeptrA[molA]) : const_unrotatedSitePositions.size();
951 const auto unrotatedSitePositionsA =
952 useMixing ? _PPLibrary->getSitePositions(typeptrA[molA]) : const_unrotatedSitePositions;
953
954 const auto rotatedSitePositionsA = autopas::utils::quaternion::rotateVectorOfPositions(
955 {q0Aptr[molA], q1Aptr[molA], q2Aptr[molA], q3Aptr[molA]}, unrotatedSitePositionsA);
956
957 // create mask over every mol in cell B (char to keep arrays aligned)
958 std::vector<char, autopas::AlignedAllocator<char>> molMask;
959 molMask.reserve(soaB.size());
960
961#pragma omp simd
962 for (size_t molB = 0; molB < soaB.size(); ++molB) {
963 const auto ownedStateB = ownedStatePtrB[molB];
964
965 const auto displacementCoMX = xAptr[molA] - xBptr[molB];
966 const auto displacementCoMY = yAptr[molA] - yBptr[molB];
967 const auto displacementCoMZ = zAptr[molA] - zBptr[molB];
968
969 const auto distanceSquaredCoMX = displacementCoMX * displacementCoMX;
970 const auto distanceSquaredCoMY = displacementCoMY * displacementCoMY;
971 const auto distanceSquaredCoMZ = displacementCoMZ * displacementCoMZ;
972
973 const auto distanceSquaredCoM = distanceSquaredCoMX + distanceSquaredCoMY + distanceSquaredCoMZ;
974
975 // mask sites of molecules beyond cutoff or if molecule is a dummy
976 molMask[molB] = distanceSquaredCoM <= cutoffSquared and ownedStateB != autopas::OwnershipState::dummy;
977 }
978
979 // generate mask for each site in cell B from molecular mask
980 std::vector<char, autopas::AlignedAllocator<char>> siteMask;
981 siteMask.reserve(siteCountB);
982
983 for (size_t molB = 0; molB < soaB.size(); ++molB) {
984 for (size_t siteB = 0; siteB < _PPLibrary->getNumSites(typeptrB[molB]); ++siteB) {
985 siteMask.emplace_back(molMask[molB]);
986 }
987 }
988
989 // sums used for molA
990 SoAFloatPrecision forceSumX = 0.;
991 SoAFloatPrecision forceSumY = 0.;
992 SoAFloatPrecision forceSumZ = 0.;
993 SoAFloatPrecision torqueSumX = 0.;
994 SoAFloatPrecision torqueSumY = 0.;
995 SoAFloatPrecision torqueSumZ = 0.;
996
997 for (size_t siteA = 0; siteA < noSitesInMolA; ++siteA) {
998 if (useMixing) {
999 // preload sigmas, epsilons, and shifts
1000 for (size_t siteB = 0; siteB < siteCountB; ++siteB) {
1001 const auto mixingData =
1002 _PPLibrary->getLJMixingData(_PPLibrary->getSiteTypes(typeptrA[molA])[siteA], siteTypesB[siteB]);
1003 sigmaSquareds[siteB] = mixingData.sigmaSquared;
1004 epsilon24s[siteB] = mixingData.epsilon24;
1005 if (applyShift) {
1006 shift6s[siteB] = mixingData.shift6;
1007 }
1008 }
1009 }
1010
1011 const auto rotatedSitePositionAx = rotatedSitePositionsA[siteA][0];
1012 const auto rotatedSitePositionAy = rotatedSitePositionsA[siteA][1];
1013 const auto rotatedSitePositionAz = rotatedSitePositionsA[siteA][2];
1014
1015 const auto exactSitePositionAx = rotatedSitePositionAx + xAptr[molA];
1016 const auto exactSitePositionAy = rotatedSitePositionAy + yAptr[molA];
1017 const auto exactSitePositionAz = rotatedSitePositionAz + zAptr[molA];
1018
1019#pragma omp simd reduction (+ : forceSumX, forceSumY, forceSumZ, torqueSumX, torqueSumY, torqueSumZ, potentialEnergySum, virialSumX, virialSumY, virialSumZ)
1020 for (size_t siteB = 0; siteB < siteCountB; ++siteB) {
1021 const SoAFloatPrecision sigmaSquared = useMixing ? sigmaSquareds[siteB] : const_sigmaSquared;
1022 const SoAFloatPrecision epsilon24 = useMixing ? epsilon24s[siteB] : const_epsilon24;
1023 const SoAFloatPrecision shift6 = applyShift ? (useMixing ? shift6s[siteB] : const_shift6) : 0;
1024
1025 const auto isSiteOwnedB = !calculateGlobals || isSiteOwnedBArr[siteB];
1026
1027 const auto displacementX = exactSitePositionAx - exactSitePositionBx[siteB];
1028 const auto displacementY = exactSitePositionAy - exactSitePositionBy[siteB];
1029 const auto displacementZ = exactSitePositionAz - exactSitePositionBz[siteB];
1030
1031 const auto distanceSquaredX = displacementX * displacementX;
1032 const auto distanceSquaredY = displacementY * displacementY;
1033 const auto distanceSquaredZ = displacementZ * displacementZ;
1034
1035 const auto distanceSquared = distanceSquaredX + distanceSquaredY + distanceSquaredZ;
1036
1037 const auto invDistSquared = 1. / distanceSquared;
1038 const auto lj2 = sigmaSquared * invDistSquared;
1039 const auto lj6 = lj2 * lj2 * lj2;
1040 const auto lj12 = lj6 * lj6;
1041 const auto lj12m6 = lj12 - lj6;
1042 const auto scalarMultiple = siteMask[siteB] ? epsilon24 * (lj12 + lj12m6) * invDistSquared : 0.;
1043
1044 // calculate forces
1045 const auto forceX = scalarMultiple * displacementX;
1046 const auto forceY = scalarMultiple * displacementY;
1047 const auto forceZ = scalarMultiple * displacementZ;
1048
1049 forceSumX += forceX;
1050 forceSumY += forceY;
1051 forceSumZ += forceZ;
1052
1053 torqueSumX += rotatedSitePositionAy * forceZ - rotatedSitePositionAz * forceY;
1054 torqueSumY += rotatedSitePositionAz * forceX - rotatedSitePositionAx * forceZ;
1055 torqueSumZ += rotatedSitePositionAx * forceY - rotatedSitePositionAy * forceX;
1056
1057 // N3L ( total molecular forces + torques to be determined later )
1058 if constexpr (newton3) {
1059 siteForceBx[siteB] -= forceX;
1060 siteForceBy[siteB] -= forceY;
1061 siteForceBz[siteB] -= forceZ;
1062 }
1063
1064 // globals
1065 if constexpr (calculateGlobals) {
1066 const auto potentialEnergy6 = siteMask[siteB] ? (epsilon24 * lj12m6 + shift6) : 0.;
1067 const auto virialX = displacementX * forceX;
1068 const auto virialY = displacementY * forceY;
1069 const auto virialZ = displacementZ * forceZ;
1070
1071 // We add 6 times the potential energy for each owned particle. The total sum is corrected in
1072 // endTraversal().
1073 const auto ownershipFactor =
1074 newton3 ? (ownedStateA == autopas::OwnershipState::owned ? 1. : 0.) + (isSiteOwnedB ? 1. : 0.)
1075 : (ownedStateA == autopas::OwnershipState::owned ? 1. : 0.);
1076 potentialEnergySum += potentialEnergy6 * ownershipFactor;
1077 virialSumX += virialX * ownershipFactor;
1078 virialSumY += virialY * ownershipFactor;
1079 virialSumZ += virialZ * ownershipFactor;
1080 }
1081 }
1082 }
1083 fxAptr[molA] += forceSumX;
1084 fyAptr[molA] += forceSumY;
1085 fzAptr[molA] += forceSumZ;
1086 txAptr[molA] += torqueSumX;
1087 tyAptr[molA] += torqueSumY;
1088 tzAptr[molA] += torqueSumZ;
1089 }
1090
1091 // reduce the forces on individual sites in SoA B to total forces & torques on whole molecules
1092 if constexpr (useMixing) {
1093 size_t siteIndex = 0;
1094 for (size_t mol = 0; mol < soaB.size(); ++mol) {
1095 const auto rotatedSitePositions = autopas::utils::quaternion::rotateVectorOfPositions(
1096 {q0Bptr[mol], q1Bptr[mol], q2Bptr[mol], q3Bptr[mol]}, _PPLibrary->getSitePositions(typeptrB[mol]));
1097 for (size_t site = 0; site < _PPLibrary->getNumSites(typeptrB[mol]); ++site) {
1098 fxBptr[mol] += siteForceBx[siteIndex];
1099 fyBptr[mol] += siteForceBy[siteIndex];
1100 fzBptr[mol] += siteForceBz[siteIndex];
1101 txBptr[mol] += rotatedSitePositions[site][1] * siteForceBz[siteIndex] -
1102 rotatedSitePositions[site][2] * siteForceBy[siteIndex];
1103 tyBptr[mol] += rotatedSitePositions[site][2] * siteForceBx[siteIndex] -
1104 rotatedSitePositions[site][0] * siteForceBz[siteIndex];
1105 tzBptr[mol] += rotatedSitePositions[site][0] * siteForceBy[siteIndex] -
1106 rotatedSitePositions[site][1] * siteForceBx[siteIndex];
1107 ++siteIndex;
1108 }
1109 }
1110 } else {
1111 size_t siteIndex = 0;
1112 for (size_t mol = 0; mol < soaB.size(); ++mol) {
1113 const auto rotatedSitePositions = autopas::utils::quaternion::rotateVectorOfPositions(
1114 {q0Bptr[mol], q1Bptr[mol], q2Bptr[mol], q3Bptr[mol]}, const_unrotatedSitePositions);
1115 for (size_t site = 0; site < const_unrotatedSitePositions.size(); ++site) {
1116 fxBptr[mol] += siteForceBx[siteIndex];
1117 fyBptr[mol] += siteForceBy[siteIndex];
1118 fzBptr[mol] += siteForceBz[siteIndex];
1119 txBptr[mol] += rotatedSitePositions[site][1] * siteForceBz[siteIndex] -
1120 rotatedSitePositions[site][2] * siteForceBy[siteIndex];
1121 tyBptr[mol] += rotatedSitePositions[site][2] * siteForceBx[siteIndex] -
1122 rotatedSitePositions[site][0] * siteForceBz[siteIndex];
1123 tzBptr[mol] += rotatedSitePositions[site][0] * siteForceBy[siteIndex] -
1124 rotatedSitePositions[site][1] * siteForceBx[siteIndex];
1125 ++siteIndex;
1126 }
1127 }
1128 }
1129 if constexpr (calculateGlobals) {
1130 const auto threadNum = autopas::autopas_get_thread_num();
1131 // SoAFunctorPairImpl obtains the potential energy * 12. For non-newton3, this sum is divided by 12 in
1132 // post-processing. For newton3, this sum is only divided by 6 in post-processing, so must be divided by 2 here.
1133 _aosThreadData[threadNum].potentialEnergySum += potentialEnergySum;
1134 _aosThreadData[threadNum].virialSum[0] += virialSumX;
1135 _aosThreadData[threadNum].virialSum[1] += virialSumY;
1136 _aosThreadData[threadNum].virialSum[2] += virialSumZ;
1137 }
1138 }
1139
1140 template <bool newton3>
1141 void SoAFunctorVerletImpl(autopas::SoAView<SoAArraysType> soa, const size_t indexPrime,
1142 const std::vector<size_t, autopas::AlignedAllocator<size_t>> &neighborList) {
1143 const auto *const __restrict ownedStatePtr = soa.template begin<Particle_T::AttributeNames::ownershipState>();
1144
1145 // Skip if primary particle is dummy
1146 const auto ownedStatePrime = ownedStatePtr[indexPrime];
1147 if (ownedStatePrime == autopas::OwnershipState::dummy) {
1148 return;
1149 }
1150
1151 const auto *const __restrict xptr = soa.template begin<Particle_T::AttributeNames::posX>();
1152 const auto *const __restrict yptr = soa.template begin<Particle_T::AttributeNames::posY>();
1153 const auto *const __restrict zptr = soa.template begin<Particle_T::AttributeNames::posZ>();
1154
1155 const auto *const __restrict q0ptr = soa.template begin<Particle_T::AttributeNames::quaternion0>();
1156 const auto *const __restrict q1ptr = soa.template begin<Particle_T::AttributeNames::quaternion1>();
1157 const auto *const __restrict q2ptr = soa.template begin<Particle_T::AttributeNames::quaternion2>();
1158 const auto *const __restrict q3ptr = soa.template begin<Particle_T::AttributeNames::quaternion3>();
1159
1160 SoAFloatPrecision *const __restrict fxptr = soa.template begin<Particle_T::AttributeNames::forceX>();
1161 SoAFloatPrecision *const __restrict fyptr = soa.template begin<Particle_T::AttributeNames::forceY>();
1162 SoAFloatPrecision *const __restrict fzptr = soa.template begin<Particle_T::AttributeNames::forceZ>();
1163
1164 SoAFloatPrecision *const __restrict txptr = soa.template begin<Particle_T::AttributeNames::torqueX>();
1165 SoAFloatPrecision *const __restrict typtr = soa.template begin<Particle_T::AttributeNames::torqueY>();
1166 SoAFloatPrecision *const __restrict tzptr = soa.template begin<Particle_T::AttributeNames::torqueZ>();
1167
1168 [[maybe_unused]] auto *const __restrict typeptr = soa.template begin<Particle_T::AttributeNames::typeId>();
1169
1170 SoAFloatPrecision potentialEnergySum = 0.;
1171 SoAFloatPrecision virialSumX = 0.;
1172 SoAFloatPrecision virialSumY = 0.;
1173 SoAFloatPrecision virialSumZ = 0.;
1174
1175 // the local redeclaration of the following values helps the SoAFloatPrecision-generation of various compilers.
1176 const SoAFloatPrecision cutoffSquared = _cutoffSquared;
1177 const auto const_unrotatedSitePositions = _sitePositionsLJ;
1178
1179 std::vector<SoAFloatPrecision, autopas::AlignedAllocator<SoAFloatPrecision>> sigmaSquareds;
1180 std::vector<SoAFloatPrecision, autopas::AlignedAllocator<SoAFloatPrecision>> epsilon24s;
1181 std::vector<SoAFloatPrecision, autopas::AlignedAllocator<SoAFloatPrecision>> shift6s;
1182
1183 const auto const_sigmaSquared = _sigmaSquared;
1184 const auto const_epsilon24 = _epsilon24;
1185 const auto const_shift6 = _shift6;
1186
1187 const size_t neighborListSize = neighborList.size();
1188 const size_t *const __restrict neighborListPtr = neighborList.data();
1189
1190 // Count sites
1191 const size_t siteCountMolPrime =
1192 useMixing ? _PPLibrary->getNumSites(typeptr[indexPrime]) : const_unrotatedSitePositions.size();
1193
1194 size_t siteCountNeighbors = 0; // site count of neighbours of primary molecule
1195 if constexpr (useMixing) {
1196 for (size_t neighborMol = 0; neighborMol < neighborListSize; ++neighborMol) {
1197 siteCountNeighbors += _PPLibrary->getNumSites(typeptr[neighborList[neighborMol]]);
1198 }
1199 } else {
1200 siteCountNeighbors = const_unrotatedSitePositions.size() * neighborListSize;
1201 }
1202
1203 // initialize site-wise arrays for neighbors
1204 std::vector<SoAFloatPrecision, autopas::AlignedAllocator<SoAFloatPrecision>> exactNeighborSitePositionX;
1205 std::vector<SoAFloatPrecision, autopas::AlignedAllocator<SoAFloatPrecision>> exactNeighborSitePositionY;
1206 std::vector<SoAFloatPrecision, autopas::AlignedAllocator<SoAFloatPrecision>> exactNeighborSitePositionZ;
1207
1208 std::vector<size_t, autopas::AlignedAllocator<size_t>> siteTypesNeighbors;
1209 std::vector<char, autopas::AlignedAllocator<char>> isNeighborSiteOwnedArr;
1210
1211 // we require arrays for forces for sites to maintain SIMD in site-site calculations
1212 std::vector<SoAFloatPrecision, autopas::AlignedAllocator<SoAFloatPrecision>> siteForceX;
1213 std::vector<SoAFloatPrecision, autopas::AlignedAllocator<SoAFloatPrecision>> siteForceY;
1214 std::vector<SoAFloatPrecision, autopas::AlignedAllocator<SoAFloatPrecision>> siteForceZ;
1215
1216 // pre-reserve arrays
1217 exactNeighborSitePositionX.reserve(siteCountNeighbors);
1218 exactNeighborSitePositionY.reserve(siteCountNeighbors);
1219 exactNeighborSitePositionZ.reserve(siteCountNeighbors);
1220
1221 if constexpr (useMixing) {
1222 siteTypesNeighbors.reserve(siteCountNeighbors);
1223 }
1224
1225 siteForceX.reserve(siteCountNeighbors);
1226 siteForceY.reserve(siteCountNeighbors);
1227 siteForceZ.reserve(siteCountNeighbors);
1228
1229 if constexpr (calculateGlobals) {
1230 isNeighborSiteOwnedArr.reserve(siteCountNeighbors);
1231 }
1232
1233 if constexpr (useMixing) {
1234 sigmaSquareds.reserve(siteCountNeighbors);
1235 epsilon24s.reserve(siteCountNeighbors);
1236 if constexpr (applyShift) {
1237 shift6s.reserve(siteCountNeighbors);
1238 }
1239 }
1240
1241 const auto rotatedSitePositionsPrime =
1243 {q0ptr[indexPrime], q1ptr[indexPrime], q2ptr[indexPrime], q3ptr[indexPrime]},
1244 _PPLibrary->getSitePositions(typeptr[indexPrime]))
1245 : autopas::utils::quaternion::rotateVectorOfPositions(
1246 {q0ptr[indexPrime], q1ptr[indexPrime], q2ptr[indexPrime], q3ptr[indexPrime]},
1247 const_unrotatedSitePositions);
1248
1249 const auto siteTypesPrime = _PPLibrary->getSiteTypes(typeptr[indexPrime]); // this is not used if non-mixing
1250
1251 // generate site-wise arrays for neighbors of primary mol
1252 if constexpr (useMixing) {
1253 size_t siteIndex = 0;
1254 for (size_t neighborMol = 0; neighborMol < neighborListSize; ++neighborMol) {
1255 const auto neighborMolIndex = neighborList[neighborMol];
1256 const auto rotatedSitePositions = autopas::utils::quaternion::rotateVectorOfPositions(
1257 {q0ptr[neighborMolIndex], q1ptr[neighborMolIndex], q2ptr[neighborMolIndex], q3ptr[neighborMolIndex]},
1258 _PPLibrary->getSitePositions(typeptr[neighborMolIndex]));
1259 const auto siteTypesOfMol = _PPLibrary->getSiteTypes(typeptr[neighborMolIndex]);
1260
1261 for (size_t site = 0; site < _PPLibrary->getNumSites(typeptr[neighborMolIndex]); ++site) {
1262 exactNeighborSitePositionX[siteIndex] = rotatedSitePositions[site][0] + xptr[neighborMolIndex];
1263 exactNeighborSitePositionY[siteIndex] = rotatedSitePositions[site][1] + yptr[neighborMolIndex];
1264 exactNeighborSitePositionZ[siteIndex] = rotatedSitePositions[site][2] + zptr[neighborMolIndex];
1265 siteTypesNeighbors[siteIndex] = siteTypesOfMol[site];
1266 siteForceX[siteIndex] = 0.;
1267 siteForceY[siteIndex] = 0.;
1268 siteForceZ[siteIndex] = 0.;
1269 if (calculateGlobals) {
1270 isNeighborSiteOwnedArr[siteIndex] = ownedStatePtr[neighborMolIndex] == autopas::OwnershipState::owned;
1271 }
1272 ++siteIndex;
1273 }
1274 }
1275 } else {
1276 size_t siteIndex = 0;
1277 for (size_t neighborMol = 0; neighborMol < neighborListSize; ++neighborMol) {
1278 const auto neighborMolIndex = neighborList[neighborMol];
1279 const auto rotatedSitePositions = autopas::utils::quaternion::rotateVectorOfPositions(
1280 {q0ptr[neighborMolIndex], q1ptr[neighborMolIndex], q2ptr[neighborMolIndex], q3ptr[neighborMolIndex]},
1281 const_unrotatedSitePositions);
1282 for (size_t site = 0; site < const_unrotatedSitePositions.size(); ++site) {
1283 exactNeighborSitePositionX[siteIndex] = rotatedSitePositions[site][0] + xptr[neighborMolIndex];
1284 exactNeighborSitePositionY[siteIndex] = rotatedSitePositions[site][1] + yptr[neighborMolIndex];
1285 exactNeighborSitePositionZ[siteIndex] = rotatedSitePositions[site][2] + zptr[neighborMolIndex];
1286 siteForceX[siteIndex] = 0.;
1287 siteForceY[siteIndex] = 0.;
1288 siteForceZ[siteIndex] = 0.;
1289 if (calculateGlobals) {
1290 isNeighborSiteOwnedArr[siteIndex] = ownedStatePtr[neighborMolIndex] == autopas::OwnershipState::owned;
1291 }
1292 ++siteIndex;
1293 }
1294 }
1295 }
1296
1297 // -- main force calculation --
1298
1299 // - calculate mol mask -
1300 std::vector<char, autopas::AlignedAllocator<char>> molMask;
1301 molMask.reserve(neighborListSize);
1302
1303#pragma omp simd
1304 for (size_t neighborMol = 0; neighborMol < neighborListSize; ++neighborMol) {
1305 const auto neighborMolIndex = neighborList[neighborMol]; // index of neighbor mol in soa
1306
1307 const auto ownedState = ownedStatePtr[neighborMolIndex];
1308
1309 const auto displacementCoMX = xptr[indexPrime] - xptr[neighborMolIndex];
1310 const auto displacementCoMY = yptr[indexPrime] - yptr[neighborMolIndex];
1311 const auto displacementCoMZ = zptr[indexPrime] - zptr[neighborMolIndex];
1312
1313 const auto distanceSquaredCoMX = displacementCoMX * displacementCoMX;
1314 const auto distanceSquaredCoMY = displacementCoMY * displacementCoMY;
1315 const auto distanceSquaredCoMZ = displacementCoMZ * displacementCoMZ;
1316
1317 const auto distanceSquaredCoM = distanceSquaredCoMX + distanceSquaredCoMY + distanceSquaredCoMZ;
1318
1319 // mask molecules beyond cutoff or if molecule is a dummy
1320 molMask[neighborMol] = distanceSquaredCoM <= cutoffSquared and ownedState != autopas::OwnershipState::dummy;
1321 }
1322
1323 // generate mask for each site from molecular mask
1324 std::vector<char, autopas::AlignedAllocator<char>> siteMask;
1325 siteMask.reserve(siteCountNeighbors);
1326
1327 for (size_t neighborMol = 0; neighborMol < neighborListSize; ++neighborMol) {
1328 const auto neighborMolIndex = neighborList[neighborMol]; // index of neighbor mol in soa
1329 for (size_t siteB = 0; siteB < _PPLibrary->getNumSites(typeptr[neighborMolIndex]); ++siteB) {
1330 siteMask.emplace_back(molMask[neighborMol]);
1331 }
1332 }
1333
1334 // sums used for prime mol
1335 SoAFloatPrecision forceSumX = 0.;
1336 SoAFloatPrecision forceSumY = 0.;
1337 SoAFloatPrecision forceSumZ = 0.;
1338 SoAFloatPrecision torqueSumX = 0.;
1339 SoAFloatPrecision torqueSumY = 0.;
1340 SoAFloatPrecision torqueSumZ = 0.;
1341
1342 // - actual LJ calculation -
1343
1344 for (size_t primeSite = 0; primeSite < siteCountMolPrime; ++primeSite) {
1345 const auto rotatedPrimeSitePositionX = rotatedSitePositionsPrime[primeSite][0];
1346 const auto rotatedPrimeSitePositionY = rotatedSitePositionsPrime[primeSite][1];
1347 const auto rotatedPrimeSitePositionZ = rotatedSitePositionsPrime[primeSite][2];
1348
1349 const auto exactPrimeSitePositionX = rotatedPrimeSitePositionX + xptr[indexPrime];
1350 const auto exactPrimeSitePositionY = rotatedPrimeSitePositionY + yptr[indexPrime];
1351 const auto exactPrimeSitePositionZ = rotatedPrimeSitePositionZ + zptr[indexPrime];
1352
1353 // generate parameter data for chosen site
1354 if constexpr (useMixing) {
1355 const auto primeSiteType = siteTypesPrime[primeSite];
1356
1357 size_t siteIndex = 0;
1358 for (size_t neighborMol = 0; neighborMol < neighborListSize; ++neighborMol) {
1359 const auto neighborMolIndex = neighborList[neighborMol];
1360 const auto siteTypesOfNeighborMol = _PPLibrary->getSiteTypes(typeptr[neighborMolIndex]);
1361
1362 for (size_t site = 0; site < _PPLibrary->getNumSites(typeptr[neighborMolIndex]); ++site) {
1363 const auto mixingData = _PPLibrary->getLJMixingData(primeSiteType, siteTypesOfNeighborMol[site]);
1364 sigmaSquareds[siteIndex] = mixingData.sigmaSquared;
1365 epsilon24s[siteIndex] = mixingData.epsilon24;
1366 if constexpr (applyShift) {
1367 shift6s[siteIndex] = mixingData.shift6;
1368 }
1369 ++siteIndex;
1370 }
1371 }
1372 }
1373
1374#pragma omp simd reduction(+ : forceSumX, forceSumY, forceSumZ, torqueSumX, torqueSumY, torqueSumZ)
1375 for (size_t neighborSite = 0; neighborSite < siteCountNeighbors; ++neighborSite) {
1376 const SoAFloatPrecision sigmaSquared = useMixing ? sigmaSquareds[neighborSite] : const_sigmaSquared;
1377 const SoAFloatPrecision epsilon24 = useMixing ? epsilon24s[neighborSite] : const_epsilon24;
1378 const SoAFloatPrecision shift6 = applyShift ? (useMixing ? shift6s[neighborSite] : const_shift6) : 0;
1379
1380 const bool isNeighborSiteOwned = !calculateGlobals || isNeighborSiteOwnedArr[neighborSite];
1381
1382 const auto displacementX = exactPrimeSitePositionX - exactNeighborSitePositionX[neighborSite];
1383 const auto displacementY = exactPrimeSitePositionY - exactNeighborSitePositionY[neighborSite];
1384 const auto displacementZ = exactPrimeSitePositionZ - exactNeighborSitePositionZ[neighborSite];
1385
1386 const auto distanceSquaredX = displacementX * displacementX;
1387 const auto distanceSquaredY = displacementY * displacementY;
1388 const auto distanceSquaredZ = displacementZ * displacementZ;
1389
1390 const auto distanceSquared = distanceSquaredX + distanceSquaredY + distanceSquaredZ;
1391
1392 const auto invDistSquared = 1. / distanceSquared;
1393 const auto lj2 = sigmaSquared * invDistSquared;
1394 const auto lj6 = lj2 * lj2 * lj2;
1395 const auto lj12 = lj6 * lj6;
1396 const auto lj12m6 = lj12 - lj6;
1397 const auto scalarMultiple = siteMask[neighborSite] ? epsilon24 * (lj12 + lj12m6) * invDistSquared : 0.;
1398
1399 // calculate forces
1400 const auto forceX = scalarMultiple * displacementX;
1401 const auto forceY = scalarMultiple * displacementY;
1402 const auto forceZ = scalarMultiple * displacementZ;
1403
1404 forceSumX += forceX;
1405 forceSumY += forceY;
1406 forceSumZ += forceZ;
1407
1408 torqueSumX += rotatedPrimeSitePositionY * forceZ - rotatedPrimeSitePositionZ * forceY;
1409 torqueSumY += rotatedPrimeSitePositionZ * forceX - rotatedPrimeSitePositionX * forceZ;
1410 torqueSumZ += rotatedPrimeSitePositionX * forceY - rotatedPrimeSitePositionY * forceX;
1411
1412 // N3L
1413 if (newton3) {
1414 siteForceX[neighborSite] -= forceX;
1415 siteForceY[neighborSite] -= forceY;
1416 siteForceZ[neighborSite] -= forceZ;
1417 }
1418
1419 // calculate globals
1420 if constexpr (calculateGlobals) {
1421 const auto potentialEnergy6 = siteMask[neighborSite] ? (epsilon24 * lj12m6 + shift6) : 0.;
1422 const auto virialX = displacementX * forceX;
1423 const auto virialY = displacementY * forceY;
1424 const auto virialZ = displacementZ * forceZ;
1425
1426 // We add 6 times the potential energy for each owned particle. The total sum is corrected in endTraversal().
1427 const auto ownershipFactor =
1428 newton3 ? (ownedStatePrime == autopas::OwnershipState::owned ? 1. : 0.) + (isNeighborSiteOwned ? 1. : 0.)
1429 : (ownedStatePrime == autopas::OwnershipState::owned ? 1. : 0.);
1430 potentialEnergySum += potentialEnergy6 * ownershipFactor;
1431 virialSumX += virialX * ownershipFactor;
1432 virialSumY += virialY * ownershipFactor;
1433 virialSumZ += virialZ * ownershipFactor;
1434 }
1435 }
1436 }
1437 // Add forces to prime mol
1438 fxptr[indexPrime] += forceSumX;
1439 fyptr[indexPrime] += forceSumY;
1440 fzptr[indexPrime] += forceSumZ;
1441 txptr[indexPrime] += torqueSumX;
1442 typtr[indexPrime] += torqueSumY;
1443 tzptr[indexPrime] += torqueSumZ;
1444
1445 // Reduce forces on individual neighbor sites to molecular forces & torques if newton3=true
1446 if constexpr (newton3) {
1447 if constexpr (useMixing) {
1448 size_t siteIndex = 0;
1449 for (size_t neighborMol = 0; neighborMol < neighborListSize; ++neighborMol) {
1450 const auto neighborMolIndex = neighborList[neighborMol];
1451 const auto rotatedSitePositions = autopas::utils::quaternion::rotateVectorOfPositions(
1452 {q0ptr[neighborMolIndex], q1ptr[neighborMolIndex], q2ptr[neighborMolIndex], q3ptr[neighborMolIndex]},
1453 _PPLibrary->getSitePositions(typeptr[neighborMolIndex]));
1454 for (size_t site = 0; site < _PPLibrary->getNumSites(typeptr[neighborMolIndex]); ++site) {
1455 fxptr[neighborMolIndex] += siteForceX[siteIndex];
1456 fyptr[neighborMolIndex] += siteForceY[siteIndex];
1457 fzptr[neighborMolIndex] += siteForceZ[siteIndex];
1458 txptr[neighborMolIndex] += rotatedSitePositions[site][1] * siteForceZ[siteIndex] -
1459 rotatedSitePositions[site][2] * siteForceY[siteIndex];
1460 typtr[neighborMolIndex] += rotatedSitePositions[site][2] * siteForceX[siteIndex] -
1461 rotatedSitePositions[site][0] * siteForceZ[siteIndex];
1462 tzptr[neighborMolIndex] += rotatedSitePositions[site][0] * siteForceY[siteIndex] -
1463 rotatedSitePositions[site][1] * siteForceX[siteIndex];
1464 ++siteIndex;
1465 }
1466 }
1467 } else {
1468 size_t siteIndex = 0;
1469 for (size_t neighborMol = 0; neighborMol < neighborListSize; ++neighborMol) {
1470 const auto neighborMolIndex = neighborList[neighborMol];
1471 const auto rotatedSitePositions = autopas::utils::quaternion::rotateVectorOfPositions(
1472 {q0ptr[neighborMolIndex], q1ptr[neighborMolIndex], q2ptr[neighborMolIndex], q3ptr[neighborMolIndex]},
1473 const_unrotatedSitePositions);
1474 for (size_t site = 0; site < const_unrotatedSitePositions.size(); ++site) {
1475 fxptr[neighborMolIndex] += siteForceX[siteIndex];
1476 fyptr[neighborMolIndex] += siteForceY[siteIndex];
1477 fzptr[neighborMolIndex] += siteForceZ[siteIndex];
1478 txptr[neighborMolIndex] += rotatedSitePositions[site][1] * siteForceZ[siteIndex] -
1479 rotatedSitePositions[site][2] * siteForceY[siteIndex];
1480 typtr[neighborMolIndex] += rotatedSitePositions[site][2] * siteForceX[siteIndex] -
1481 rotatedSitePositions[site][0] * siteForceZ[siteIndex];
1482 txptr[neighborMolIndex] += rotatedSitePositions[site][0] * siteForceY[siteIndex] -
1483 rotatedSitePositions[site][1] * siteForceX[siteIndex];
1484 ++siteIndex;
1485 }
1486 }
1487 }
1488 }
1489
1490 if constexpr (calculateGlobals) {
1491 const auto threadNum = autopas::autopas_get_thread_num();
1492
1493 _aosThreadData[threadNum].potentialEnergySum += potentialEnergySum;
1494 _aosThreadData[threadNum].virialSum[0] += virialSumX;
1495 _aosThreadData[threadNum].virialSum[1] += virialSumY;
1496 _aosThreadData[threadNum].virialSum[2] += virialSumZ;
1497 }
1498 }
1499
1503 class AoSThreadData {
1504 public:
1505 AoSThreadData() : virialSum{0., 0., 0.}, potentialEnergySum{0.}, __remainingTo64{} {}
1506 void setZero() {
1507 virialSum = {0., 0., 0.};
1508 potentialEnergySum = 0.;
1509 }
1510
1511 // variables
1512 std::array<double, 3> virialSum;
1513 double potentialEnergySum;
1514
1515 private:
1516 // dummy parameter to get the right size (64 bytes)
1517 double __remainingTo64[(64 - 4 * sizeof(double)) / sizeof(double)];
1518 };
1519
1520 static_assert(sizeof(AoSThreadData) % 64 == 0, "AoSThreadData has wrong size (should be multiple of 64)");
1521
1525 std::vector<AoSThreadData> _aosThreadData;
1526};
1527} // namespace mdLib
#define AutoPasLog(lvl, fmt,...)
Macro for logging providing common meta information without filename.
Definition: Logger.h:24
This class stores the (physical) properties of molecule types, and, in the case of multi-site molecul...
Definition: ParticlePropertiesLibrary.h:28
floatType getMixingShift6(intType i, intType j) const
Returns precomputed mixed shift * 6 for one pair of site types.
Definition: ParticlePropertiesLibrary.h:262
intType getNumSites(intType i) const
Get number of sites of a multi-site molecule.
Definition: ParticlePropertiesLibrary.h:553
std::vector< std::array< floatType, 3 > > getSitePositions(intType i) const
Get relative site positions to a multi-site molecule's center-of-mass.
Definition: ParticlePropertiesLibrary.h:516
floatType getMixingSigmaSquared(intType i, intType j) const
Returns precomputed mixed squared sigma for one pair of site types.
Definition: ParticlePropertiesLibrary.h:252
floatType getMixing24Epsilon(intType i, intType j) const
Returns the precomputed mixed epsilon * 24.
Definition: ParticlePropertiesLibrary.h:224
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:575
auto getLJMixingData(intType i, intType j) const
Get complete mixing data for one pair of LJ site types.
Definition: ParticlePropertiesLibrary.h:234
std::vector< intType > getSiteTypes(intType i) const
Get site types of a multi-site molecule.
Definition: ParticlePropertiesLibrary.h:527
AlignedAllocator class.
Definition: AlignedAllocator.h:29
PairwiseFunctor class.
Definition: PairwiseFunctor.h:31
PairwiseFunctor(double cutoff)
Constructor.
Definition: PairwiseFunctor.h:42
View on a fixed part of a SoA between a start index and an end index.
Definition: SoAView.h:23
size_t size() const
Returns the number of particles in the view.
Definition: SoAView.h:83
Default exception class for autopas exceptions.
Definition: ExceptionHandler.h:115
A functor to handle Lennard-Jones interactions between two Multisite Molecules.
Definition: LJMultisiteFunctor.h:47
void SoAFunctorSingle(autopas::SoAView< SoAArraysType > soa, bool newton3) final
PairwiseFunctor for structure of arrays (SoA)
Definition: LJMultisiteFunctor.h:279
void AoSFunctor(Particle_T &particleA, Particle_T &particleB, bool newton3) final
Functor for arrays of structures (AoS).
Definition: LJMultisiteFunctor.h:179
LJMultisiteFunctor()=delete
Delete Default constructor.
bool isRelevantForTuning() final
Specifies whether the functor should be considered for the auto-tuning process.
Definition: LJMultisiteFunctor.h:162
LJMultisiteFunctor(double cutoff, ParticlePropertiesLibrary< double, size_t > &particlePropertiesLibrary)
Constructor for Functor with particle mixing enabled.
Definition: LJMultisiteFunctor.h:152
LJMultisiteFunctor(double cutoff)
Constructor for Functor with particle mixing disabled.
Definition: LJMultisiteFunctor.h:138
void initTraversal() final
Reset the global values.
Definition: LJMultisiteFunctor.h:710
static constexpr bool getMixing()
Definition: LJMultisiteFunctor.h:681
static constexpr auto getComputedAttr()
Get attributes computed by this functor.
Definition: LJMultisiteFunctor.h:672
void setParticleProperties(SoAFloatPrecision epsilon24, SoAFloatPrecision sigmaSquared, std::vector< std::array< SoAFloatPrecision, 3 > > sitePositionsLJ)
Sets the molecule properties constants for this functor.
Definition: LJMultisiteFunctor.h:627
bool allowsNewton3() final
Specifies whether the functor is capable of Newton3-like functors.
Definition: LJMultisiteFunctor.h:164
bool allowsNonNewton3() final
Specifies whether the functor is capable of non-Newton3-like functors.
Definition: LJMultisiteFunctor.h:168
double getPotentialEnergy()
Get the potential energy.
Definition: LJMultisiteFunctor.h:755
std::string getName() final
Returns name of functor.
Definition: LJMultisiteFunctor.h:160
unsigned long getNumFlopsPerKernelCall(size_t molAType, size_t molBType, bool newton3)
Get the number of flops used per kernel call - i.e.
Definition: LJMultisiteFunctor.h:693
void SoAFunctorPair(autopas::SoAView< SoAArraysType > soa1, autopas::SoAView< SoAArraysType > soa2, const bool newton3) final
PairwiseFunctor for structure of arrays (SoA)
Definition: LJMultisiteFunctor.h:594
static constexpr auto getNeededAttr(std::false_type)
Get attributes needed for computation without N3 optimization.
Definition: LJMultisiteFunctor.h:657
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: LJMultisiteFunctor.h:608
double getVirial()
Get the virial.
Definition: LJMultisiteFunctor.h:773
void endTraversal(bool newton3) final
Postprocesses global values, e.g.
Definition: LJMultisiteFunctor.h:723
static constexpr auto getNeededAttr()
Get attributes needed for computation.
Definition: LJMultisiteFunctor.h:642
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
constexpr std::array< T, SIZE > mulScalar(const std::array< T, SIZE > &a, T s)
Multiplies a scalar s to each element of array a and returns the result.
Definition: ArrayMath.h:181
constexpr std::array< T, SIZE > sub(const std::array< T, SIZE > &a, const std::array< T, SIZE > &b)
Subtracts array b from array a and returns the result.
Definition: ArrayMath.h:45
constexpr std::array< T, SIZE > add(const std::array< T, SIZE > &a, const std::array< T, SIZE > &b)
Adds two arrays, returns the result.
Definition: ArrayMath.h:28
constexpr std::array< T, 3 > cross(const std::array< T, 3 > &a, const std::array< T, 3 > &b)
Generates the cross product of two arrays of 3 floats.
Definition: ArrayMath.h:249
std::vector< std::array< double, 3 > > rotateVectorOfPositions(const std::array< double, 4 > &q, const std::vector< std::array< double, 3 > > &positionVector)
Rotates a std::vector of 3D positions.
Definition: Quaternion.cpp:13
This is the main namespace of AutoPas.
Definition: AutoPasDecl.h:32
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:19
@ 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:22
int autopas_get_thread_num()
Dummy for omp_set_lock() when no OpenMP is available.
Definition: WrapOpenMP.h:132