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

Properties

Name Value
svn:eol-style native