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