45#include "nonbonded/Electrostatic.hpp"
57#include "flucq/FluctuatingChargeForces.hpp"
58#include "io/Globals.hpp"
60#include "math/erfc.hpp"
61#include "nonbonded/SlaterIntegrals.hpp"
63#include "types/FixedChargeAdapter.hpp"
64#include "types/FluctuatingChargeAdapter.hpp"
65#include "types/MultipoleAdapter.hpp"
67#include "utils/Constants.hpp"
68#include "utils/simError.h"
72 Electrostatic::Electrostatic() :
73 name_(
"Electrostatic"), initialized_(false), haveCutoffRadius_(false),
74 haveDampingAlpha_(false), haveDielectric_(false),
75 haveElectroSplines_(false), info_(NULL), forceField_(NULL)
81 Electrostatic::~Electrostatic() {
delete flucQ_; }
83 void Electrostatic::setForceField(
ForceField* ff) {
85 flucQ_->setForceField(forceField_);
88 void Electrostatic::setSimulatedAtomTypes(AtomTypeSet& simtypes) {
90 flucQ_->setSimulatedAtomTypes(simTypes_);
93 void Electrostatic::initialize() {
94 Globals* simParams_ = info_->getSimParams();
96 summationMap_[
"HARD"] = esm_HARD;
97 summationMap_[
"NONE"] = esm_HARD;
98 summationMap_[
"SWITCHING_FUNCTION"] = esm_SWITCHING_FUNCTION;
99 summationMap_[
"SHIFTED_POTENTIAL"] = esm_SHIFTED_POTENTIAL;
100 summationMap_[
"SHIFTED_FORCE"] = esm_SHIFTED_FORCE;
101 summationMap_[
"TAYLOR_SHIFTED"] = esm_TAYLOR_SHIFTED;
102 summationMap_[
"REACTION_FIELD"] = esm_REACTION_FIELD;
103 summationMap_[
"EWALD_FULL"] = esm_EWALD_FULL;
106 screeningMap_[
"DAMPED"] = DAMPED;
107 screeningMap_[
"UNDAMPED"] = UNDAMPED;
112 pre11_ = 332.0637778;
129 chargeToC_ = 1.60217733e-19;
130 angstromToM_ = 1.0e-10;
131 debyeToCm_ = 3.33564095198e-30;
138 summationMethod_ = esm_HARD;
139 screeningMethod_ = UNDAMPED;
143 if (simParams_->haveElectrostaticSummationMethod()) {
144 string myMethod = simParams_->getElectrostaticSummationMethod();
146 map<string, ElectrostaticSummationMethod>::iterator i;
147 i = summationMap_.find(myMethod);
148 if (i != summationMap_.end()) {
149 summationMethod_ = (*i).second;
153 painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
154 "Electrostatic::initialize: Unknown electrostaticSummationMethod.\n"
155 "\t(Input file specified %s .)\n"
156 "\telectrostaticSummationMethod must be one of: \"hard\",\n"
157 "\t\"shifted_potential\", \"shifted_force\",\n"
158 "\t\"taylor_shifted\", or \"reaction_field\".\n",
160 painCave.isFatal = 1;
165 if (simParams_->haveCutoffMethod()) {
166 string myMethod = simParams_->getCutoffMethod();
168 map<string, ElectrostaticSummationMethod>::iterator i;
169 i = summationMap_.find(myMethod);
170 if (i != summationMap_.end()) { summationMethod_ = (*i).second; }
174 if (summationMethod_ == esm_REACTION_FIELD) {
175 if (!simParams_->haveDielectric()) {
177 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
178 "SimInfo warning: dielectric was not specified in the input "
180 "the reaction field correction method.\n"
181 "\tA default value of %f will be used for the dielectric.\n",
183 painCave.isFatal = 0;
184 painCave.severity = OPENMD_INFO;
187 dielectric_ = simParams_->getDielectric();
189 haveDielectric_ =
true;
192 if (simParams_->haveElectrostaticScreeningMethod()) {
193 string myScreen = simParams_->getElectrostaticScreeningMethod();
195 map<string, ElectrostaticScreeningMethod>::iterator i;
196 i = screeningMap_.find(myScreen);
197 if (i != screeningMap_.end()) {
198 screeningMethod_ = (*i).second;
200 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
201 "SimInfo error: Unknown electrostaticScreeningMethod.\n"
202 "\t(Input file specified %s .)\n"
203 "\telectrostaticScreeningMethod must be one of: \"undamped\"\n"
206 painCave.isFatal = 1;
212 if (!haveCutoffRadius_) {
213 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
214 "Electrostatic::initialize has no Default "
216 painCave.severity = OPENMD_ERROR;
217 painCave.isFatal = 1;
221 if (screeningMethod_ == DAMPED || summationMethod_ == esm_EWALD_FULL) {
222 if (!simParams_->haveDampingAlpha()) {
223 haveDampingAlpha_ =
false;
226 dampingAlpha_ = 0.425 - cutoffRadius_ * 0.02;
227 if (dampingAlpha_ < 0.0) {
228 screeningMethod_ = UNDAMPED;
232 painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
233 "Electrostatic::initialize: dampingAlpha was not specified in "
235 "\tinput file, but the computed value would be 0.0 with a\n"
236 "\tcutoff of %f (ang). Switching to UNDAMPED electrostatics.\n",
238 painCave.severity = OPENMD_INFO;
239 painCave.isFatal = 0;
244 painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
245 "Electrostatic::initialize: dampingAlpha was not specified in "
247 "\tinput file. A default value of %f (1/ang) will be used for "
249 "\tcutoff of %f (ang).\n",
250 dampingAlpha_, cutoffRadius_);
251 painCave.severity = OPENMD_INFO;
252 painCave.isFatal = 0;
254 haveDampingAlpha_ =
true;
257 dampingAlpha_ = simParams_->getDampingAlpha();
258 haveDampingAlpha_ =
true;
266 ElectrostaticMap.clear();
271 Etids.resize(forceField_->getNAtomType(), -1);
272 FQtids.resize(forceField_->getNAtomType(), -1);
274 AtomTypeSet::iterator at;
275 for (at = simTypes_.begin(); at != simTypes_.end(); ++at) {
276 if ((*at)->isElectrostatic()) nElectro_++;
277 if ((*at)->isFluctuatingCharge()) nFlucq_++;
282 for (at = simTypes_.begin(); at != simTypes_.end(); ++at) {
283 if ((*at)->isElectrostatic()) addType(*at);
286 if (summationMethod_ == esm_REACTION_FIELD) {
287 preRF_ = (dielectric_ - 1.0) /
288 ((2.0 * dielectric_ + 1.0) * pow(cutoffRadius_, 3));
291 RealType b0c, b1c, b2c, b3c, b4c, b5c;
292 RealType db0c_1, db0c_2, db0c_3, db0c_4, db0c_5;
293 RealType a2, expTerm, invArootPi(0.0);
295 RealType r = cutoffRadius_;
297 RealType ric = 1.0 / r;
298 RealType ric2 = ric * ric;
300 if (screeningMethod_ == DAMPED) {
301 a2 = dampingAlpha_ * dampingAlpha_;
302 invArootPi = 1.0 / (dampingAlpha_ * sqrt(Constants::PI));
303 expTerm = exp(-a2 * r2);
305 b0c = erfc(dampingAlpha_ * r) / r;
306 b1c = (b0c + 2.0 * a2 * expTerm * invArootPi) / r2;
307 b2c = (3.0 * b1c + pow(2.0 * a2, 2) * expTerm * invArootPi) / r2;
308 b3c = (5.0 * b2c + pow(2.0 * a2, 3) * expTerm * invArootPi) / r2;
309 b4c = (7.0 * b3c + pow(2.0 * a2, 4) * expTerm * invArootPi) / r2;
310 b5c = (9.0 * b4c + pow(2.0 * a2, 5) * expTerm * invArootPi) / r2;
312 selfMult1_ = -a2 * invArootPi;
313 selfMult2_ = -2.0 * a2 * a2 * invArootPi / 3.0;
314 selfMult4_ = -4.0 * a2 * a2 * a2 * invArootPi / 5.0;
319 b2c = (3.0 * b1c) / r2;
320 b3c = (5.0 * b2c) / r2;
321 b4c = (7.0 * b3c) / r2;
322 b5c = (9.0 * b4c) / r2;
330 db0c_2 = -b1c + r2 * b2c;
331 db0c_3 = 3.0 * r * b2c - r2 * r * b3c;
332 db0c_4 = 3.0 * b2c - 6.0 * r2 * b3c + r2 * r2 * b4c;
333 db0c_5 = -15.0 * r * b3c + 10.0 * r2 * r * b4c - r2 * r2 * r * b5c;
335 if (summationMethod_ != esm_EWALD_FULL) {
337 selfMult2_ += (db0c_2 + 2.0 * db0c_1 * ric) / 3.0;
338 selfMult4_ -= (db0c_4 + 4.0 * db0c_3 * ric) / 15.0;
343 RealType b0, b1, b2, b3, b4, b5;
344 RealType db0_1, db0_2, db0_3, db0_4, db0_5;
346 RealType g, gc, g0, g1, g2, g3, g4;
347 RealType h, hc, h1, h2, h3, h4;
348 RealType s, sc, s2, s3, s4;
349 RealType t, tc, t3, t4;
353 RealType rmRc, rmRc2, rmRc3, rmRc4;
357 int nptest = int((cutoffRadius_ + 2.0) / 0.1);
358 np_ = (np_ > nptest) ? np_ : nptest;
366 RealType dx = (cutoffRadius_ + 2.0) / RealType(np_);
370 vector<RealType> v01v;
371 vector<RealType> v11v;
372 vector<RealType> v21v, v22v;
373 vector<RealType> v31v, v32v;
374 vector<RealType> v41v, v42v, v43v;
376 for (
int i = 1; i < np_ + 1; i++) {
377 r = RealType(i) * dx;
384 expTerm = exp(-a2 * r2);
387 rmRc = r - cutoffRadius_;
388 rmRc2 = rmRc * rmRc / 2.0;
389 rmRc3 = rmRc2 * rmRc / 3.0;
390 rmRc4 = rmRc3 * rmRc / 4.0;
393 if (screeningMethod_ == DAMPED) {
394 b0 = erfc(dampingAlpha_ * r) * ri;
395 b1 = (b0 + 2.0 * a2 * expTerm * invArootPi) * ri2;
396 b2 = (3.0 * b1 + pow(2.0 * a2, 2) * expTerm * invArootPi) * ri2;
397 b3 = (5.0 * b2 + pow(2.0 * a2, 3) * expTerm * invArootPi) * ri2;
398 b4 = (7.0 * b3 + pow(2.0 * a2, 4) * expTerm * invArootPi) * ri2;
399 b5 = (9.0 * b4 + pow(2.0 * a2, 5) * expTerm * invArootPi) * ri2;
403 b2 = (3.0 * b1) * ri2;
404 b3 = (5.0 * b2) * ri2;
405 b4 = (7.0 * b3) * ri2;
406 b5 = (9.0 * b4) * ri2;
411 db0_2 = -b1 + r2 * b2;
412 db0_3 = 3.0 * r * b2 - r2 * r * b3;
413 db0_4 = 3.0 * b2 - 6.0 * r2 * b3 + r2 * r2 * b4;
414 db0_5 = -15.0 * r * b3 + 10.0 * r2 * r * b4 - r2 * r2 * r * b5;
418 f0 = f - fc - rmRc * db0c_1;
423 g1 = g0 - rmRc * db0c_2;
424 g2 = g1 - rmRc2 * db0c_3;
425 g3 = g2 - rmRc3 * db0c_4;
426 g4 = g3 - rmRc4 * db0c_5;
431 h2 = h1 - rmRc * db0c_3;
432 h3 = h2 - rmRc2 * db0c_4;
433 h4 = h3 - rmRc3 * db0c_5;
438 s3 = s2 - rmRc * db0c_4;
439 s4 = s3 - rmRc2 * db0c_5;
444 t4 = t3 - rmRc * db0c_5;
454 switch (summationMethod_) {
455 case esm_SHIFTED_FORCE:
457 v01 = f - fc - rmRc * gc;
458 v11 = g - gc - rmRc * hc;
459 v21 = g * ri - gc * ric - rmRc * (hc - gc * ric) * ric;
461 h - g * ri - (hc - gc * ric) - rmRc * (sc - (hc - gc * ric) * ric);
462 v31 = (h - g * ri) * ri - (hc - gc * ric) * ric -
463 rmRc * (sc - 2.0 * (hc - gc * ric) * ric) * ric;
464 v32 = (s - 3.0 * (h - g * ri) * ri) -
465 (sc - 3.0 * (hc - gc * ric) * ric) -
466 rmRc * (tc - 3.0 * (sc - 2.0 * (hc - gc * ric) * ric) * ric);
467 v41 = (h - g * ri) * ri2 - (hc - gc * ric) * ric2 -
468 rmRc * (sc - 3.0 * (hc - gc * ric) * ric) * ric2;
470 (s - 3.0 * (h - g * ri) * ri) * ri -
471 (sc - 3.0 * (hc - gc * ric) * ric) * ric -
472 rmRc * (tc - (4.0 * sc - 9.0 * (hc - gc * ric) * ric) * ric) * ric;
475 (t - 3.0 * (2.0 * s - 5.0 * (h - g * ri) * ri) * ri) -
476 (tc - 3.0 * (2.0 * sc - 5.0 * (hc - gc * ric) * ric) * ric) -
479 (7.0 * sc - 15.0 * (hc - gc * ric) * ric) * ric) *
484 dv21 = (h - g * ri) * ri - (hc - gc * ric) * ric;
485 dv22 = (s - (h - g * ri) * ri) - (sc - (hc - gc * ric) * ric);
486 dv31 = (s - 2.0 * (h - g * ri) * ri) * ri -
487 (sc - 2.0 * (hc - gc * ric) * ric) * ric;
488 dv32 = (t - 3.0 * (s - 2.0 * (h - g * ri) * ri) * ri) -
489 (tc - 3.0 * (sc - 2.0 * (hc - gc * ric) * ric) * ric);
490 dv41 = (s - 3.0 * (h - g * ri) * ri) * ri2 -
491 (sc - 3.0 * (hc - gc * ric) * ric) * ric2;
492 dv42 = (t - (4.0 * s - 9.0 * (h - g * ri) * ri) * ri) * ri -
493 (tc - (4.0 * sc - 9.0 * (hc - gc * ric) * ric) * ric) * ric;
496 3.0 * (2.0 * t - (7.0 * s - 15.0 * (h - g * ri) * ri) * ri) * ri) -
499 (2.0 * tc - (7.0 * sc - 15.0 * (hc - gc * ric) * ric) * ric) *
504 case esm_TAYLOR_SHIFTED:
510 v31 = (h3 - g3 * ri) * ri;
511 v32 = s3 - 3.0 * v31;
512 v41 = (h4 - g4 * ri) * ri2;
513 v42 = s4 * ri - 3.0 * v41;
514 v43 = t4 - 6.0 * v42 - 3.0 * v41;
518 dv21 = (h2 - g2 * ri) * ri;
519 dv22 = (s2 - (h2 - g2 * ri) * ri);
520 dv31 = (s3 - 2.0 * (h3 - g3 * ri) * ri) * ri;
521 dv32 = (t3 - 3.0 * (s3 - 2.0 * (h3 - g3 * ri) * ri) * ri);
522 dv41 = (s4 - 3.0 * (h4 - g4 * ri) * ri) * ri2;
523 dv42 = (t4 - (4.0 * s4 - 9.0 * (h4 - g4 * ri) * ri) * ri) * ri;
526 3.0 * (2.0 * t4 - (7.0 * s4 - 15.0 * (h4 - g4 * ri) * ri) * ri) *
531 case esm_SHIFTED_POTENTIAL:
535 v21 = g * ri - gc * ric;
536 v22 = h - g * ri - (hc - gc * ric);
537 v31 = (h - g * ri) * ri - (hc - gc * ric) * ric;
539 (s - 3.0 * (h - g * ri) * ri) - (sc - 3.0 * (hc - gc * ric) * ric);
540 v41 = (h - g * ri) * ri2 - (hc - gc * ric) * ric2;
541 v42 = (s - 3.0 * (h - g * ri) * ri) * ri -
542 (sc - 3.0 * (hc - gc * ric) * ric) * ric;
543 v43 = (t - 3.0 * (2.0 * s - 5.0 * (h - g * ri) * ri) * ri) -
544 (tc - 3.0 * (2.0 * sc - 5.0 * (hc - gc * ric) * ric) * ric);
548 dv21 = (h - g * ri) * ri;
549 dv22 = (s - (h - g * ri) * ri);
550 dv31 = (s - 2.0 * (h - g * ri) * ri) * ri;
551 dv32 = (t - 3.0 * (s - 2.0 * (h - g * ri) * ri) * ri);
552 dv41 = (s - 3.0 * (h - g * ri) * ri) * ri2;
553 dv42 = (t - (4.0 * s - 9.0 * (h - g * ri) * ri) * ri) * ri;
556 3.0 * (2.0 * t - (7.0 * s - 15.0 * (h - g * ri) * ri) * ri) * ri);
560 case esm_SWITCHING_FUNCTION:
568 v31 = (h - g * ri) * ri;
569 v32 = (s - 3.0 * (h - g * ri) * ri);
570 v41 = (h - g * ri) * ri2;
571 v42 = (s - 3.0 * (h - g * ri) * ri) * ri;
572 v43 = (t - 3.0 * (2.0 * s - 5.0 * (h - g * ri) * ri) * ri);
576 dv21 = (h - g * ri) * ri;
577 dv22 = (s - (h - g * ri) * ri);
578 dv31 = (s - 2.0 * (h - g * ri) * ri) * ri;
579 dv32 = (t - 3.0 * (s - 2.0 * (h - g * ri) * ri) * ri);
580 dv41 = (s - 3.0 * (h - g * ri) * ri) * ri2;
581 dv42 = (t - (4.0 * s - 9.0 * (h - g * ri) * ri) * ri) * ri;
584 3.0 * (2.0 * t - (7.0 * s - 15.0 * (h - g * ri) * ri) * ri) * ri);
588 case esm_REACTION_FIELD:
591 f = b0 + preRF_ * r2;
592 fc = b0c + preRF_ * cutoffRadius_ * cutoffRadius_;
594 g = db0_1 + preRF_ * 2.0 * r;
595 gc = db0c_1 + preRF_ * 2.0 * cutoffRadius_;
597 h = db0_2 + preRF_ * 2.0;
598 hc = db0c_2 + preRF_ * 2.0;
602 v21 = g * ri - gc * ric;
603 v22 = h - g * ri - (hc - gc * ric);
604 v31 = (h - g * ri) * ri - (hc - gc * ric) * ric;
606 (s - 3.0 * (h - g * ri) * ri) - (sc - 3.0 * (hc - gc * ric) * ric);
607 v41 = (h - g * ri) * ri2 - (hc - gc * ric) * ric2;
608 v42 = (s - 3.0 * (h - g * ri) * ri) * ri -
609 (sc - 3.0 * (hc - gc * ric) * ric) * ric;
610 v43 = (t - 3.0 * (2.0 * s - 5.0 * (h - g * ri) * ri) * ri) -
611 (tc - 3.0 * (2.0 * sc - 5.0 * (hc - gc * ric) * ric) * ric);
615 dv21 = (h - g * ri) * ri;
616 dv22 = (s - (h - g * ri) * ri);
617 dv31 = (s - 2.0 * (h - g * ri) * ri) * ri;
618 dv32 = (t - 3.0 * (s - 2.0 * (h - g * ri) * ri) * ri);
619 dv41 = (s - 3.0 * (h - g * ri) * ri) * ri2;
620 dv42 = (t - (4.0 * s - 9.0 * (h - g * ri) * ri) * ri) * ri;
623 3.0 * (2.0 * t - (7.0 * s - 15.0 * (h - g * ri) * ri) * ri) * ri);
630 map<string, ElectrostaticSummationMethod>::iterator i;
632 for (i = summationMap_.begin(); i != summationMap_.end(); ++i) {
633 if ((*i).second == summationMethod_) meth = (*i).first;
635 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
636 "Electrostatic::initialize: electrostaticSummationMethod %s \n"
637 "\thas not been implemented yet. Please select one of:\n"
638 "\t\"hard\", \"shifted_potential\", or \"shifted_force\"\n",
640 painCave.isFatal = 1;
660 v01s = std::make_shared<CubicSpline>();
661 v01s->addPoints(rv, v01v);
662 v11s = std::make_shared<CubicSpline>();
663 v11s->addPoints(rv, v11v);
664 v21s = std::make_shared<CubicSpline>();
665 v21s->addPoints(rv, v21v);
666 v22s = std::make_shared<CubicSpline>();
667 v22s->addPoints(rv, v22v);
668 v31s = std::make_shared<CubicSpline>();
669 v31s->addPoints(rv, v31v);
670 v32s = std::make_shared<CubicSpline>();
671 v32s->addPoints(rv, v32v);
672 v41s = std::make_shared<CubicSpline>();
673 v41s->addPoints(rv, v41v);
674 v42s = std::make_shared<CubicSpline>();
675 v42s->addPoints(rv, v42v);
676 v43s = std::make_shared<CubicSpline>();
677 v43s->addPoints(rv, v43v);
679 haveElectroSplines_ =
true;
684 void Electrostatic::addType(
AtomType* atomType) {
686 electrostaticAtomData.is_Charge =
false;
687 electrostaticAtomData.is_Dipole =
false;
688 electrostaticAtomData.is_Quadrupole =
false;
689 electrostaticAtomData.is_Fluctuating =
false;
690 electrostaticAtomData.uses_SlaterIntramolecular =
false;
694 if (fca.isFixedCharge()) {
695 electrostaticAtomData.is_Charge =
true;
696 electrostaticAtomData.fixedCharge = fca.getCharge();
700 if (ma.isMultipole()) {
702 electrostaticAtomData.is_Dipole =
true;
703 electrostaticAtomData.dipole = ma.getDipole();
705 if (ma.isQuadrupole()) {
706 electrostaticAtomData.is_Quadrupole =
true;
707 electrostaticAtomData.quadrupole = ma.getQuadrupole();
713 if (fqa.isFluctuatingCharge()) {
714 electrostaticAtomData.is_Fluctuating =
true;
715 electrostaticAtomData.uses_SlaterIntramolecular =
716 fqa.usesSlaterIntramolecular();
717 electrostaticAtomData.electronegativity = fqa.getElectronegativity();
718 electrostaticAtomData.hardness = fqa.getHardness();
719 electrostaticAtomData.slaterN = fqa.getSlaterN();
720 electrostaticAtomData.slaterZeta = fqa.getSlaterZeta();
723 int atid = atomType->getIdent();
724 int etid = Etypes.size();
725 int fqtid = FQtypes.size();
727 pair<set<int>::iterator,
bool> ret;
728 ret = Etypes.insert(atid);
729 if (ret.second ==
false) {
730 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
731 "Electrostatic already had a previous entry with ident %d\n",
733 painCave.severity = OPENMD_INFO;
734 painCave.isFatal = 0;
739 ElectrostaticMap.push_back(electrostaticAtomData);
741 if (electrostaticAtomData.is_Fluctuating) {
742 ret = FQtypes.insert(atid);
743 if (ret.second ==
false) {
745 painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
746 "Electrostatic already had a previous fluctuating charge entry "
749 painCave.severity = OPENMD_INFO;
750 painCave.isFatal = 0;
753 FQtids[atid] = fqtid;
754 Jij[fqtid].resize(nFlucq_);
759 std::set<int>::iterator it;
760 for (it = FQtypes.begin(); it != FQtypes.end(); ++it) {
761 int etid2 = Etids[(*it)];
762 int fqtid2 = FQtids[(*it)];
764 RealType a = electrostaticAtomData.slaterZeta;
765 RealType b = eaData2.slaterZeta;
766 int m = electrostaticAtomData.slaterN;
767 int n = eaData2.slaterN;
768 CubicSplinePtr J {std::make_shared<CubicSpline>()};
772 if ((electrostaticAtomData.uses_SlaterIntramolecular &&
773 eaData2.uses_SlaterIntramolecular)) {
780 RealType dr = (cutoffRadius_ + 2.0) / RealType(np_ - 1);
781 vector<RealType> rvals;
782 vector<RealType> Jvals;
786 for (
int i = 1; i < np_ + 1; i++) {
787 rval = RealType(i) * dr;
788 rvals.push_back(rval);
791 sSTOCoulInt(a, b, m, n, rval * Constants::angstromToBohr) *
792 Constants::hartreeToKcal);
795 J->addPoints(rvals, Jvals);
797 Jij[fqtid][fqtid2] = J;
798 Jij[fqtid2].resize(nFlucq_);
799 Jij[fqtid2][fqtid] = J;
805 void Electrostatic::setCutoffRadius(RealType rCut) {
806 cutoffRadius_ = rCut;
807 haveCutoffRadius_ =
true;
810 void Electrostatic::setElectrostaticSummationMethod(
812 summationMethod_ = esm;
814 void Electrostatic::setElectrostaticScreeningMethod(
815 ElectrostaticScreeningMethod sm) {
816 screeningMethod_ = sm;
818 void Electrostatic::setDampingAlpha(RealType alpha) {
819 dampingAlpha_ = alpha;
820 haveDampingAlpha_ =
true;
822 void Electrostatic::setReactionFieldDielectric(RealType dielectric) {
823 dielectric_ = dielectric;
824 haveDielectric_ =
true;
828 if (!initialized_) initialize();
830 if (Etids[idat.
atid1] != -1) {
831 data1 = ElectrostaticMap[Etids[idat.
atid1]];
832 a_is_Charge = data1.is_Charge;
833 a_is_Dipole = data1.is_Dipole;
834 a_is_Quadrupole = data1.is_Quadrupole;
835 a_is_Fluctuating = data1.is_Fluctuating;
836 a_uses_SlaterIntra = data1.uses_SlaterIntramolecular;
841 a_is_Quadrupole =
false;
842 a_is_Fluctuating =
false;
843 a_uses_SlaterIntra =
false;
845 if (Etids[idat.
atid2] != -1) {
846 data2 = ElectrostaticMap[Etids[idat.
atid2]];
847 b_is_Charge = data2.is_Charge;
848 b_is_Dipole = data2.is_Dipole;
849 b_is_Quadrupole = data2.is_Quadrupole;
850 b_is_Fluctuating = data2.is_Fluctuating;
851 b_uses_SlaterIntra = data2.uses_SlaterIntramolecular;
856 b_is_Quadrupole =
false;
857 b_is_Fluctuating =
false;
858 b_uses_SlaterIntra =
false;
889 if (((a_uses_SlaterIntra || b_uses_SlaterIntra) && idat.
excluded)) {
890 J = Jij[FQtids[idat.
atid1]][FQtids[idat.
atid2]];
894 if (a_is_Charge || b_is_Charge) {
895 v01s->getValueAndDerivativeAt(idat.
rij, v01, dv01);
897 if (a_is_Dipole || b_is_Dipole) {
898 v11s->getValueAndDerivativeAt(idat.
rij, v11, dv11);
901 if (a_is_Quadrupole || b_is_Quadrupole || (a_is_Dipole && b_is_Dipole)) {
902 v21s->getValueAndDerivativeAt(idat.
rij, v21, dv21);
903 v22s->getValueAndDerivativeAt(idat.
rij, v22, dv22);
908 if ((a_is_Dipole && b_is_Quadrupole) || (b_is_Dipole && a_is_Quadrupole)) {
909 v31s->getValueAndDerivativeAt(idat.
rij, v31, dv31);
910 v32s->getValueAndDerivativeAt(idat.
rij, v32, dv32);
914 if (a_is_Quadrupole && b_is_Quadrupole) {
915 v41s->getValueAndDerivativeAt(idat.
rij, v41, dv41);
916 v42s->getValueAndDerivativeAt(idat.
rij, v42, dv42);
917 v43s->getValueAndDerivativeAt(idat.
rij, v43, dv43);
925 C_a = data1.fixedCharge;
927 if (a_is_Fluctuating) { C_a += idat.
flucQ1; }
933 Eb -= C_a * pre11_ * dv01 * rhat;
934 Pb += C_a * pre11_ * v01;
939 rdDa =
dot(rhat, idat.
D_1);
942 Eb -= pre12_ * ((dv11 - v11or) * rdDa * rhat + v11or * idat.
D_1);
943 Pb += pre12_ * v11 * rdDa;
947 if (a_is_Quadrupole) {
949 Qar = idat.
Q_1 * rhat;
950 rQa = rhat * idat.
Q_1;
951 rdQar =
dot(rhat, Qar);
952 rxQar =
cross(rhat, Qar);
954 Eb -= pre14_ * (trQa * rhat * dv21 + 2.0 * Qar * v22or +
955 rdQar * rhat * (dv22 - 2.0 * v22or));
956 Pb += pre14_ * (v21 * trQa + v22 * rdQar);
961 C_b = data2.fixedCharge;
963 if (b_is_Fluctuating) { C_b += idat.
flucQ2; }
969 Ea += C_b * pre11_ * dv01 * rhat;
970 Pa += C_b * pre11_ * v01;
975 rdDb =
dot(rhat, idat.
D_2);
978 Ea += pre12_ * ((dv11 - v11or) * rdDb * rhat + v11or * idat.
D_2);
979 Pa += pre12_ * v11 * rdDb;
983 if (b_is_Quadrupole) {
985 Qbr = idat.
Q_2 * rhat;
986 rQb = rhat * idat.
Q_2;
987 rdQbr =
dot(rhat, Qbr);
988 rxQbr =
cross(rhat, Qbr);
990 Ea += pre14_ * (trQb * rhat * dv21 + 2.0 * Qbr * v22or +
991 rdQbr * rhat * (dv22 - 2.0 * v22or));
992 Pa += pre14_ * (v21 * trQb + v22 * rdQbr);
999 U += C_a * C_b * pref * v01;
1000 F += C_a * C_b * pref * dv01 * rhat;
1005 if (summationMethod_ == esm_REACTION_FIELD && idat.
excluded) {
1006 rfContrib = preRF_ * pref * C_a * C_b * idat.
r2;
1007 indirect_Pot += rfContrib;
1008 indirect_F += rfContrib * 2.0 * ri * rhat;
1016 if (a_uses_SlaterIntra || b_uses_SlaterIntra) {
1017 coulInt = J->getValueAt(idat.
rij);
1018 excluded_Pot += C_a * C_b * coulInt;
1019 if (a_is_Fluctuating) dUdCa += C_b * coulInt;
1020 if (b_is_Fluctuating) dUdCb += C_a * coulInt;
1023 if (a_is_Fluctuating) dUdCa += C_b * pref * v01;
1024 if (b_is_Fluctuating) dUdCb += C_a * pref * v01;
1030 U += C_a * pref * v11 * rdDb;
1031 F += C_a * pref * ((dv11 - v11or) * rdDb * rhat + v11or * idat.
D_2);
1032 Tb += C_a * pref * v11 * rxDb;
1034 if (a_is_Fluctuating) dUdCa += pref * v11 * rdDb;
1040 if (summationMethod_ == esm_REACTION_FIELD && idat.
excluded) {
1041 rfContrib = C_a * pref * preRF_ * 2.0 * idat.
rij;
1042 indirect_Pot += rfContrib * rdDb;
1043 indirect_F += rfContrib * idat.
D_2 / idat.
rij;
1044 indirect_Tb += C_a * pref * preRF_ * rxDb;
1048 if (b_is_Quadrupole) {
1050 U += C_a * pref * (v21 * trQb + v22 * rdQbr);
1051 F += C_a * pref * (trQb * dv21 * rhat + 2.0 * Qbr * v22or);
1052 F += C_a * pref * rdQbr * rhat * (dv22 - 2.0 * v22or);
1053 Tb += C_a * pref * 2.0 * rxQbr * v22;
1055 if (a_is_Fluctuating) dUdCa += pref * (v21 * trQb + v22 * rdQbr);
1063 U -= C_b * pref * v11 * rdDa;
1064 F -= C_b * pref * ((dv11 - v11or) * rdDa * rhat + v11or * idat.
D_1);
1065 Ta -= C_b * pref * v11 * rxDa;
1067 if (b_is_Fluctuating) dUdCb -= pref * v11 * rdDa;
1072 if (summationMethod_ == esm_REACTION_FIELD && idat.
excluded) {
1073 rfContrib = C_b * pref * preRF_ * 2.0 * idat.
rij;
1074 indirect_Pot -= rfContrib * rdDa;
1075 indirect_F -= rfContrib * idat.
D_1 / idat.
rij;
1076 indirect_Ta -= C_b * pref * preRF_ * rxDa;
1085 U -= pref * (DadDb * v21 + rdDa * rdDb * v22);
1086 F -= pref * (dv21 * DadDb * rhat +
1087 v22or * (rdDb * idat.
D_1 + rdDa * idat.
D_2));
1088 F -= pref * (rdDa * rdDb) * (dv22 - 2.0 * v22or) * rhat;
1089 Ta += pref * (v21 * DaxDb - v22 * rdDb * rxDa);
1090 Tb += pref * (-v21 * DaxDb - v22 * rdDa * rxDb);
1094 if (summationMethod_ == esm_REACTION_FIELD && idat.
excluded) {
1095 rfContrib = -pref * preRF_ * 2.0;
1096 indirect_Pot += rfContrib * DadDb;
1097 indirect_Ta += rfContrib * DaxDb;
1098 indirect_Tb -= rfContrib * DaxDb;
1102 if (b_is_Quadrupole) {
1104 DadQb = idat.
D_1 * idat.
Q_2;
1105 DadQbr =
dot(idat.
D_1, Qbr);
1108 U -= pref * ((trQb * rdDa + 2.0 * DadQbr) * v31 + rdDa * rdQbr * v32);
1109 F -= pref * (trQb * idat.
D_1 + 2.0 * DadQb) * v31or;
1110 F -= pref * (trQb * rdDa + 2.0 * DadQbr) * (dv31 - v31or) * rhat;
1111 F -= pref * (idat.
D_1 * rdQbr + 2.0 * rdDa * rQb) * v32or;
1112 F -= pref * (rdDa * rdQbr * rhat * (dv32 - 3.0 * v32or));
1113 Ta += pref * ((-trQb * rxDa + 2.0 * DaxQbr) * v31 - rxDa * rdQbr * v32);
1114 Tb += pref * ((2.0 *
cross(DadQb, rhat) - 2.0 * DaxQbr) * v31 -
1115 2.0 * rdDa * rxQbr * v32);
1119 if (a_is_Quadrupole) {
1122 U += C_b * pref * (v21 * trQa + v22 * rdQar);
1123 F += C_b * pref * (trQa * rhat * dv21 + 2.0 * Qar * v22or);
1124 F += C_b * pref * rdQar * rhat * (dv22 - 2.0 * v22or);
1125 Ta += C_b * pref * 2.0 * rxQar * v22;
1127 if (b_is_Fluctuating) dUdCb += pref * (v21 * trQa + v22 * rdQar);
1131 DbdQa = idat.
D_2 * idat.
Q_1;
1132 DbdQar =
dot(idat.
D_2, Qar);
1135 U += pref * ((trQa * rdDb + 2.0 * DbdQar) * v31 + rdDb * rdQar * v32);
1136 F += pref * (trQa * idat.
D_2 + 2.0 * DbdQa) * v31or;
1137 F += pref * (trQa * rdDb + 2.0 * DbdQar) * (dv31 - v31or) * rhat;
1138 F += pref * (idat.
D_2 * rdQar + 2.0 * rdDb * rQa) * v32or;
1139 F += pref * (rdDb * rdQar * rhat * (dv32 - 3.0 * v32or));
1140 Ta += pref * ((-2.0 *
cross(DbdQa, rhat) + 2.0 * DbxQar) * v31 +
1141 2.0 * rdDb * rxQar * v32);
1142 Tb += pref * ((trQa * rxDb - 2.0 * DbxQar) * v31 + rxDb * rdQar * v32);
1144 if (b_is_Quadrupole) {
1146 QaQb = idat.
Q_1 * idat.
Q_2;
1147 trQaQb = QaQb.
trace();
1148 rQaQb = rhat * QaQb;
1149 QaQbr = QaQb * rhat;
1151 rQaQbr =
dot(rQa, Qbr);
1152 rQaxQbr =
cross(rQa, Qbr);
1154 U += pref * (trQa * trQb + 2.0 * trQaQb) * v41;
1155 U += pref * (trQa * rdQbr + trQb * rdQar + 4.0 * rQaQbr) * v42;
1156 U += pref * (rdQar * rdQbr) * v43;
1158 F += pref * rhat * (trQa * trQb + 2.0 * trQaQb) * dv41;
1159 F += pref * rhat * (trQa * rdQbr + trQb * rdQar + 4.0 * rQaQbr) *
1160 (dv42 - 2.0 * v42or);
1161 F += pref * rhat * (rdQar * rdQbr) * (dv43 - 4.0 * v43or);
1163 F += pref * 2.0 * (trQb * rQa + trQa * rQb) * v42or;
1164 F += pref * 4.0 * (rQaQb + QaQbr) * v42or;
1165 F += pref * 2.0 * (rQa * rdQbr + rdQar * rQb) * v43or;
1167 Ta += pref * (-4.0 * QaxQb * v41);
1169 (-2.0 * trQb *
cross(rQa, rhat) + 4.0 *
cross(rhat, QaQbr) -
1172 Ta += pref * 2.0 *
cross(rhat, Qar) * rdQbr * v43;
1174 Tb += pref * (+4.0 * QaxQb * v41);
1176 (-2.0 * trQa *
cross(rQb, rhat) - 4.0 *
cross(rQaQb, rhat) +
1182 Tb += pref * 2.0 *
cross(rhat, Qbr) * rdQar * v43;
1196 if (a_is_Fluctuating) idat.
dVdFQ1 += dUdCa * idat.
sw;
1197 if (b_is_Fluctuating) idat.
dVdFQ2 += dUdCb * idat.
sw;
1204 idat.
f1 += F * idat.
sw;
1206 if (a_is_Dipole || a_is_Quadrupole) idat.
t1 += Ta * idat.
sw;
1208 if (b_is_Dipole || b_is_Quadrupole) idat.
t2 += Tb * idat.
sw;
1214 idat.
vpair += indirect_Pot;
1220 idat.
f1 += idat.
sw * indirect_F;
1222 if (a_is_Dipole || a_is_Quadrupole) idat.
t1 += idat.
sw * indirect_Ta;
1224 if (b_is_Dipole || b_is_Quadrupole) idat.
t2 += idat.
sw * indirect_Tb;
1229 void Electrostatic::calcSelfCorrection(
SelfData& sdat) {
1230 if (!initialized_) initialize();
1235 bool i_is_Charge = data.is_Charge;
1236 bool i_is_Dipole = data.is_Dipole;
1237 bool i_is_Quadrupole = data.is_Quadrupole;
1238 bool i_is_Fluctuating = data.is_Fluctuating;
1239 RealType C_a = data.fixedCharge;
1240 RealType selfPot(0.0), fqf(0.0), preVal, DdD(0.0), trQ, trQQ;
1244 if (i_is_Fluctuating) {
1248 flucQ_->getSelfInteraction(sdat.
atid, sdat.
flucQ, selfPot, fqf);
1251 switch (summationMethod_) {
1252 case esm_REACTION_FIELD:
1258 preVal = pre11_ * preRF_ * C_a * C_a;
1259 selfPot -= 0.5 * preVal / cutoffRadius_;
1265 if (i_is_Dipole) { selfPot -= pre22_ * preRF_ * DdD; }
1269 case esm_SHIFTED_FORCE:
1270 case esm_SHIFTED_POTENTIAL:
1271 case esm_TAYLOR_SHIFTED:
1272 case esm_EWALD_FULL:
1274 selfPot += selfMult1_ * pre11_ * pow(C_a + sdat.
skippedCharge, 2);
1275 if (i_is_Fluctuating) {
1276 fqf -= selfMult1_ * pre11_ * 2.0 * (C_a + sdat.
skippedCharge);
1279 if (i_is_Dipole) selfPot += selfMult2_ * pre22_ * DdD;
1280 if (i_is_Quadrupole) {
1281 trQ = data.quadrupole.
trace();
1282 trQQ = (data.quadrupole * data.quadrupole).trace();
1283 selfPot += selfMult4_ * pre44_ * (2.0 * trQQ + trQ * trQ);
1285 selfPot -= selfMult2_ * pre14_ * 2.0 * C_a * trQ;
1286 if (i_is_Fluctuating) { fqf += selfMult2_ * pre14_ * 2.0 * trQ; }
1300 if (i_is_Fluctuating) sdat.
flucQfrc += fqf;
1303 void Electrostatic::calcSurfaceTerm(
bool slabGeometry,
int axis,
1305 SimInfo::MoleculeIterator mi;
1306 Molecule::AtomIterator ai;
1315 const RealType mPoleConverter = 0.20819434;
1323 const RealType eConverter = 332.0637778;
1331 if (!initialized_) initialize();
1335 for (
Atom* atom = mol->beginAtom(ai); atom != NULL;
1336 atom = mol->nextAtom(ai)) {
1337 atid = atom->getAtomType()->getIdent();
1338 data = ElectrostaticMap[Etids[atid]];
1340 if (data.is_Charge) {
1341 C = data.fixedCharge;
1342 if (data.is_Fluctuating) C += atom->getFlucQPos();
1350 if (data.is_Dipole) {
1351 D = atom->getDipole() * mPoleConverter;
1358 MPI_Allreduce(MPI_IN_PLACE, netDipole.getArrayPointer(), 3, MPI_REALTYPE,
1359 MPI_SUM, MPI_COMM_WORLD);
1366 prefactor = 2.0 * Constants::PI / V;
1368 int axis1 = (axis + 1) % 3;
1369 int axis2 = (axis + 2) % 3;
1370 netDipole[axis1] = 0.0;
1371 netDipole[axis2] = 0.0;
1373 prefactor = 2.0 * Constants::PI / (3.0 * V);
1376 pot += eConverter * prefactor * netDipole.lengthSquare();
1380 for (
Atom* atom = mol->beginAtom(ai); atom != NULL;
1381 atom = mol->nextAtom(ai)) {
1382 atom->addElectricField(-eConverter * prefactor * 2.0 * netDipole);
1384 atid = atom->getAtomType()->getIdent();
1385 data = ElectrostaticMap[Etids[atid]];
1387 if (data.is_Charge) {
1388 C = data.fixedCharge;
1389 if (data.is_Fluctuating) {
1392 atom->addFlucQFrc(-eConverter * prefactor * 2.0 *
1395 atom->addFrc(-eConverter * prefactor * 2.0 * C * netDipole);
1398 if (data.is_Dipole) {
1399 D = atom->getDipole() * mPoleConverter;
1400 t = -eConverter * prefactor * 2.0 *
cross(D, netDipole);
1407 RealType Electrostatic::getSuggestedCutoffRadius(pair<AtomType*, AtomType*>) {
1415 void Electrostatic::ReciprocalSpaceSum(RealType& pot) {
1416 RealType kPot = 0.0;
1417 RealType kVir = 0.0;
1420 const RealType mPoleConverter = 0.20819434;
1428 const RealType eConverter = 332.0637778;
1438 RealType boxMax = box.max();
1443 int kSqMax = kMax * kMax + 2;
1445 int kLimit = kMax + 1;
1446 int kLim2 = 2 * kMax + 1;
1447 int kSqLim = kSqMax;
1449 vector<RealType> AK(kSqLim + 1, 0.0);
1450 RealType xcl = 2.0 * Constants::PI / box.
x();
1451 RealType ycl = 2.0 * Constants::PI / box.
y();
1452 RealType zcl = 2.0 * Constants::PI / box.
z();
1453 RealType rcl = 2.0 * Constants::PI / boxMax;
1454 RealType rvol = 2.0 * Constants::PI / (box.
x() * box.
y() * box.
z());
1456 if (dampingAlpha_ < 1.0e-12)
return;
1458 RealType ralph = -0.25 / pow(dampingAlpha_, 2);
1462 vector<vector<RealType>> elc;
1463 vector<vector<RealType>> emc;
1464 vector<vector<RealType>> enc;
1465 vector<vector<RealType>> els;
1466 vector<vector<RealType>> ems;
1467 vector<vector<RealType>> ens;
1471 elc.resize(kLimit + 1);
1472 emc.resize(kLimit + 1);
1473 enc.resize(kLimit + 1);
1474 els.resize(kLimit + 1);
1475 ems.resize(kLimit + 1);
1476 ens.resize(kLimit + 1);
1478 for (
int j = 0; j < kLimit + 1; j++) {
1479 elc[j].resize(nMax);
1480 emc[j].resize(nMax);
1481 enc[j].resize(nMax);
1482 els[j].resize(nMax);
1483 ems[j].resize(nMax);
1484 ens[j].resize(nMax);
1490 SimInfo::MoleculeIterator mi;
1491 Molecule::AtomIterator ai;
1498 for (
Atom* atom = mol->beginAtom(ai); atom != NULL;
1499 atom = mol->nextAtom(ai)) {
1500 i = atom->getLocalIndex();
1513 elc[2][i] = cos(tt.
x());
1514 emc[2][i] = cos(tt.
y());
1515 enc[2][i] = cos(tt.
z());
1516 els[2][i] = sin(tt.
x());
1517 ems[2][i] = sin(tt.
y());
1518 ens[2][i] = sin(tt.
z());
1520 for (
int l = 3; l <= kLimit; l++) {
1521 elc[l][i] = elc[l - 1][i] * elc[2][i] - els[l - 1][i] * els[2][i];
1522 emc[l][i] = emc[l - 1][i] * emc[2][i] - ems[l - 1][i] * ems[2][i];
1523 enc[l][i] = enc[l - 1][i] * enc[2][i] - ens[l - 1][i] * ens[2][i];
1524 els[l][i] = els[l - 1][i] * elc[2][i] + elc[l - 1][i] * els[2][i];
1525 ems[l][i] = ems[l - 1][i] * emc[2][i] + emc[l - 1][i] * ems[2][i];
1526 ens[l][i] = ens[l - 1][i] * enc[2][i] + enc[l - 1][i] * ens[2][i];
1533 RealType eksq = 1.0;
1534 RealType expf = 0.0;
1535 if (ralph < 0.0) expf = exp(ralph * rcl * rcl);
1536 for (i = 1; i <= kSqLim; i++) {
1537 RealType rksq = float(i) * rcl * rcl;
1539 AK[i] = eConverter * eksq / rksq;
1558 std::vector<RealType> clm(nMax, 0.0);
1559 std::vector<RealType> slm(nMax, 0.0);
1560 std::vector<RealType> ckr(nMax, 0.0);
1561 std::vector<RealType> skr(nMax, 0.0);
1562 std::vector<RealType> ckc(nMax, 0.0);
1563 std::vector<RealType> cks(nMax, 0.0);
1564 std::vector<RealType> dkc(nMax, 0.0);
1565 std::vector<RealType> dks(nMax, 0.0);
1566 std::vector<RealType> qkc(nMax, 0.0);
1567 std::vector<RealType> qks(nMax, 0.0);
1568 std::vector<Vector3d> dxk(nMax, V3Zero);
1569 std::vector<Vector3d> qxk(nMax, V3Zero);
1570 RealType rl, rm, rn;
1575 RealType ckcs, ckss, dkcs, dkss, qkcs, qkss;
1583 int nMin = kLimit + 1;
1584 for (
int l = 1; l <= kLimit; l++) {
1586 rl = xcl * float(ll);
1587 for (
int mmm = mMin; mmm <= kLim2; mmm++) {
1588 int mm = mmm - kLimit;
1589 int m = abs(mm) + 1;
1590 rm = ycl * float(mm);
1594 for (
Atom* atom = mol->beginAtom(ai); atom != NULL;
1595 atom = mol->nextAtom(ai)) {
1596 i = atom->getLocalIndex();
1598 clm[i] = elc[l][i] * emc[m][i] + els[l][i] * ems[m][i];
1599 slm[i] = els[l][i] * emc[m][i] - ems[m][i] * elc[l][i];
1601 clm[i] = elc[l][i] * emc[m][i] - els[l][i] * ems[m][i];
1602 slm[i] = els[l][i] * emc[m][i] + ems[m][i] * elc[l][i];
1606 for (
int nnn = nMin; nnn <= kLim2; nnn++) {
1607 int nn = nnn - kLimit;
1608 int n = abs(nn) + 1;
1609 rn = zcl * float(nn);
1611 int kk = ll * ll + mm * mm + nn * nn;
1615 Kmat = outProduct(kVec, kVec);
1619 for (
Atom* atom = mol->beginAtom(ai); atom != NULL;
1620 atom = mol->nextAtom(ai)) {
1621 i = atom->getLocalIndex();
1624 ckr[i] = clm[i] * enc[n][i] + slm[i] * ens[n][i];
1625 skr[i] = slm[i] * enc[n][i] - clm[i] * ens[n][i];
1628 ckr[i] = clm[i] * enc[n][i] - slm[i] * ens[n][i];
1629 skr[i] = slm[i] * enc[n][i] + clm[i] * ens[n][i];
1638 for (
Atom* atom = mol->beginAtom(ai); atom != NULL;
1639 atom = mol->nextAtom(ai)) {
1640 i = atom->getLocalIndex();
1641 int atid = atom->getAtomType()->getIdent();
1642 data = ElectrostaticMap[Etids[atid]];
1644 if (data.is_Charge) {
1645 C = data.fixedCharge;
1646 if (data.is_Fluctuating) C += atom->getFlucQPos();
1647 ckc[i] = C * ckr[i];
1648 cks[i] = C * skr[i];
1651 if (data.is_Dipole) {
1652 D = atom->getDipole() * mPoleConverter;
1654 dxk[i] =
cross(D, kVec);
1655 dkc[i] = dk * ckr[i];
1656 dks[i] = dk * skr[i];
1658 if (data.is_Quadrupole) {
1659 Q = atom->getQuadrupole() * mPoleConverter;
1662 qxk[i] = -
cross(kVec, Qk);
1663 qkc[i] = qk * ckr[i];
1664 qks[i] = qk * skr[i];
1671 ckcs = std::accumulate(ckc.begin(), ckc.end(), 0.0);
1672 ckss = std::accumulate(cks.begin(), cks.end(), 0.0);
1673 dkcs = std::accumulate(dkc.begin(), dkc.end(), 0.0);
1674 dkss = std::accumulate(dks.begin(), dks.end(), 0.0);
1675 qkcs = std::accumulate(qkc.begin(), qkc.end(), 0.0);
1676 qkss = std::accumulate(qks.begin(), qks.end(), 0.0);
1679 MPI_Allreduce(MPI_IN_PLACE, &ckcs, 1, MPI_REALTYPE, MPI_SUM,
1681 MPI_Allreduce(MPI_IN_PLACE, &ckss, 1, MPI_REALTYPE, MPI_SUM,
1683 MPI_Allreduce(MPI_IN_PLACE, &dkcs, 1, MPI_REALTYPE, MPI_SUM,
1685 MPI_Allreduce(MPI_IN_PLACE, &dkss, 1, MPI_REALTYPE, MPI_SUM,
1687 MPI_Allreduce(MPI_IN_PLACE, &qkcs, 1, MPI_REALTYPE, MPI_SUM,
1689 MPI_Allreduce(MPI_IN_PLACE, &qkss, 1, MPI_REALTYPE, MPI_SUM,
1695 kPot += 2.0 * rvol * AK[kk] *
1696 ((ckss + dkcs - qkss) * (ckss + dkcs - qkss) +
1697 (ckcs - dkss - qkcs) * (ckcs - dkss - qkcs));
1700 2.0 * rvol * AK[kk] *
1701 (ckcs * ckcs + ckss * ckss + 4.0 * (ckss * dkcs - ckcs * dkss) +
1702 3.0 * (dkcs * dkcs + dkss * dkss) -
1703 6.0 * (ckss * qkss + ckcs * qkcs) +
1704 8.0 * (dkss * qkcs - dkcs * qkss) +
1705 5.0 * (qkss * qkss + qkcs * qkcs));
1720 for (
Atom* atom = mol->beginAtom(ai); atom != NULL;
1721 atom = mol->nextAtom(ai)) {
1722 i = atom->getLocalIndex();
1723 atid = atom->getAtomType()->getIdent();
1724 data = ElectrostaticMap[Etids[atid]];
1728 ((cks[i] + dkc[i] - qks[i]) * (ckcs - dkss - qkcs) -
1729 (ckc[i] - dks[i] - qkc[i]) * (ckss + dkcs - qkss));
1730 RealType qtrq1 = AK[kk] * (skr[i] * (ckcs - dkss - qkcs) -
1731 ckr[i] * (ckss + dkcs - qkss));
1732 RealType qtrq2 = 2.0 * AK[kk] *
1733 (ckr[i] * (ckcs - dkss - qkcs) +
1734 skr[i] * (ckss + dkcs - qkss));
1736 atom->addFrc(4.0 * rvol * qfrc * kVec);
1738 if (data.is_Fluctuating) {
1739 atom->addFlucQFrc(-2.0 * rvol * qtrq2);
1742 if (data.is_Dipole) {
1743 atom->addTrq(4.0 * rvol * qtrq1 * dxk[i]);
1745 if (data.is_Quadrupole) {
1746 atom->addTrq(4.0 * rvol * qtrq2 * qxk[i]);
1760 void Electrostatic::getSitePotentials(
Atom* a1,
Atom* a2,
bool excluded,
1761 RealType& spot1, RealType& spot2) {
1762 if (!initialized_) { initialize(); }
1764 const RealType mPoleConverter = 0.20819434;
1768 int atid1 = atype1->getIdent();
1769 int atid2 = atype2->getIdent();
1770 data1 = ElectrostaticMap[Etids[atid1]];
1771 data2 = ElectrostaticMap[Etids[atid2]];
1778 RealType rij = d.
length();
1781 RealType ri = 1.0 / rij;
1784 if ((rij >= cutoffRadius_) || excluded) {
1792 a_is_Charge = data1.is_Charge;
1793 a_is_Dipole = data1.is_Dipole;
1794 a_is_Quadrupole = data1.is_Quadrupole;
1795 a_is_Fluctuating = data1.is_Fluctuating;
1797 b_is_Charge = data2.is_Charge;
1798 b_is_Dipole = data2.is_Dipole;
1799 b_is_Quadrupole = data2.is_Quadrupole;
1800 b_is_Fluctuating = data2.is_Fluctuating;
1805 if (a_is_Charge || b_is_Charge) { v01 = v01s->getValueAt(rij); }
1806 if (a_is_Dipole || b_is_Dipole) {
1807 v11 = v11s->getValueAt(rij);
1810 if (a_is_Quadrupole || b_is_Quadrupole) {
1811 v21 = v21s->getValueAt(rij);
1812 v22 = v22s->getValueAt(rij);
1817 C_a = data1.fixedCharge;
1819 if (a_is_Fluctuating) { C_a += a1->
getFlucQPos(); }
1821 Pb += C_a * pre11_ * v01;
1826 rdDa =
dot(rhat, D_a);
1827 Pb += pre12_ * v11 * rdDa;
1830 if (a_is_Quadrupole) {
1834 rdQar =
dot(rhat, Qar);
1835 Pb += pre14_ * (v21 * trQa + v22 * rdQar);
1839 C_b = data2.fixedCharge;
1843 Pa += C_b * pre11_ * v01;
1848 rdDb =
dot(rhat, D_b);
1849 Pa += pre12_ * v11 * rdDb;
1852 if (b_is_Quadrupole) {
1856 rdQbr =
dot(rhat, Qbr);
1857 Pa += pre14_ * (v21 * trQb + v22 * rdQbr);
1864 RealType Electrostatic::getFieldFunction(RealType r) {
1865 if (!initialized_) { initialize(); }
1867 v01s->getValueAndDerivativeAt(r, v01, dv01);
1868 return dv01 * pre11_;
AtomType * getAtomType()
Returns the AtomType of this Atom.
AtomType is what OpenMD looks to for unchanging data about an atom.
Molecule * beginMolecule(MoleculeIterator &i)
Returns the first molecule in this SimInfo and intialize the iterator.
unsigned int getNAtoms()
Returns the number of local atoms.
Molecule * nextMolecule(MoleculeIterator &i)
Returns the next avaliable Molecule based on the iterator.
SnapshotManager * getSnapshotManager()
Returns the snapshot manager.
Mat3x3d getHmat()
Returns the H-Matrix.
void wrapVector(Vector3d &v)
Wrapping the vector according to periodic boundary condition.
Snapshot * getCurrentSnapshot()
Returns the pointer of current snapshot.
Real trace() const
Returns the trace of this matrix.
Vector< Real, Dim > diagonals() const
Returns a column vector that contains the elements from the diagonal of m in the order R(0) = m(0,...
Mat3x3d getQuadrupole()
Returns the current quadrupole tensor of this stuntDouble.
Vector3d getPos()
Returns the current position of this stuntDouble.
RealType getFlucQPos()
Returns the current fluctuating charge of this stuntDouble.
Vector3d getDipole()
Returns the current dipole vector of this stuntDouble.
Real & z()
Returns reference of the third element of Vector3.
Real & x()
Returns reference of the first element of Vector3.
Real & y()
Returns reference of the second element of Vector3.
void zero()
Zeros out the values in this vector in place.
Real length()
Returns the length of this vector.
void Vmul(const Vector< Real, Dim > &v1, const Vector< Real, Dim > &v2)
Sets the elements of this vector to the multiplication of elements of two other vectors.
Real lengthSquare()
Returns the squared length of this vector.
void Vdiv(const Vector< Real, Dim > &v1, const Vector< Real, Dim > &v2)
Sets the elements of this vector to the division of elements of two other vectors.
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.
Vector3< Real > cross(const Vector3< Real > &v1, const Vector3< Real > &v2)
Returns the cross product of two Vectors.
Real dot(const DynamicVector< Real > &v1, const DynamicVector< Real > &v2)
Returns the dot product of two DynamicVectors.
ElectrostaticSummationMethod
@ esm_EWALD_SPME
SPME Ewald methods aren't supported yet.
@ esm_EWALD_PME
PME Ewald methods aren't supported yet.
Vector< Real, Row > mCross(const RectMatrix< Real, Row, Col > &t1, const RectMatrix< Real, Row, Col > &t2)
Returns the vector (cross) product of two matrices.
@ ELECTROSTATIC_FAMILY
Coulombic and point-multipole interactions.
The InteractionData struct.
Vector3d d
interatomic vector (already wrapped into box)
RealType sPot2
site potential on second atom
Vector3d D_1
dipole vector of first atom
RealType skippedCharge1
charge skipped on atom1 in pairwise interaction loop with atom2
RealType dVdFQ1
fluctuating charge force on atom1
RealType dVdFQ2
fluctuating charge force on atom2
RealType electroMult
multiplier for electrostatic interactions
int atid1
atomType ident for atom 1
potVec pot
total potential
potVec selePot
potential energies of the selected sites
RealType flucQ2
fluctuating charge on atom2
bool excluded
is this excluded from direct pairwise interactions? (some indirect interactions may still apply)
RealType sw
switching function value at rij
Vector3d eField1
electric field on first atom
bool isSelected
one of the particles has been selected for selection potential
bool doElectricField
should we bother with the electric field?
RealType flucQ1
fluctuating charge on atom1
Mat3x3d Q_2
quadrupole tensor of first atom
Vector3d eField2
electric field on second atom
Vector3d t1
torque on first atom
Vector3d t2
torque on second atom
RealType vpair
pair potential
RealType sPot1
site potential on first atom
int atid2
atomType ident for atom 2
bool doSitePotential
should we bother with electrostatic site potential
Vector3d D_2
dipole vector of first atom
RealType skippedCharge2
charge skipped on atom2 in pairwise interaction loop with atom1
potVec excludedPot
potential energy excluded from the overall calculation
Mat3x3d Q_1
quadrupole tensor of first atom
Vector3d f1
force between the two atoms
RealType rij
interatomic separation
potVec selePot
potential energy of the selected site
RealType flucQfrc
fluctuating charge derivative
potVec selfPot
total potential (including embedding energy)
RealType particlePot
contribution to potential from this particle
bool isSelected
this site has been selected for selection potential
RealType flucQ
current value of atom's fluctuating charge
RealType skippedCharge
charge skipped in pairwise interaction loop
bool doParticlePot
should we bother with the particle pot?
int atid
atomType ident for the atom