ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/branches/devel_omp/src/nonbonded/Electrostatic.cpp
Revision: 1614
Committed: Tue Aug 23 20:55:51 2011 UTC (13 years, 11 months ago) by mciznick
File size: 39606 byte(s)
Log Message:
Updated scalability of OpenMP threads.

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

Properties

Name Value
svn:eol-style native