ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/branches/development/src/nonbonded/Electrostatic.cpp
Revision: 1584
Committed: Fri Jun 17 20:16:35 2011 UTC (13 years, 11 months ago) by gezelter
File size: 36886 byte(s)
Log Message:
bug fixes.

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

Properties

Name Value
svn:eol-style native