30constexpr double kRSqrtPi = 0.5641895835477563;
35 const double rr1 = 1.0 / r;
36 const double rr2 = rr1 * rr1;
38 const double a3 = a1 * a1 * a1;
39 const double expTerm = kRSqrtPi * std::exp(-a1 * a1 * r * r);
42 b.
B0 = std::erfc(a1 * r) * rr1;
43 b.
B1 = rr2 * (b.
B0 + 2.0 * a1 * expTerm);
44 b.
B2 = rr2 * (3.0 * b.
B1 + 4.0 * a3 * expTerm);
51 const double rr1 = 1.0 / r;
52 const double rr3 = rr1 * rr1 * rr1;
54 b.
B0 = rr1 - erfc_b.
B0;
55 b.
B1 = rr3 - erfc_b.
B1;
56 b.
B2 = 3.0 * rr3 * rr1 * rr1 - erfc_b.
B2;
61 double q,
const Eigen::Vector3d& mu,
const Eigen::Vector3d& r_vec)
const {
63 return q * b.
B0 + mu.dot(r_vec) * b.
B1;
67 double q,
const Eigen::Vector3d& mu,
const Eigen::Vector3d& r_vec)
const {
68 const double r = r_vec.norm();
74 return q * b.
B0 + mu.dot(r_vec) * b.
B1;
87 const double expUa = std::exp(-au3);
89 t.
l5 = 1.0 - (1.0 + au3) * expUa;
101struct ScreenedPotentialField {
103 Eigen::Vector3d field;
106ScreenedPotentialField EvaluateSource(
107 double q,
const Eigen::Vector3d& mu,
const Eigen::Vector3d& r_vec,
double r,
108 const EwaldRealSpaceInteractor::BFunctions& b) {
109 ScreenedPotentialField result;
110 const double mu_dot_r = mu.dot(r_vec);
113 result.phi = q * b.B0 + mu_dot_r * b.B1;
121 result.field = q * b.B1 * r_vec + mu_dot_r * b.B2 * r_vec - b.B1 * mu;
128template <
class T, enum Estatic CE>
131 const Eigen::Vector3d& source_shift)
const {
132 const Eigen::Vector3d r_vec =
133 site2.
getPos() - (site1.getPos() + source_shift);
134 const double r = r_vec.norm();
137 const double q1 = site1.getCharge();
138 const Eigen::Vector3d mu1 = site1.getStaticDipole();
139 const ScreenedPotentialField src = EvaluateSource(q1, mu1, r_vec, r, b);
142 site2.
V_noE() += src.field;
144 site2.
V() += src.field;
150 return q2 * src.phi - mu2.dot(src.field);
153template <
class T, enum Estatic CE>
156 const Eigen::Vector3d& source_shift)
const {
157 const Eigen::Vector3d r_vec =
158 site2.
getPos() - (site1.getPos() + source_shift);
159 const double r = r_vec.norm();
183 const Eigen::Vector3d self_field = -self_coeff * site1.getStaticDipole();
185 site2.
V_noE() -= self_field;
187 site2.
V() -= self_field;
193 const double q1 = site1.getCharge();
194 const Eigen::Vector3d mu1 = site1.getStaticDipole();
195 const ScreenedPotentialField src = EvaluateSource(q1, mu1, r_vec, r, b);
203 site2.
V_noE() -= src.field;
205 site2.
V() -= src.field;
209template <enum Estatic CE>
212 const Eigen::Vector3d& source_shift)
const {
213 const Eigen::Vector3d r_vec =
215 const double r = r_vec.norm();
245 site2.
V_noE() -= self_field;
247 site2.
V() -= self_field;
259 const ScreenedPotentialField src =
263 site2.
V_noE() -= src.field;
265 site2.
V() -= src.field;
269template <enum Estatic CE>
272 const Eigen::Vector3d& source_shift)
const {
273 const Eigen::Vector3d r_vec =
275 const double r = r_vec.norm();
281 const double mu_dot_r = mu1.dot(r_vec);
298 const double c3 = t.
l3 * b.
B1 + (t.
l3 - 1.0) * berf.
B1;
299 const double c5 = t.
l5 * b.
B2 + (t.
l5 - 1.0) * berf.
B2;
300 const Eigen::Vector3d field = mu_dot_r * c5 * r_vec - c3 * mu1;
303 site2.
V_noE() += field;
309 return -mu2.dot(field);
312template <
class S1,
class S2>
314 const S1& site1,
const S2& site2,
315 const Eigen::Vector3d& source_shift)
const {
316 const Eigen::Vector3d r_vec =
317 site2.getPos() - (site1.getPos() + source_shift);
318 const double r = r_vec.norm();
321 const double q1 = site1.getCharge();
322 const Eigen::Vector3d mu1 = site1.getStaticDipole();
323 const ScreenedPotentialField src = EvaluateSource(q1, mu1, r_vec, r, b);
325 const double q2 = site2.getCharge();
326 const Eigen::Vector3d mu2 = site2.getStaticDipole();
327 return q2 * src.phi - mu2.dot(src.field);
330template <
class S1,
class S2>
332 const S1& site1,
const S2& site2,
333 const Eigen::Vector3d& source_shift)
const {
334 const Eigen::Vector3d r_vec =
335 site2.getPos() - (site1.getPos() + source_shift);
336 const double r = r_vec.norm();
338 const double q1 = site1.getCharge();
339 const Eigen::Vector3d mu1 = site1.getStaticDipole();
340 const double q2 = site2.getCharge();
341 const Eigen::Vector3d mu2 = site2.getStaticDipole();
350 const double phi_self = 2.0 *
alpha_ / sqrt_pi;
361 return q2 * q1 * phi_self + dip_self * mu2.dot(mu1);
365 const ScreenedPotentialField src = EvaluateSource(q1, mu1, r_vec, r, b);
366 return q2 * src.phi - mu2.dot(src.field);
371 const Eigen::Vector3d& source_shift)
const {
375 const Eigen::Vector3d r_vec =
377 const double r = r_vec.norm();
392 return dip_self * mu2.dot(mu1);
396 const ScreenedPotentialField src = EvaluateSource(0.0, mu1, r_vec, r, b);
397 return q2 * src.phi - mu2.dot(src.field);
402 const Eigen::Vector3d r_vec = site2.
getPos() - site1.
getPos();
403 const double r = r_vec.norm();
410 const double mu1_dot_r = mu1.dot(r_vec);
418 const double c3 = t.
l3 * b.
B1 + (t.
l3 - 1.0) * berf.
B1;
419 const double c5 = t.
l5 * b.
B2 + (t.
l5 - 1.0) * berf.
B2;
420 const Eigen::Vector3d field1 = mu1_dot_r * c5 * r_vec - c3 * mu1;
421 return -mu2.dot(field1);
426 const Eigen::Vector3d& source_shift,
bool damp)
const {
431 const Eigen::Vector3d r_vec =
433 const double r = r_vec.norm();
440 const double mu_dot_r = mu1.dot(r_vec);
449 const double c3 = t.
l3 * b.
B1 + (t.
l3 - 1.0) * berf.
B1;
450 const double c5 = t.
l5 * b.
B2 + (t.
l5 - 1.0) * berf.
B2;
451 const double phi = c3 * mu_dot_r;
452 const Eigen::Vector3d field = mu_dot_r * c5 * r_vec - c3 * mu1;
458 return q2 * phi - mu2.dot(field);
477 const Eigen::Vector3d&)
const;
480 const Eigen::Vector3d&)
const;
483 const Eigen::Vector3d&)
const;
486 const Eigen::Vector3d&)
const;
BFunctions ComputeB(double r) const
double CalcInducedSourceEnergy(const PolarSite &site1, const PolarSite &site2, const Eigen::Vector3d &source_shift=Eigen::Vector3d::Zero(), bool damp=true) const
double CalcStaticEnergy(const S1 &site1, const S2 &site2, const Eigen::Vector3d &source_shift=Eigen::Vector3d::Zero()) const
BFunctions ComputeErfB(double r) const
double ErfPotential(double q, const Eigen::Vector3d &mu, const Eigen::Vector3d &r_vec) const
TholeFactors ComputeThole(double r, const PolarSite &site1, const PolarSite &site2) const
static constexpr double kCoincidenceTol
void ApplyErfInducedFieldCorrection(const PolarSite &site1, PolarSite &site2, const Eigen::Vector3d &source_shift=Eigen::Vector3d::Zero()) const
double ScreenedPotential(double q, const Eigen::Vector3d &mu, const Eigen::Vector3d &r_vec) const
double CalcInducedEnergy(const PolarSite &site1, const PolarSite &site2) const
double ApplyInducedField(const PolarSite &site1, PolarSite &site2, const Eigen::Vector3d &source_shift=Eigen::Vector3d::Zero()) const
double CalcErfInducedSourceEnergy(const PolarSite &site1, const PolarSite &site2, const Eigen::Vector3d &source_shift=Eigen::Vector3d::Zero()) const
double CalcErfStaticEnergy(const S1 &site1, const S2 &site2, const Eigen::Vector3d &source_shift=Eigen::Vector3d::Zero()) const
double ApplyStaticField(const T &site1, PolarSite &site2, const Eigen::Vector3d &source_shift=Eigen::Vector3d::Zero()) const
void ApplyErfStaticFieldCorrection(const T &site1, PolarSite &site2, const Eigen::Vector3d &source_shift=Eigen::Vector3d::Zero()) const
Class to represent Atom/Site in electrostatic+polarization.
double getSqrtInvEigenDamp() const
const Eigen::Vector3d & V_noE() const
Eigen::Vector3d getStaticDipole() const final
const Eigen::Vector3d & V() const
Eigen::Vector3d getInducedDipole() const final
Class to represent Atom/Site in electrostatic.
const Eigen::Vector3d & getPos() const
Charge transport classes.
Provides a means for comparing floating point numbers.