AutoPas  3.0.0
Loading...
Searching...
No Matches
ATPotential.h
Go to the documentation of this file.
1
9#pragma once
10#include <tuple>
11
14
25constexpr double calculateATPotential(const std::array<double, 3> &posI, const std::array<double, 3> &posJ,
26 const std::array<double, 3> &posK, double cutoff, double nu) {
27 using namespace autopas::utils::ArrayMath::literals;
28
29 // the distance vectors
30 const auto posIToPosJ = posI - posJ;
31 const auto posIToPosK = posI - posK;
32 const auto posJToPosK = posJ - posK;
33
34 // distances between particles
35 const auto distIJ =
36 autopas::utils::ConstexprMath::sqrt(autopas::utils::ArrayMath::dot(posIToPosJ, posIToPosJ), 1e-16);
37 const auto distIK =
38 autopas::utils::ConstexprMath::sqrt(autopas::utils::ArrayMath::dot(posIToPosK, posIToPosK), 1e-16);
39 const auto distJK =
40 autopas::utils::ConstexprMath::sqrt(autopas::utils::ArrayMath::dot(posJToPosK, posJToPosK), 1e-16);
41
42 // if the distance between the two particles is larger than cutoff, we don't
43 // consider this interaction
44 if (distIJ > cutoff or distIK > cutoff or distJK > cutoff) {
45 return 0;
46 }
47
48 // calculate the cosines between the particles
49 // cos_i = (r_ki * r_ji) / (|r_ki| |r_ji|)
50
51 const auto cosI = autopas::utils::ArrayMath::dot(posIToPosK, posIToPosJ) / (distIK * distIJ);
52 const auto cosJ = -autopas::utils::ArrayMath::dot(posJToPosK, posIToPosJ) / (distJK * distIJ);
53 const auto cosK = autopas::utils::ArrayMath::dot(posIToPosK, posJToPosK) / (distIK * distJK);
54
55 const auto rrr = distIJ * distJK * distIK;
56 const auto rrr3 = rrr * rrr * rrr;
57
58 // the axilrod teller potential
59 const auto potentialEnergy = nu * (3 * cosI * cosJ * cosK + 1.) / rrr3;
60
61 return potentialEnergy;
62}
63
73constexpr std::array<std::array<double, 3>, 3> calculateATForce(const std::array<double, 3> &posI,
74 const std::array<double, 3> &posJ,
75 const std::array<double, 3> &posK, double cutoff,
76 double nu) {
77 using namespace autopas::utils::ArrayMath::literals;
78
79 // the distance vectors
80 const auto posJToPosI = posJ - posI;
81 const auto posIToPosK = posI - posK;
82 const auto posKToPosJ = posK - posJ;
83
84 // distances between particles
85 const auto distJISquared = autopas::utils::ArrayMath::dot(posJToPosI, posJToPosI);
86 const auto distJI = autopas::utils::ConstexprMath::sqrt(distJISquared, 1e-16);
87 const auto distIKSquared = autopas::utils::ArrayMath::dot(posIToPosK, posIToPosK);
88 const auto distIK = autopas::utils::ConstexprMath::sqrt(distIKSquared, 1e-16);
89 const auto distKJSquared = autopas::utils::ArrayMath::dot(posKToPosJ, posKToPosJ);
90 const auto distKJ = autopas::utils::ConstexprMath::sqrt(distKJSquared, 1e-16);
91
92 // if the distance between the two particles is larger than cutoff, we don't
93 // consider this interaction
94 if (distJI > cutoff or distIK > cutoff or distKJ > cutoff) {
95 return {std::array<double, 3>{0., 0., 0.}, std::array<double, 3>{0., 0., 0.}, std::array<double, 3>{0., 0., 0.}};
96 }
97
98 // Dot products that are the numerators of the cosine formula
99 const double cosI = autopas::utils::ArrayMath::dot(posJToPosI, posIToPosK);
100 const double cosJ = autopas::utils::ArrayMath::dot(posKToPosJ, posJToPosI);
101 const double cosK = autopas::utils::ArrayMath::dot(posIToPosK, posKToPosJ);
102
103 const double cos6 = cosI * cosJ * cosK;
104 const double distSquaredAll = distJI * distJI * distIK * distIK * distKJ * distKJ;
105 const double dist5All = distSquaredAll * distSquaredAll * std::sqrt(distSquaredAll);
106
107 auto forceI = std::array<double, 3>{0., 0., 0.};
108 auto forceJ = std::array<double, 3>{0., 0., 0.};
109 auto forceK = std::array<double, 3>{0., 0., 0.};
110
111 // loop over all dimensions
112 for (size_t i = 0; i < 3; i++) {
113 forceI[i] = posIToPosK[i] * cosI * (cosJ - cosK) +
114 posJToPosI[i] * (cosJ * cosK - distKJSquared * distIKSquared + 5.0 * cos6 / distJISquared) +
115 posIToPosK[i] * (-cosJ * cosK + distJISquared * distKJSquared - 5.0 * cos6 / distIKSquared);
116
117 forceJ[i] = posIToPosK[i] * cosJ * (cosK - cosI) +
118 posKToPosJ[i] * (cosI * cosK - distJISquared * distIKSquared + 5.0 * cos6 / distKJSquared) +
119 posJToPosI[i] * (-cosI * cosK + distKJSquared * distIKSquared - 5.0 * cos6 / distJISquared);
120
121 forceK[i] = posJToPosI[i] * cosK * (cosI - cosJ) +
122 posIToPosK[i] * (cosI * cosJ - distJISquared * distKJSquared + 5.0 * cos6 / distIKSquared) +
123 posKToPosJ[i] * (-cosI * cosJ + distJISquared * distIKSquared - 5.0 * cos6 / distKJSquared);
124 }
125 forceI *= 3.0 * nu / dist5All;
126 forceJ *= 3.0 * nu / dist5All;
127 forceK *= 3.0 * nu / dist5All;
128
129 return {forceI, forceJ, forceK};
130}
131
141constexpr std::array<std::array<double, 3>, 3> calculateATVirials(const std::array<double, 3> &posI,
142 const std::array<double, 3> &posJ,
143 const std::array<double, 3> &posK, double cutoff,
144 double nu) {
145 using namespace autopas::utils::ArrayMath::literals;
146
147 // first we need the forces
148 const auto forces = calculateATForce(posI, posJ, posK, cutoff, nu);
149 const auto forceI = forces[0];
150 const auto forceJ = forces[1];
151 const auto forceK = forces[2];
152
153 const auto virialI = forceI * posI;
154 const auto virialJ = forceJ * posJ;
155 const auto virialK = forceK * posK;
156
157 return {virialI, virialJ, virialK};
158}
159
169constexpr double calculateATVirialTotal(const std::array<double, 3> &posI, const std::array<double, 3> &posJ,
170 const std::array<double, 3> &posK, double cutoff, double nu) {
171 using namespace autopas::utils::ArrayMath::literals;
172 const auto [virialI, virialJ, virialK] = calculateATVirials(posI, posJ, posK, cutoff, nu);
173 const auto virialSum = virialI + virialJ + virialK;
174 return virialSum[0] + virialSum[1] + virialSum[2];
175}
176
187constexpr std::array<double, 3> calculateATVirialTotalPerParticle(const std::array<double, 3> &posI,
188 const std::array<double, 3> &posJ,
189 const std::array<double, 3> &posK, double cutoff,
190 double nu) {
191 using namespace autopas::utils::ArrayMath::literals;
192 const auto [virialI, virialJ, virialK] = calculateATVirials(posI, posJ, posK, cutoff, nu);
193 const auto virialSumI = virialI[0] + virialI[1] + virialI[2];
194 const auto virialSumJ = virialJ[0] + virialJ[1] + virialJ[2];
195 const auto virialSumK = virialK[0] + virialK[1] + virialK[2];
196 return {virialSumI, virialSumJ, virialSumK};
197}
constexpr std::array< std::array< double, 3 >, 3 > calculateATVirials(const std::array< double, 3 > &posI, const std::array< double, 3 > &posJ, const std::array< double, 3 > &posK, double cutoff, double nu)
Calculates the virial between three particles i,j,k from the Axilrod-Teller potential.
Definition: ATPotential.h:141
constexpr std::array< double, 3 > calculateATVirialTotalPerParticle(const std::array< double, 3 > &posI, const std::array< double, 3 > &posJ, const std::array< double, 3 > &posK, double cutoff, double nu)
Returns the sum of all components of the virial for each particle i, j, k individually using the Axil...
Definition: ATPotential.h:187
constexpr double calculateATVirialTotal(const std::array< double, 3 > &posI, const std::array< double, 3 > &posJ, const std::array< double, 3 > &posK, double cutoff, double nu)
Calculates the sum of all components of the virial between particle i, j, k using the Axilrod-Teller ...
Definition: ATPotential.h:169
constexpr double calculateATPotential(const std::array< double, 3 > &posI, const std::array< double, 3 > &posJ, const std::array< double, 3 > &posK, double cutoff, double nu)
Calculates the potential energy between particles i, j and k using the Axilrod Teller potential.
Definition: ATPotential.h:25
constexpr std::array< std::array< double, 3 >, 3 > calculateATForce(const std::array< double, 3 > &posI, const std::array< double, 3 > &posJ, const std::array< double, 3 > &posK, double cutoff, double nu)
Calculates the forces exerted on three particles using the Axilrod-Teller potential.
Definition: ATPotential.h:73
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