ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/branches/development/src/nonbonded/Electrostatic.cpp
Revision: 1668
Committed: Fri Jan 6 19:03:05 2012 UTC (13 years, 4 months ago) by gezelter
File size: 37408 byte(s)
Log Message:
Some fixes for CMake and single precision builds

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

Properties

Name Value
svn:eol-style native