ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/branches/development/src/nonbonded/Electrostatic.cpp
Revision: 1766
Committed: Thu Jul 5 17:08:25 2012 UTC (12 years, 10 months ago) by gezelter
File size: 38883 byte(s)
Log Message:
Added Fluctuating Charge Langevin propagator, and made it the default
fixed some errors on the one-center slater coulomb integrals, and some
parameters in PhysicalConstants.


File Contents

# User Rev Content
1 gezelter 1502 /*
2     * Copyright (c) 2005 The University of Notre Dame. All Rights Reserved.
3     *
4     * The University of Notre Dame grants you ("Licensee") a
5     * non-exclusive, royalty free, license to use, modify and
6     * redistribute this software in source and binary code form, provided
7     * that the following conditions are met:
8     *
9     * 1. Redistributions of source code must retain the above copyright
10     * notice, this list of conditions and the following disclaimer.
11     *
12     * 2. Redistributions in binary form must reproduce the above copyright
13     * notice, this list of conditions and the following disclaimer in the
14     * documentation and/or other materials provided with the
15     * distribution.
16     *
17     * This software is provided "AS IS," without a warranty of any
18     * kind. All express or implied conditions, representations and
19     * warranties, including any implied warranty of merchantability,
20     * fitness for a particular purpose or non-infringement, are hereby
21     * excluded. The University of Notre Dame and its licensors shall not
22     * be liable for any damages suffered by licensee as a result of
23     * using, modifying or distributing the software or its
24     * derivatives. In no event will the University of Notre Dame or its
25     * licensors be liable for any lost revenue, profit or data, or for
26     * direct, indirect, special, consequential, incidental or punitive
27     * damages, however caused and regardless of the theory of liability,
28     * arising out of the use of or inability to use software, even if the
29     * University of Notre Dame has been advised of the possibility of
30     * such damages.
31     *
32     * SUPPORT OPEN SCIENCE! If you use OpenMD or its source code in your
33     * research, please cite the appropriate papers when you publish your
34     * work. Good starting points are:
35     *
36     * [1] Meineke, et al., J. Comp. Chem. 26, 252-271 (2005).
37 gezelter 1587 * [2] Fennell & Gezelter, J. Chem. Phys. 124 234104 (2006).
38 gezelter 1502 * [3] Sun, Lin & Gezelter, J. Chem. Phys. 128, 24107 (2008).
39 gezelter 1665 * [4] Kuang & Gezelter, J. Chem. Phys. 133, 164101 (2010).
40     * [5] Vardeman, Stocker & Gezelter, J. Chem. Theory Comput. 7, 834 (2011).
41 gezelter 1502 */
42    
43     #include <stdio.h>
44     #include <string.h>
45    
46     #include <cmath>
47     #include "nonbonded/Electrostatic.hpp"
48     #include "utils/simError.h"
49     #include "types/NonBondedInteractionType.hpp"
50 gezelter 1710 #include "types/FixedChargeAdapter.hpp"
51 gezelter 1720 #include "types/FluctuatingChargeAdapter.hpp"
52 gezelter 1710 #include "types/MultipoleAdapter.hpp"
53 gezelter 1535 #include "io/Globals.hpp"
54 gezelter 1718 #include "nonbonded/SlaterIntegrals.hpp"
55     #include "utils/PhysicalConstants.hpp"
56 gezelter 1502
57 gezelter 1718
58 gezelter 1502 namespace OpenMD {
59    
60     Electrostatic::Electrostatic(): name_("Electrostatic"), initialized_(false),
61 gezelter 1587 forceField_(NULL), info_(NULL),
62     haveCutoffRadius_(false),
63     haveDampingAlpha_(false),
64     haveDielectric_(false),
65 gezelter 1586 haveElectroSpline_(false)
66 gezelter 1587 {}
67 gezelter 1502
68     void Electrostatic::initialize() {
69 gezelter 1587
70 gezelter 1584 Globals* simParams_ = info_->getSimParams();
71 gezelter 1535
72 gezelter 1528 summationMap_["HARD"] = esm_HARD;
73 gezelter 1616 summationMap_["NONE"] = esm_HARD;
74 gezelter 1528 summationMap_["SWITCHING_FUNCTION"] = esm_SWITCHING_FUNCTION;
75     summationMap_["SHIFTED_POTENTIAL"] = esm_SHIFTED_POTENTIAL;
76     summationMap_["SHIFTED_FORCE"] = esm_SHIFTED_FORCE;
77     summationMap_["REACTION_FIELD"] = esm_REACTION_FIELD;
78     summationMap_["EWALD_FULL"] = esm_EWALD_FULL;
79     summationMap_["EWALD_PME"] = esm_EWALD_PME;
80     summationMap_["EWALD_SPME"] = esm_EWALD_SPME;
81     screeningMap_["DAMPED"] = DAMPED;
82     screeningMap_["UNDAMPED"] = UNDAMPED;
83    
84 gezelter 1502 // these prefactors convert the multipole interactions into kcal / mol
85     // all were computed assuming distances are measured in angstroms
86     // Charge-Charge, assuming charges are measured in electrons
87     pre11_ = 332.0637778;
88     // Charge-Dipole, assuming charges are measured in electrons, and
89     // dipoles are measured in debyes
90     pre12_ = 69.13373;
91     // Dipole-Dipole, assuming dipoles are measured in debyes
92     pre22_ = 14.39325;
93     // Charge-Quadrupole, assuming charges are measured in electrons, and
94     // quadrupoles are measured in 10^-26 esu cm^2
95     // This unit is also known affectionately as an esu centi-barn.
96     pre14_ = 69.13373;
97    
98     // conversions for the simulation box dipole moment
99     chargeToC_ = 1.60217733e-19;
100     angstromToM_ = 1.0e-10;
101     debyeToCm_ = 3.33564095198e-30;
102    
103     // number of points for electrostatic splines
104     np_ = 100;
105    
106     // variables to handle different summation methods for long-range
107     // electrostatics:
108 gezelter 1528 summationMethod_ = esm_HARD;
109 gezelter 1502 screeningMethod_ = UNDAMPED;
110     dielectric_ = 1.0;
111     one_third_ = 1.0 / 3.0;
112    
113 gezelter 1528 // check the summation method:
114     if (simParams_->haveElectrostaticSummationMethod()) {
115     string myMethod = simParams_->getElectrostaticSummationMethod();
116     toUpper(myMethod);
117     map<string, ElectrostaticSummationMethod>::iterator i;
118     i = summationMap_.find(myMethod);
119     if ( i != summationMap_.end() ) {
120     summationMethod_ = (*i).second;
121     } else {
122     // throw error
123     sprintf( painCave.errMsg,
124 gezelter 1536 "Electrostatic::initialize: Unknown electrostaticSummationMethod.\n"
125 gezelter 1528 "\t(Input file specified %s .)\n"
126 gezelter 1616 "\telectrostaticSummationMethod must be one of: \"hard\",\n"
127 gezelter 1528 "\t\"shifted_potential\", \"shifted_force\", or \n"
128     "\t\"reaction_field\".\n", myMethod.c_str() );
129     painCave.isFatal = 1;
130     simError();
131     }
132     } else {
133     // set ElectrostaticSummationMethod to the cutoffMethod:
134     if (simParams_->haveCutoffMethod()){
135     string myMethod = simParams_->getCutoffMethod();
136     toUpper(myMethod);
137     map<string, ElectrostaticSummationMethod>::iterator i;
138     i = summationMap_.find(myMethod);
139     if ( i != summationMap_.end() ) {
140     summationMethod_ = (*i).second;
141     }
142     }
143     }
144    
145     if (summationMethod_ == esm_REACTION_FIELD) {
146     if (!simParams_->haveDielectric()) {
147     // throw warning
148     sprintf( painCave.errMsg,
149     "SimInfo warning: dielectric was not specified in the input file\n\tfor the reaction field correction method.\n"
150     "\tA default value of %f will be used for the dielectric.\n", dielectric_);
151     painCave.isFatal = 0;
152     painCave.severity = OPENMD_INFO;
153     simError();
154     } else {
155     dielectric_ = simParams_->getDielectric();
156     }
157     haveDielectric_ = true;
158     }
159    
160     if (simParams_->haveElectrostaticScreeningMethod()) {
161     string myScreen = simParams_->getElectrostaticScreeningMethod();
162     toUpper(myScreen);
163     map<string, ElectrostaticScreeningMethod>::iterator i;
164     i = screeningMap_.find(myScreen);
165     if ( i != screeningMap_.end()) {
166     screeningMethod_ = (*i).second;
167     } else {
168     sprintf( painCave.errMsg,
169     "SimInfo error: Unknown electrostaticScreeningMethod.\n"
170     "\t(Input file specified %s .)\n"
171     "\telectrostaticScreeningMethod must be one of: \"undamped\"\n"
172     "or \"damped\".\n", myScreen.c_str() );
173     painCave.isFatal = 1;
174     simError();
175     }
176     }
177    
178     // check to make sure a cutoff value has been set:
179     if (!haveCutoffRadius_) {
180     sprintf( painCave.errMsg, "Electrostatic::initialize has no Default "
181     "Cutoff value!\n");
182     painCave.severity = OPENMD_ERROR;
183     painCave.isFatal = 1;
184     simError();
185     }
186    
187     if (screeningMethod_ == DAMPED) {
188     if (!simParams_->haveDampingAlpha()) {
189     // first set a cutoff dependent alpha value
190     // we assume alpha depends linearly with rcut from 0 to 20.5 ang
191     dampingAlpha_ = 0.425 - cutoffRadius_* 0.02;
192     if (dampingAlpha_ < 0.0) dampingAlpha_ = 0.0;
193    
194     // throw warning
195     sprintf( painCave.errMsg,
196 gezelter 1750 "Electrostatic::initialize: dampingAlpha was not specified in the\n"
197     "\tinput file. A default value of %f (1/ang) will be used for the\n"
198     "\tcutoff of %f (ang).\n",
199 gezelter 1528 dampingAlpha_, cutoffRadius_);
200     painCave.severity = OPENMD_INFO;
201     painCave.isFatal = 0;
202     simError();
203     } else {
204     dampingAlpha_ = simParams_->getDampingAlpha();
205     }
206     haveDampingAlpha_ = true;
207     }
208    
209 gezelter 1502 // find all of the Electrostatic atom Types:
210     ForceField::AtomTypeContainer* atomTypes = forceField_->getAtomTypes();
211     ForceField::AtomTypeContainer::MapTypeIterator i;
212     AtomType* at;
213 gezelter 1528
214 gezelter 1502 for (at = atomTypes->beginType(i); at != NULL;
215     at = atomTypes->nextType(i)) {
216    
217     if (at->isElectrostatic())
218     addType(at);
219     }
220    
221 gezelter 1528 cutoffRadius2_ = cutoffRadius_ * cutoffRadius_;
222     rcuti_ = 1.0 / cutoffRadius_;
223 gezelter 1502 rcuti2_ = rcuti_ * rcuti_;
224     rcuti3_ = rcuti2_ * rcuti_;
225     rcuti4_ = rcuti2_ * rcuti2_;
226    
227     if (screeningMethod_ == DAMPED) {
228 gezelter 1528
229 gezelter 1502 alpha2_ = dampingAlpha_ * dampingAlpha_;
230     alpha4_ = alpha2_ * alpha2_;
231     alpha6_ = alpha4_ * alpha2_;
232     alpha8_ = alpha4_ * alpha4_;
233    
234 gezelter 1528 constEXP_ = exp(-alpha2_ * cutoffRadius2_);
235 gezelter 1502 invRootPi_ = 0.56418958354775628695;
236     alphaPi_ = 2.0 * dampingAlpha_ * invRootPi_;
237    
238 gezelter 1528 c1c_ = erfc(dampingAlpha_ * cutoffRadius_) * rcuti_;
239 gezelter 1502 c2c_ = alphaPi_ * constEXP_ * rcuti_ + c1c_ * rcuti_;
240     c3c_ = 2.0 * alphaPi_ * alpha2_ + 3.0 * c2c_ * rcuti_;
241     c4c_ = 4.0 * alphaPi_ * alpha4_ + 5.0 * c3c_ * rcuti2_;
242     c5c_ = 8.0 * alphaPi_ * alpha6_ + 7.0 * c4c_ * rcuti2_;
243     c6c_ = 16.0 * alphaPi_ * alpha8_ + 9.0 * c5c_ * rcuti2_;
244     } else {
245     c1c_ = rcuti_;
246     c2c_ = c1c_ * rcuti_;
247     c3c_ = 3.0 * c2c_ * rcuti_;
248     c4c_ = 5.0 * c3c_ * rcuti2_;
249     c5c_ = 7.0 * c4c_ * rcuti2_;
250     c6c_ = 9.0 * c5c_ * rcuti2_;
251     }
252    
253 gezelter 1528 if (summationMethod_ == esm_REACTION_FIELD) {
254     preRF_ = (dielectric_ - 1.0) /
255     ((2.0 * dielectric_ + 1.0) * cutoffRadius2_ * cutoffRadius_);
256     preRF2_ = 2.0 * preRF_;
257 gezelter 1502 }
258 gezelter 1528
259 gezelter 1613 // Add a 2 angstrom safety window to deal with cutoffGroups that
260     // have charged atoms longer than the cutoffRadius away from each
261     // other. Splining may not be the best choice here. Direct calls
262     // to erfc might be preferrable.
263    
264     RealType dx = (cutoffRadius_ + 2.0) / RealType(np_ - 1);
265 gezelter 1502 RealType rval;
266     vector<RealType> rvals;
267     vector<RealType> yvals;
268     for (int i = 0; i < np_; i++) {
269     rval = RealType(i) * dx;
270     rvals.push_back(rval);
271     yvals.push_back(erfc(dampingAlpha_ * rval));
272     }
273     erfcSpline_ = new CubicSpline();
274     erfcSpline_->addPoints(rvals, yvals);
275     haveElectroSpline_ = true;
276    
277     initialized_ = true;
278     }
279    
280     void Electrostatic::addType(AtomType* atomType){
281    
282     ElectrostaticAtomData electrostaticAtomData;
283     electrostaticAtomData.is_Charge = false;
284     electrostaticAtomData.is_Dipole = false;
285     electrostaticAtomData.is_SplitDipole = false;
286     electrostaticAtomData.is_Quadrupole = false;
287 gezelter 1723 electrostaticAtomData.is_Fluctuating = false;
288 gezelter 1502
289 gezelter 1710 FixedChargeAdapter fca = FixedChargeAdapter(atomType);
290 gezelter 1502
291 gezelter 1710 if (fca.isFixedCharge()) {
292 gezelter 1502 electrostaticAtomData.is_Charge = true;
293 gezelter 1720 electrostaticAtomData.fixedCharge = fca.getCharge();
294 gezelter 1502 }
295    
296 gezelter 1710 MultipoleAdapter ma = MultipoleAdapter(atomType);
297     if (ma.isMultipole()) {
298     if (ma.isDipole()) {
299 gezelter 1502 electrostaticAtomData.is_Dipole = true;
300 gezelter 1710 electrostaticAtomData.dipole_moment = ma.getDipoleMoment();
301 gezelter 1502 }
302 gezelter 1710 if (ma.isSplitDipole()) {
303 gezelter 1502 electrostaticAtomData.is_SplitDipole = true;
304 gezelter 1710 electrostaticAtomData.split_dipole_distance = ma.getSplitDipoleDistance();
305 gezelter 1502 }
306 gezelter 1710 if (ma.isQuadrupole()) {
307 gezelter 1505 // Quadrupoles in OpenMD are set as the diagonal elements
308     // of the diagonalized traceless quadrupole moment tensor.
309     // The column vectors of the unitary matrix that diagonalizes
310     // the quadrupole moment tensor become the eFrame (or the
311     // electrostatic version of the body-fixed frame.
312 gezelter 1502 electrostaticAtomData.is_Quadrupole = true;
313 gezelter 1710 electrostaticAtomData.quadrupole_moments = ma.getQuadrupoleMoments();
314 gezelter 1502 }
315     }
316    
317 gezelter 1718 FluctuatingChargeAdapter fqa = FluctuatingChargeAdapter(atomType);
318 gezelter 1502
319 gezelter 1718 if (fqa.isFluctuatingCharge()) {
320 gezelter 1720 electrostaticAtomData.is_Fluctuating = true;
321     electrostaticAtomData.electronegativity = fqa.getElectronegativity();
322     electrostaticAtomData.hardness = fqa.getHardness();
323     electrostaticAtomData.slaterN = fqa.getSlaterN();
324     electrostaticAtomData.slaterZeta = fqa.getSlaterZeta();
325 gezelter 1718 }
326    
327 gezelter 1502 pair<map<int,AtomType*>::iterator,bool> ret;
328 gezelter 1710 ret = ElectrostaticList.insert( pair<int,AtomType*>(atomType->getIdent(),
329     atomType) );
330 gezelter 1502 if (ret.second == false) {
331     sprintf( painCave.errMsg,
332     "Electrostatic already had a previous entry with ident %d\n",
333 gezelter 1710 atomType->getIdent() );
334 gezelter 1502 painCave.severity = OPENMD_INFO;
335     painCave.isFatal = 0;
336     simError();
337     }
338    
339 gezelter 1718 ElectrostaticMap[atomType] = electrostaticAtomData;
340    
341     // Now, iterate over all known types and add to the mixing map:
342    
343     map<AtomType*, ElectrostaticAtomData>::iterator it;
344     for( it = ElectrostaticMap.begin(); it != ElectrostaticMap.end(); ++it) {
345     AtomType* atype2 = (*it).first;
346 gezelter 1720 ElectrostaticAtomData eaData2 = (*it).second;
347     if (eaData2.is_Fluctuating && electrostaticAtomData.is_Fluctuating) {
348 gezelter 1718
349     RealType a = electrostaticAtomData.slaterZeta;
350 gezelter 1720 RealType b = eaData2.slaterZeta;
351 gezelter 1718 int m = electrostaticAtomData.slaterN;
352 gezelter 1720 int n = eaData2.slaterN;
353 gezelter 1718
354     // Create the spline of the coulombic integral for s-type
355     // Slater orbitals. Add a 2 angstrom safety window to deal
356     // with cutoffGroups that have charged atoms longer than the
357     // cutoffRadius away from each other.
358    
359 gezelter 1720 RealType rval;
360 gezelter 1718 RealType dr = (cutoffRadius_ + 2.0) / RealType(np_ - 1);
361     vector<RealType> rvals;
362     vector<RealType> J1vals;
363     vector<RealType> J2vals;
364 gezelter 1761 // don't start at i = 0, as rval = 0 is undefined for the slater overlap integrals.
365     for (int i = 1; i < np_+1; i++) {
366 gezelter 1718 rval = RealType(i) * dr;
367     rvals.push_back(rval);
368 gezelter 1766 J1vals.push_back(sSTOCoulInt( a, b, m, n, rval * PhysicalConstants::angstromToBohr ) * PhysicalConstants::hartreeToKcal );
369 gezelter 1721 // may not be necessary if Slater coulomb integral is symmetric
370 gezelter 1766 J2vals.push_back(sSTOCoulInt( b, a, n, m, rval * PhysicalConstants::angstromToBohr ) * PhysicalConstants::hartreeToKcal );
371 gezelter 1718 }
372    
373 gezelter 1720 CubicSpline* J1 = new CubicSpline();
374 gezelter 1718 J1->addPoints(rvals, J1vals);
375 gezelter 1720 CubicSpline* J2 = new CubicSpline();
376 gezelter 1718 J2->addPoints(rvals, J2vals);
377    
378     pair<AtomType*, AtomType*> key1, key2;
379     key1 = make_pair(atomType, atype2);
380     key2 = make_pair(atype2, atomType);
381    
382     Jij[key1] = J1;
383     Jij[key2] = J2;
384     }
385     }
386    
387 gezelter 1502 return;
388     }
389    
390 gezelter 1584 void Electrostatic::setCutoffRadius( RealType rCut ) {
391     cutoffRadius_ = rCut;
392 gezelter 1528 rrf_ = cutoffRadius_;
393     haveCutoffRadius_ = true;
394 gezelter 1502 }
395 gezelter 1584
396     void Electrostatic::setSwitchingRadius( RealType rSwitch ) {
397     rt_ = rSwitch;
398     }
399 gezelter 1502 void Electrostatic::setElectrostaticSummationMethod( ElectrostaticSummationMethod esm ) {
400     summationMethod_ = esm;
401     }
402     void Electrostatic::setElectrostaticScreeningMethod( ElectrostaticScreeningMethod sm ) {
403     screeningMethod_ = sm;
404     }
405     void Electrostatic::setDampingAlpha( RealType alpha ) {
406     dampingAlpha_ = alpha;
407     haveDampingAlpha_ = true;
408     }
409     void Electrostatic::setReactionFieldDielectric( RealType dielectric ){
410     dielectric_ = dielectric;
411     haveDielectric_ = true;
412     }
413    
414 gezelter 1536 void Electrostatic::calcForce(InteractionData &idat) {
415 gezelter 1502
416     // utility variables. Should clean these up and use the Vector3d and
417     // Mat3x3d to replace as many as we can in future versions:
418    
419     RealType q_i, q_j, mu_i, mu_j, d_i, d_j;
420     RealType qxx_i, qyy_i, qzz_i;
421     RealType qxx_j, qyy_j, qzz_j;
422     RealType cx_i, cy_i, cz_i;
423     RealType cx_j, cy_j, cz_j;
424     RealType cx2, cy2, cz2;
425     RealType ct_i, ct_j, ct_ij, a1;
426     RealType riji, ri, ri2, ri3, ri4;
427     RealType pref, vterm, epot, dudr;
428 gezelter 1587 RealType vpair(0.0);
429 gezelter 1502 RealType scale, sc2;
430     RealType pot_term, preVal, rfVal;
431     RealType c2ri, c3ri, c4rij, cti3, ctj3, ctidotj;
432     RealType preSw, preSwSc;
433     RealType c1, c2, c3, c4;
434 gezelter 1587 RealType erfcVal(1.0), derfcVal(0.0);
435 gezelter 1502 RealType BigR;
436 gezelter 1668 RealType two(2.0), three(3.0);
437 gezelter 1502
438     Vector3d Q_i, Q_j;
439     Vector3d ux_i, uy_i, uz_i;
440     Vector3d ux_j, uy_j, uz_j;
441     Vector3d dudux_i, duduy_i, duduz_i;
442     Vector3d dudux_j, duduy_j, duduz_j;
443     Vector3d rhatdot2, rhatc4;
444     Vector3d dVdr;
445    
446 gezelter 1587 // variables for indirect (reaction field) interactions for excluded pairs:
447     RealType indirect_Pot(0.0);
448     RealType indirect_vpair(0.0);
449     Vector3d indirect_dVdr(V3Zero);
450     Vector3d indirect_duduz_i(V3Zero), indirect_duduz_j(V3Zero);
451    
452 gezelter 1723 RealType coulInt, vFluc1(0.0), vFluc2(0.0);
453 gezelter 1502 pair<RealType, RealType> res;
454    
455 gezelter 1721 // splines for coulomb integrals
456     CubicSpline* J1;
457     CubicSpline* J2;
458    
459 gezelter 1502 if (!initialized_) initialize();
460    
461 gezelter 1571 ElectrostaticAtomData data1 = ElectrostaticMap[idat.atypes.first];
462     ElectrostaticAtomData data2 = ElectrostaticMap[idat.atypes.second];
463 gezelter 1502
464     // some variables we'll need independent of electrostatic type:
465    
466 gezelter 1554 riji = 1.0 / *(idat.rij) ;
467     Vector3d rhat = *(idat.d) * riji;
468 gezelter 1502
469     // logicals
470    
471     bool i_is_Charge = data1.is_Charge;
472     bool i_is_Dipole = data1.is_Dipole;
473     bool i_is_SplitDipole = data1.is_SplitDipole;
474     bool i_is_Quadrupole = data1.is_Quadrupole;
475 gezelter 1721 bool i_is_Fluctuating = data1.is_Fluctuating;
476 gezelter 1502
477     bool j_is_Charge = data2.is_Charge;
478     bool j_is_Dipole = data2.is_Dipole;
479     bool j_is_SplitDipole = data2.is_SplitDipole;
480     bool j_is_Quadrupole = data2.is_Quadrupole;
481 gezelter 1721 bool j_is_Fluctuating = data2.is_Fluctuating;
482 gezelter 1502
483 gezelter 1587 if (i_is_Charge) {
484 gezelter 1720 q_i = data1.fixedCharge;
485 gezelter 1721
486     if (i_is_Fluctuating) {
487     q_i += *(idat.flucQ1);
488     }
489    
490 gezelter 1587 if (idat.excluded) {
491     *(idat.skippedCharge2) += q_i;
492     }
493     }
494 gezelter 1502
495     if (i_is_Dipole) {
496     mu_i = data1.dipole_moment;
497 gezelter 1554 uz_i = idat.eFrame1->getColumn(2);
498 gezelter 1502
499     ct_i = dot(uz_i, rhat);
500    
501     if (i_is_SplitDipole)
502     d_i = data1.split_dipole_distance;
503    
504     duduz_i = V3Zero;
505     }
506    
507     if (i_is_Quadrupole) {
508     Q_i = data1.quadrupole_moments;
509     qxx_i = Q_i.x();
510     qyy_i = Q_i.y();
511     qzz_i = Q_i.z();
512    
513 gezelter 1554 ux_i = idat.eFrame1->getColumn(0);
514     uy_i = idat.eFrame1->getColumn(1);
515     uz_i = idat.eFrame1->getColumn(2);
516 gezelter 1502
517     cx_i = dot(ux_i, rhat);
518     cy_i = dot(uy_i, rhat);
519     cz_i = dot(uz_i, rhat);
520    
521     dudux_i = V3Zero;
522     duduy_i = V3Zero;
523     duduz_i = V3Zero;
524     }
525    
526 gezelter 1587 if (j_is_Charge) {
527 gezelter 1720 q_j = data2.fixedCharge;
528 gezelter 1721
529 jmichalk 1734 if (j_is_Fluctuating)
530 gezelter 1721 q_j += *(idat.flucQ2);
531    
532 gezelter 1587 if (idat.excluded) {
533     *(idat.skippedCharge1) += q_j;
534     }
535     }
536 gezelter 1502
537 gezelter 1587
538 gezelter 1502 if (j_is_Dipole) {
539     mu_j = data2.dipole_moment;
540 gezelter 1554 uz_j = idat.eFrame2->getColumn(2);
541 gezelter 1502
542     ct_j = dot(uz_j, rhat);
543    
544     if (j_is_SplitDipole)
545     d_j = data2.split_dipole_distance;
546    
547     duduz_j = V3Zero;
548     }
549    
550     if (j_is_Quadrupole) {
551     Q_j = data2.quadrupole_moments;
552     qxx_j = Q_j.x();
553     qyy_j = Q_j.y();
554     qzz_j = Q_j.z();
555    
556 gezelter 1554 ux_j = idat.eFrame2->getColumn(0);
557     uy_j = idat.eFrame2->getColumn(1);
558     uz_j = idat.eFrame2->getColumn(2);
559 gezelter 1502
560     cx_j = dot(ux_j, rhat);
561     cy_j = dot(uy_j, rhat);
562     cz_j = dot(uz_j, rhat);
563    
564     dudux_j = V3Zero;
565     duduy_j = V3Zero;
566     duduz_j = V3Zero;
567     }
568    
569 gezelter 1721 if (i_is_Fluctuating && j_is_Fluctuating) {
570     J1 = Jij[idat.atypes];
571     J2 = Jij[make_pair(idat.atypes.second, idat.atypes.first)];
572     }
573    
574 gezelter 1502 epot = 0.0;
575     dVdr = V3Zero;
576    
577     if (i_is_Charge) {
578    
579     if (j_is_Charge) {
580     if (screeningMethod_ == DAMPED) {
581     // assemble the damping variables
582 gezelter 1756 res = erfcSpline_->getValueAndDerivativeAt( *(idat.rij) );
583     erfcVal = res.first;
584     derfcVal = res.second;
585 gezelter 1616
586 gezelter 1756 //erfcVal = erfc(dampingAlpha_ * *(idat.rij));
587     //derfcVal = - alphaPi_ * exp(-alpha2_ * *(idat.r2));
588 gezelter 1616
589 gezelter 1502 c1 = erfcVal * riji;
590     c2 = (-derfcVal + c1) * riji;
591     } else {
592     c1 = riji;
593     c2 = c1 * riji;
594     }
595    
596 jmichalk 1734 preVal = *(idat.electroMult) * pre11_;
597 gezelter 1502
598 gezelter 1528 if (summationMethod_ == esm_SHIFTED_POTENTIAL) {
599 gezelter 1502 vterm = preVal * (c1 - c1c_);
600 gezelter 1554 dudr = - *(idat.sw) * preVal * c2;
601 gezelter 1502
602 gezelter 1528 } else if (summationMethod_ == esm_SHIFTED_FORCE) {
603 gezelter 1554 vterm = preVal * ( c1 - c1c_ + c2c_*( *(idat.rij) - cutoffRadius_) );
604     dudr = *(idat.sw) * preVal * (c2c_ - c2);
605 gezelter 1502
606 gezelter 1528 } else if (summationMethod_ == esm_REACTION_FIELD) {
607 gezelter 1587 rfVal = preRF_ * *(idat.rij) * *(idat.rij);
608    
609 gezelter 1502 vterm = preVal * ( riji + rfVal );
610 gezelter 1554 dudr = *(idat.sw) * preVal * ( 2.0 * rfVal - riji ) * riji;
611 gezelter 1587
612     // if this is an excluded pair, there are still indirect
613     // interactions via the reaction field we must worry about:
614 gezelter 1502
615 gezelter 1587 if (idat.excluded) {
616     indirect_vpair += preVal * rfVal;
617     indirect_Pot += *(idat.sw) * preVal * rfVal;
618 gezelter 1668 indirect_dVdr += *(idat.sw) * preVal * two * rfVal * riji * rhat;
619 gezelter 1587 }
620    
621 gezelter 1502 } else {
622    
623 gezelter 1587 vterm = preVal * riji * erfcVal;
624 gezelter 1554 dudr = - *(idat.sw) * preVal * c2;
625 gezelter 1721
626     }
627 gezelter 1723
628 jmichalk 1734 vpair += vterm * q_i * q_j;
629     epot += *(idat.sw) * vterm * q_i * q_j;
630     dVdr += dudr * rhat * q_i * q_j;
631 gezelter 1502
632 gezelter 1721 if (i_is_Fluctuating) {
633 gezelter 1723 if (idat.excluded) {
634     // vFluc1 is the difference between the direct coulomb integral
635     // and the normal 1/r-like interaction between point charges.
636     coulInt = J1->getValueAt( *(idat.rij) );
637 jmichalk 1734 vFluc1 = coulInt - (*(idat.sw) * vterm);
638 gezelter 1723 } else {
639     vFluc1 = 0.0;
640 gezelter 1721 }
641 jmichalk 1734 *(idat.dVdFQ1) += ( *(idat.sw) * vterm + vFluc1 ) * q_j;
642 gezelter 1502 }
643 gezelter 1723
644 gezelter 1721 if (j_is_Fluctuating) {
645 gezelter 1723 if (idat.excluded) {
646     // vFluc2 is the difference between the direct coulomb integral
647     // and the normal 1/r-like interaction between point charges.
648     coulInt = J2->getValueAt( *(idat.rij) );
649 jmichalk 1734 vFluc2 = coulInt - (*(idat.sw) * vterm);
650 gezelter 1723 } else {
651     vFluc2 = 0.0;
652 gezelter 1721 }
653 jmichalk 1734 *(idat.dVdFQ2) += ( *(idat.sw) * vterm + vFluc2 ) * q_i;
654 gezelter 1721 }
655 gezelter 1723
656    
657 gezelter 1502 }
658    
659     if (j_is_Dipole) {
660     // pref is used by all the possible methods
661 gezelter 1554 pref = *(idat.electroMult) * pre12_ * q_i * mu_j;
662     preSw = *(idat.sw) * pref;
663 gezelter 1502
664 gezelter 1528 if (summationMethod_ == esm_REACTION_FIELD) {
665 gezelter 1502 ri2 = riji * riji;
666     ri3 = ri2 * riji;
667    
668 gezelter 1554 vterm = - pref * ct_j * ( ri2 - preRF2_ * *(idat.rij) );
669 gezelter 1587 vpair += vterm;
670 gezelter 1554 epot += *(idat.sw) * vterm;
671 gezelter 1502
672 gezelter 1668 dVdr += -preSw * (ri3 * (uz_j - three * ct_j * rhat) - preRF2_*uz_j);
673 gezelter 1554 duduz_j += -preSw * rhat * (ri2 - preRF2_ * *(idat.rij) );
674 gezelter 1502
675 gezelter 1587 // Even if we excluded this pair from direct interactions,
676     // we still have the reaction-field-mediated charge-dipole
677     // interaction:
678    
679     if (idat.excluded) {
680     indirect_vpair += pref * ct_j * preRF2_ * *(idat.rij);
681     indirect_Pot += preSw * ct_j * preRF2_ * *(idat.rij);
682     indirect_dVdr += preSw * preRF2_ * uz_j;
683     indirect_duduz_j += preSw * rhat * preRF2_ * *(idat.rij);
684     }
685    
686 gezelter 1502 } else {
687     // determine the inverse r used if we have split dipoles
688     if (j_is_SplitDipole) {
689 gezelter 1554 BigR = sqrt( *(idat.r2) + 0.25 * d_j * d_j);
690 gezelter 1502 ri = 1.0 / BigR;
691 gezelter 1554 scale = *(idat.rij) * ri;
692 gezelter 1502 } else {
693     ri = riji;
694     scale = 1.0;
695     }
696    
697     sc2 = scale * scale;
698    
699     if (screeningMethod_ == DAMPED) {
700     // assemble the damping variables
701 gezelter 1616 //res = erfcSpline_->getValueAndDerivativeAt( *(idat.rij) );
702     //erfcVal = res.first;
703     //derfcVal = res.second;
704     erfcVal = erfc(dampingAlpha_ * *(idat.rij));
705     derfcVal = - alphaPi_ * exp(-alpha2_ * *(idat.r2));
706 gezelter 1502 c1 = erfcVal * ri;
707     c2 = (-derfcVal + c1) * ri;
708     c3 = -2.0 * derfcVal * alpha2_ + 3.0 * c2 * ri;
709     } else {
710     c1 = ri;
711     c2 = c1 * ri;
712     c3 = 3.0 * c2 * ri;
713     }
714    
715     c2ri = c2 * ri;
716    
717     // calculate the potential
718     pot_term = scale * c2;
719     vterm = -pref * ct_j * pot_term;
720 gezelter 1587 vpair += vterm;
721 gezelter 1554 epot += *(idat.sw) * vterm;
722 gezelter 1502
723     // calculate derivatives for forces and torques
724    
725     dVdr += -preSw * (uz_j * c2ri - ct_j * rhat * sc2 * c3);
726     duduz_j += -preSw * pot_term * rhat;
727    
728     }
729 gezelter 1723 if (i_is_Fluctuating) {
730     *(idat.dVdFQ1) += ( *(idat.sw) * vterm ) / q_i;
731     }
732 gezelter 1502 }
733    
734     if (j_is_Quadrupole) {
735     // first precalculate some necessary variables
736     cx2 = cx_j * cx_j;
737     cy2 = cy_j * cy_j;
738     cz2 = cz_j * cz_j;
739 gezelter 1554 pref = *(idat.electroMult) * pre14_ * q_i * one_third_;
740 gezelter 1502
741     if (screeningMethod_ == DAMPED) {
742     // assemble the damping variables
743 gezelter 1616 //res = erfcSpline_->getValueAndDerivativeAt( *(idat.rij) );
744     //erfcVal = res.first;
745     //derfcVal = res.second;
746     erfcVal = erfc(dampingAlpha_ * *(idat.rij));
747     derfcVal = - alphaPi_ * exp(-alpha2_ * *(idat.r2));
748 gezelter 1502 c1 = erfcVal * riji;
749     c2 = (-derfcVal + c1) * riji;
750     c3 = -2.0 * derfcVal * alpha2_ + 3.0 * c2 * riji;
751     c4 = -4.0 * derfcVal * alpha4_ + 5.0 * c3 * riji * riji;
752     } else {
753     c1 = riji;
754     c2 = c1 * riji;
755     c3 = 3.0 * c2 * riji;
756     c4 = 5.0 * c3 * riji * riji;
757     }
758    
759     // precompute variables for convenience
760 gezelter 1554 preSw = *(idat.sw) * pref;
761 gezelter 1502 c2ri = c2 * riji;
762     c3ri = c3 * riji;
763 gezelter 1554 c4rij = c4 * *(idat.rij) ;
764 gezelter 1668 rhatdot2 = two * rhat * c3;
765 gezelter 1502 rhatc4 = rhat * c4rij;
766    
767     // calculate the potential
768     pot_term = ( qxx_j * (cx2*c3 - c2ri) +
769     qyy_j * (cy2*c3 - c2ri) +
770     qzz_j * (cz2*c3 - c2ri) );
771     vterm = pref * pot_term;
772 gezelter 1587 vpair += vterm;
773 gezelter 1554 epot += *(idat.sw) * vterm;
774 gezelter 1502
775     // calculate derivatives for the forces and torques
776    
777 gezelter 1668 dVdr += -preSw * ( qxx_j* (cx2*rhatc4 - (two*cx_j*ux_j + rhat)*c3ri) +
778     qyy_j* (cy2*rhatc4 - (two*cy_j*uy_j + rhat)*c3ri) +
779     qzz_j* (cz2*rhatc4 - (two*cz_j*uz_j + rhat)*c3ri));
780 gezelter 1502
781     dudux_j += preSw * qxx_j * cx_j * rhatdot2;
782     duduy_j += preSw * qyy_j * cy_j * rhatdot2;
783     duduz_j += preSw * qzz_j * cz_j * rhatdot2;
784 gezelter 1723 if (i_is_Fluctuating) {
785     *(idat.dVdFQ1) += ( *(idat.sw) * vterm ) / q_i;
786     }
787    
788 gezelter 1502 }
789     }
790    
791     if (i_is_Dipole) {
792    
793     if (j_is_Charge) {
794     // variables used by all the methods
795 gezelter 1554 pref = *(idat.electroMult) * pre12_ * q_j * mu_i;
796     preSw = *(idat.sw) * pref;
797 gezelter 1502
798 gezelter 1528 if (summationMethod_ == esm_REACTION_FIELD) {
799 gezelter 1502
800     ri2 = riji * riji;
801     ri3 = ri2 * riji;
802    
803 gezelter 1554 vterm = pref * ct_i * ( ri2 - preRF2_ * *(idat.rij) );
804 gezelter 1587 vpair += vterm;
805 gezelter 1554 epot += *(idat.sw) * vterm;
806 gezelter 1502
807 gezelter 1668 dVdr += preSw * (ri3 * (uz_i - three * ct_i * rhat) - preRF2_ * uz_i);
808 gezelter 1502
809 gezelter 1554 duduz_i += preSw * rhat * (ri2 - preRF2_ * *(idat.rij) );
810 gezelter 1587
811     // Even if we excluded this pair from direct interactions,
812     // we still have the reaction-field-mediated charge-dipole
813     // interaction:
814    
815     if (idat.excluded) {
816     indirect_vpair += -pref * ct_i * preRF2_ * *(idat.rij);
817     indirect_Pot += -preSw * ct_i * preRF2_ * *(idat.rij);
818     indirect_dVdr += -preSw * preRF2_ * uz_i;
819     indirect_duduz_i += -preSw * rhat * preRF2_ * *(idat.rij);
820     }
821 gezelter 1502
822     } else {
823    
824     // determine inverse r if we are using split dipoles
825     if (i_is_SplitDipole) {
826 gezelter 1554 BigR = sqrt( *(idat.r2) + 0.25 * d_i * d_i);
827 gezelter 1502 ri = 1.0 / BigR;
828 gezelter 1554 scale = *(idat.rij) * ri;
829 gezelter 1502 } else {
830     ri = riji;
831     scale = 1.0;
832     }
833    
834     sc2 = scale * scale;
835    
836     if (screeningMethod_ == DAMPED) {
837     // assemble the damping variables
838 gezelter 1616 //res = erfcSpline_->getValueAndDerivativeAt( *(idat.rij) );
839     //erfcVal = res.first;
840     //derfcVal = res.second;
841     erfcVal = erfc(dampingAlpha_ * *(idat.rij));
842     derfcVal = - alphaPi_ * exp(-alpha2_ * *(idat.r2));
843 gezelter 1502 c1 = erfcVal * ri;
844     c2 = (-derfcVal + c1) * ri;
845     c3 = -2.0 * derfcVal * alpha2_ + 3.0 * c2 * ri;
846     } else {
847     c1 = ri;
848     c2 = c1 * ri;
849     c3 = 3.0 * c2 * ri;
850     }
851    
852     c2ri = c2 * ri;
853    
854     // calculate the potential
855     pot_term = c2 * scale;
856     vterm = pref * ct_i * pot_term;
857 gezelter 1587 vpair += vterm;
858 gezelter 1554 epot += *(idat.sw) * vterm;
859 gezelter 1502
860     // calculate derivatives for the forces and torques
861     dVdr += preSw * (uz_i * c2ri - ct_i * rhat * sc2 * c3);
862     duduz_i += preSw * pot_term * rhat;
863     }
864 gezelter 1723
865     if (j_is_Fluctuating) {
866     *(idat.dVdFQ2) += ( *(idat.sw) * vterm ) / q_j;
867     }
868    
869 gezelter 1502 }
870    
871     if (j_is_Dipole) {
872     // variables used by all methods
873     ct_ij = dot(uz_i, uz_j);
874    
875 gezelter 1554 pref = *(idat.electroMult) * pre22_ * mu_i * mu_j;
876     preSw = *(idat.sw) * pref;
877 gezelter 1502
878 gezelter 1528 if (summationMethod_ == esm_REACTION_FIELD) {
879 gezelter 1502 ri2 = riji * riji;
880     ri3 = ri2 * riji;
881     ri4 = ri2 * ri2;
882    
883     vterm = pref * ( ri3 * (ct_ij - 3.0 * ct_i * ct_j) -
884     preRF2_ * ct_ij );
885 gezelter 1587 vpair += vterm;
886 gezelter 1554 epot += *(idat.sw) * vterm;
887 gezelter 1502
888     a1 = 5.0 * ct_i * ct_j - ct_ij;
889    
890 gezelter 1668 dVdr += preSw * three * ri4 * (a1 * rhat - ct_i * uz_j - ct_j * uz_i);
891 gezelter 1502
892 gezelter 1668 duduz_i += preSw * (ri3 * (uz_j - three * ct_j * rhat) - preRF2_*uz_j);
893     duduz_j += preSw * (ri3 * (uz_i - three * ct_i * rhat) - preRF2_*uz_i);
894 gezelter 1502
895 gezelter 1587 if (idat.excluded) {
896     indirect_vpair += - pref * preRF2_ * ct_ij;
897     indirect_Pot += - preSw * preRF2_ * ct_ij;
898     indirect_duduz_i += -preSw * preRF2_ * uz_j;
899     indirect_duduz_j += -preSw * preRF2_ * uz_i;
900     }
901    
902 gezelter 1502 } else {
903    
904     if (i_is_SplitDipole) {
905     if (j_is_SplitDipole) {
906 gezelter 1554 BigR = sqrt( *(idat.r2) + 0.25 * d_i * d_i + 0.25 * d_j * d_j);
907 gezelter 1502 } else {
908 gezelter 1554 BigR = sqrt( *(idat.r2) + 0.25 * d_i * d_i);
909 gezelter 1502 }
910     ri = 1.0 / BigR;
911 gezelter 1554 scale = *(idat.rij) * ri;
912 gezelter 1502 } else {
913     if (j_is_SplitDipole) {
914 gezelter 1554 BigR = sqrt( *(idat.r2) + 0.25 * d_j * d_j);
915 gezelter 1502 ri = 1.0 / BigR;
916 gezelter 1554 scale = *(idat.rij) * ri;
917 gezelter 1502 } else {
918     ri = riji;
919     scale = 1.0;
920     }
921     }
922     if (screeningMethod_ == DAMPED) {
923     // assemble damping variables
924 gezelter 1616 //res = erfcSpline_->getValueAndDerivativeAt( *(idat.rij) );
925     //erfcVal = res.first;
926     //derfcVal = res.second;
927     erfcVal = erfc(dampingAlpha_ * *(idat.rij));
928     derfcVal = - alphaPi_ * exp(-alpha2_ * *(idat.r2));
929 gezelter 1502 c1 = erfcVal * ri;
930     c2 = (-derfcVal + c1) * ri;
931     c3 = -2.0 * derfcVal * alpha2_ + 3.0 * c2 * ri;
932     c4 = -4.0 * derfcVal * alpha4_ + 5.0 * c3 * ri * ri;
933     } else {
934     c1 = ri;
935     c2 = c1 * ri;
936     c3 = 3.0 * c2 * ri;
937     c4 = 5.0 * c3 * ri * ri;
938     }
939    
940     // precompute variables for convenience
941     sc2 = scale * scale;
942     cti3 = ct_i * sc2 * c3;
943     ctj3 = ct_j * sc2 * c3;
944     ctidotj = ct_i * ct_j * sc2;
945     preSwSc = preSw * scale;
946     c2ri = c2 * ri;
947     c3ri = c3 * ri;
948 gezelter 1554 c4rij = c4 * *(idat.rij) ;
949 gezelter 1502
950     // calculate the potential
951     pot_term = (ct_ij * c2ri - ctidotj * c3);
952     vterm = pref * pot_term;
953 gezelter 1587 vpair += vterm;
954 gezelter 1554 epot += *(idat.sw) * vterm;
955 gezelter 1502
956     // calculate derivatives for the forces and torques
957     dVdr += preSwSc * ( ctidotj * rhat * c4rij -
958     (ct_i*uz_j + ct_j*uz_i + ct_ij*rhat) * c3ri);
959    
960     duduz_i += preSw * (uz_j * c2ri - ctj3 * rhat);
961     duduz_j += preSw * (uz_i * c2ri - cti3 * rhat);
962     }
963     }
964     }
965    
966     if (i_is_Quadrupole) {
967     if (j_is_Charge) {
968     // precompute some necessary variables
969     cx2 = cx_i * cx_i;
970     cy2 = cy_i * cy_i;
971     cz2 = cz_i * cz_i;
972    
973 gezelter 1554 pref = *(idat.electroMult) * pre14_ * q_j * one_third_;
974 gezelter 1502
975     if (screeningMethod_ == DAMPED) {
976     // assemble the damping variables
977 gezelter 1616 //res = erfcSpline_->getValueAndDerivativeAt( *(idat.rij) );
978     //erfcVal = res.first;
979     //derfcVal = res.second;
980     erfcVal = erfc(dampingAlpha_ * *(idat.rij));
981     derfcVal = - alphaPi_ * exp(-alpha2_ * *(idat.r2));
982 gezelter 1502 c1 = erfcVal * riji;
983     c2 = (-derfcVal + c1) * riji;
984     c3 = -2.0 * derfcVal * alpha2_ + 3.0 * c2 * riji;
985     c4 = -4.0 * derfcVal * alpha4_ + 5.0 * c3 * riji * riji;
986     } else {
987     c1 = riji;
988     c2 = c1 * riji;
989     c3 = 3.0 * c2 * riji;
990     c4 = 5.0 * c3 * riji * riji;
991     }
992    
993     // precompute some variables for convenience
994 gezelter 1554 preSw = *(idat.sw) * pref;
995 gezelter 1502 c2ri = c2 * riji;
996     c3ri = c3 * riji;
997 gezelter 1554 c4rij = c4 * *(idat.rij) ;
998 gezelter 1668 rhatdot2 = two * rhat * c3;
999 gezelter 1502 rhatc4 = rhat * c4rij;
1000    
1001     // calculate the potential
1002     pot_term = ( qxx_i * (cx2 * c3 - c2ri) +
1003     qyy_i * (cy2 * c3 - c2ri) +
1004     qzz_i * (cz2 * c3 - c2ri) );
1005    
1006     vterm = pref * pot_term;
1007 gezelter 1587 vpair += vterm;
1008 gezelter 1554 epot += *(idat.sw) * vterm;
1009 gezelter 1502
1010     // calculate the derivatives for the forces and torques
1011    
1012 gezelter 1668 dVdr += -preSw * (qxx_i* (cx2*rhatc4 - (two*cx_i*ux_i + rhat)*c3ri) +
1013     qyy_i* (cy2*rhatc4 - (two*cy_i*uy_i + rhat)*c3ri) +
1014     qzz_i* (cz2*rhatc4 - (two*cz_i*uz_i + rhat)*c3ri));
1015 gezelter 1502
1016     dudux_i += preSw * qxx_i * cx_i * rhatdot2;
1017     duduy_i += preSw * qyy_i * cy_i * rhatdot2;
1018     duduz_i += preSw * qzz_i * cz_i * rhatdot2;
1019 gezelter 1723
1020     if (j_is_Fluctuating) {
1021     *(idat.dVdFQ2) += ( *(idat.sw) * vterm ) / q_j;
1022     }
1023    
1024 gezelter 1502 }
1025     }
1026    
1027    
1028 gezelter 1587 if (!idat.excluded) {
1029     *(idat.vpair) += vpair;
1030     (*(idat.pot))[ELECTROSTATIC_FAMILY] += epot;
1031     *(idat.f1) += dVdr;
1032    
1033     if (i_is_Dipole || i_is_Quadrupole)
1034     *(idat.t1) -= cross(uz_i, duduz_i);
1035     if (i_is_Quadrupole) {
1036     *(idat.t1) -= cross(ux_i, dudux_i);
1037     *(idat.t1) -= cross(uy_i, duduy_i);
1038     }
1039    
1040     if (j_is_Dipole || j_is_Quadrupole)
1041     *(idat.t2) -= cross(uz_j, duduz_j);
1042     if (j_is_Quadrupole) {
1043     *(idat.t2) -= cross(uz_j, dudux_j);
1044     *(idat.t2) -= cross(uz_j, duduy_j);
1045     }
1046    
1047     } else {
1048    
1049     // only accumulate the forces and torques resulting from the
1050     // indirect reaction field terms.
1051 gezelter 1616
1052 gezelter 1587 *(idat.vpair) += indirect_vpair;
1053 gezelter 1761
1054     (*(idat.excludedPot))[ELECTROSTATIC_FAMILY] += (*(idat.sw) * vterm +
1055     vFluc1 ) * q_i * q_j;
1056 gezelter 1587 (*(idat.pot))[ELECTROSTATIC_FAMILY] += indirect_Pot;
1057     *(idat.f1) += indirect_dVdr;
1058    
1059     if (i_is_Dipole)
1060     *(idat.t1) -= cross(uz_i, indirect_duduz_i);
1061     if (j_is_Dipole)
1062     *(idat.t2) -= cross(uz_j, indirect_duduz_j);
1063 gezelter 1502 }
1064    
1065     return;
1066     }
1067    
1068 gezelter 1545 void Electrostatic::calcSelfCorrection(SelfData &sdat) {
1069 jmichalk 1734 RealType mu1, preVal, self;
1070 gezelter 1502 if (!initialized_) initialize();
1071 gezelter 1586
1072 gezelter 1545 ElectrostaticAtomData data = ElectrostaticMap[sdat.atype];
1073 gezelter 1502
1074     // logicals
1075     bool i_is_Charge = data.is_Charge;
1076     bool i_is_Dipole = data.is_Dipole;
1077 jmichalk 1734 bool i_is_Fluctuating = data.is_Fluctuating;
1078     RealType chg1 = data.fixedCharge;
1079    
1080     if (i_is_Fluctuating) {
1081     chg1 += *(sdat.flucQ);
1082     // dVdFQ is really a force, so this is negative the derivative
1083     *(sdat.dVdFQ) -= *(sdat.flucQ) * data.hardness + data.electronegativity;
1084 gezelter 1761 (*(sdat.excludedPot))[ELECTROSTATIC_FAMILY] += (*sdat.flucQ) *
1085     (*(sdat.flucQ) * data.hardness * 0.5 + data.electronegativity);
1086 jmichalk 1734 }
1087 gezelter 1502
1088 gezelter 1528 if (summationMethod_ == esm_REACTION_FIELD) {
1089 gezelter 1502 if (i_is_Dipole) {
1090     mu1 = data.dipole_moment;
1091     preVal = pre22_ * preRF2_ * mu1 * mu1;
1092 gezelter 1586 (*(sdat.pot))[ELECTROSTATIC_FAMILY] -= 0.5 * preVal;
1093 gezelter 1502
1094     // The self-correction term adds into the reaction field vector
1095 gezelter 1554 Vector3d uz_i = sdat.eFrame->getColumn(2);
1096 gezelter 1502 Vector3d ei = preVal * uz_i;
1097    
1098     // This looks very wrong. A vector crossed with itself is zero.
1099 gezelter 1554 *(sdat.t) -= cross(uz_i, ei);
1100 gezelter 1502 }
1101 gezelter 1528 } else if (summationMethod_ == esm_SHIFTED_FORCE || summationMethod_ == esm_SHIFTED_POTENTIAL) {
1102 gezelter 1502 if (i_is_Charge) {
1103     if (screeningMethod_ == DAMPED) {
1104 gezelter 1554 self = - 0.5 * (c1c_ + alphaPi_) * chg1 * (chg1 + *(sdat.skippedCharge)) * pre11_;
1105 gezelter 1502 } else {
1106 gezelter 1554 self = - 0.5 * rcuti_ * chg1 * (chg1 + *(sdat.skippedCharge)) * pre11_;
1107 gezelter 1502 }
1108 gezelter 1586 (*(sdat.pot))[ELECTROSTATIC_FAMILY] += self;
1109 gezelter 1502 }
1110     }
1111     }
1112 gezelter 1505
1113 gezelter 1545 RealType Electrostatic::getSuggestedCutoffRadius(pair<AtomType*, AtomType*> atypes) {
1114 gezelter 1505 // This seems to work moderately well as a default. There's no
1115     // inherent scale for 1/r interactions that we can standardize.
1116     // 12 angstroms seems to be a reasonably good guess for most
1117     // cases.
1118     return 12.0;
1119     }
1120 gezelter 1502 }

Properties

Name Value
svn:eol-style native