ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/trunk/src/nonbonded/Electrostatic.cpp
Revision: 1915
Committed: Mon Jul 29 17:55:17 2013 UTC (11 years, 11 months ago) by gezelter
File size: 54013 byte(s)
Log Message:
Added Legendre Correlation function (as a function of Z), working on architecture for Ewald
Fixed some bugs in FlucQ


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 1879 * [3] Sun, Lin & Gezelter, J. Chem. Phys. 128, 234107 (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 gezelter 1915 #include <numeric>
48 gezelter 1502 #include "nonbonded/Electrostatic.hpp"
49     #include "utils/simError.h"
50     #include "types/NonBondedInteractionType.hpp"
51 gezelter 1710 #include "types/FixedChargeAdapter.hpp"
52 gezelter 1720 #include "types/FluctuatingChargeAdapter.hpp"
53 gezelter 1710 #include "types/MultipoleAdapter.hpp"
54 gezelter 1535 #include "io/Globals.hpp"
55 gezelter 1718 #include "nonbonded/SlaterIntegrals.hpp"
56     #include "utils/PhysicalConstants.hpp"
57 gezelter 1767 #include "math/erfc.hpp"
58 gezelter 1879 #include "math/SquareMatrix.hpp"
59 gezelter 1915 #include "primitives/Molecule.hpp"
60 gezelter 1502
61 gezelter 1915
62 gezelter 1502 namespace OpenMD {
63    
64     Electrostatic::Electrostatic(): name_("Electrostatic"), initialized_(false),
65 gezelter 1587 forceField_(NULL), info_(NULL),
66     haveCutoffRadius_(false),
67     haveDampingAlpha_(false),
68     haveDielectric_(false),
69 gezelter 1879 haveElectroSplines_(false)
70 gezelter 1587 {}
71 gezelter 1502
72     void Electrostatic::initialize() {
73 gezelter 1587
74 gezelter 1584 Globals* simParams_ = info_->getSimParams();
75 gezelter 1535
76 gezelter 1528 summationMap_["HARD"] = esm_HARD;
77 gezelter 1616 summationMap_["NONE"] = esm_HARD;
78 gezelter 1528 summationMap_["SWITCHING_FUNCTION"] = esm_SWITCHING_FUNCTION;
79     summationMap_["SHIFTED_POTENTIAL"] = esm_SHIFTED_POTENTIAL;
80     summationMap_["SHIFTED_FORCE"] = esm_SHIFTED_FORCE;
81 gezelter 1879 summationMap_["TAYLOR_SHIFTED"] = esm_TAYLOR_SHIFTED;
82 gezelter 1528 summationMap_["REACTION_FIELD"] = esm_REACTION_FIELD;
83     summationMap_["EWALD_FULL"] = esm_EWALD_FULL;
84     summationMap_["EWALD_PME"] = esm_EWALD_PME;
85     summationMap_["EWALD_SPME"] = esm_EWALD_SPME;
86     screeningMap_["DAMPED"] = DAMPED;
87     screeningMap_["UNDAMPED"] = UNDAMPED;
88    
89 gezelter 1502 // these prefactors convert the multipole interactions into kcal / mol
90     // all were computed assuming distances are measured in angstroms
91     // Charge-Charge, assuming charges are measured in electrons
92     pre11_ = 332.0637778;
93     // Charge-Dipole, assuming charges are measured in electrons, and
94     // dipoles are measured in debyes
95     pre12_ = 69.13373;
96 gezelter 1879 // Dipole-Dipole, assuming dipoles are measured in Debye
97 gezelter 1502 pre22_ = 14.39325;
98     // Charge-Quadrupole, assuming charges are measured in electrons, and
99     // quadrupoles are measured in 10^-26 esu cm^2
100 gezelter 1879 // This unit is also known affectionately as an esu centibarn.
101 gezelter 1502 pre14_ = 69.13373;
102 gezelter 1879 // Dipole-Quadrupole, assuming dipoles are measured in debyes and
103     // quadrupoles in esu centibarns:
104     pre24_ = 14.39325;
105     // Quadrupole-Quadrupole, assuming esu centibarns:
106     pre44_ = 14.39325;
107    
108 gezelter 1502 // conversions for the simulation box dipole moment
109     chargeToC_ = 1.60217733e-19;
110     angstromToM_ = 1.0e-10;
111     debyeToCm_ = 3.33564095198e-30;
112    
113 gezelter 1879 // Default number of points for electrostatic splines
114 gezelter 1502 np_ = 100;
115    
116     // variables to handle different summation methods for long-range
117     // electrostatics:
118 gezelter 1528 summationMethod_ = esm_HARD;
119 gezelter 1502 screeningMethod_ = UNDAMPED;
120     dielectric_ = 1.0;
121    
122 gezelter 1528 // check the summation method:
123     if (simParams_->haveElectrostaticSummationMethod()) {
124     string myMethod = simParams_->getElectrostaticSummationMethod();
125     toUpper(myMethod);
126     map<string, ElectrostaticSummationMethod>::iterator i;
127     i = summationMap_.find(myMethod);
128     if ( i != summationMap_.end() ) {
129     summationMethod_ = (*i).second;
130     } else {
131     // throw error
132     sprintf( painCave.errMsg,
133 gezelter 1536 "Electrostatic::initialize: Unknown electrostaticSummationMethod.\n"
134 gezelter 1528 "\t(Input file specified %s .)\n"
135 gezelter 1616 "\telectrostaticSummationMethod must be one of: \"hard\",\n"
136 gezelter 1879 "\t\"shifted_potential\", \"shifted_force\",\n"
137     "\t\"taylor_shifted\", or \"reaction_field\".\n",
138     myMethod.c_str() );
139 gezelter 1528 painCave.isFatal = 1;
140     simError();
141     }
142     } else {
143     // set ElectrostaticSummationMethod to the cutoffMethod:
144     if (simParams_->haveCutoffMethod()){
145     string myMethod = simParams_->getCutoffMethod();
146     toUpper(myMethod);
147     map<string, ElectrostaticSummationMethod>::iterator i;
148     i = summationMap_.find(myMethod);
149     if ( i != summationMap_.end() ) {
150     summationMethod_ = (*i).second;
151     }
152     }
153     }
154    
155     if (summationMethod_ == esm_REACTION_FIELD) {
156     if (!simParams_->haveDielectric()) {
157     // throw warning
158     sprintf( painCave.errMsg,
159     "SimInfo warning: dielectric was not specified in the input file\n\tfor the reaction field correction method.\n"
160     "\tA default value of %f will be used for the dielectric.\n", dielectric_);
161     painCave.isFatal = 0;
162     painCave.severity = OPENMD_INFO;
163     simError();
164     } else {
165     dielectric_ = simParams_->getDielectric();
166     }
167     haveDielectric_ = true;
168     }
169    
170     if (simParams_->haveElectrostaticScreeningMethod()) {
171     string myScreen = simParams_->getElectrostaticScreeningMethod();
172     toUpper(myScreen);
173     map<string, ElectrostaticScreeningMethod>::iterator i;
174     i = screeningMap_.find(myScreen);
175     if ( i != screeningMap_.end()) {
176     screeningMethod_ = (*i).second;
177     } else {
178     sprintf( painCave.errMsg,
179     "SimInfo error: Unknown electrostaticScreeningMethod.\n"
180     "\t(Input file specified %s .)\n"
181     "\telectrostaticScreeningMethod must be one of: \"undamped\"\n"
182     "or \"damped\".\n", myScreen.c_str() );
183     painCave.isFatal = 1;
184     simError();
185     }
186     }
187    
188     // check to make sure a cutoff value has been set:
189     if (!haveCutoffRadius_) {
190     sprintf( painCave.errMsg, "Electrostatic::initialize has no Default "
191     "Cutoff value!\n");
192     painCave.severity = OPENMD_ERROR;
193     painCave.isFatal = 1;
194     simError();
195     }
196    
197 gezelter 1915 if (screeningMethod_ == DAMPED || summationMethod_ == esm_EWALD_FULL) {
198 gezelter 1528 if (!simParams_->haveDampingAlpha()) {
199     // first set a cutoff dependent alpha value
200     // we assume alpha depends linearly with rcut from 0 to 20.5 ang
201     dampingAlpha_ = 0.425 - cutoffRadius_* 0.02;
202 gezelter 1915 if (dampingAlpha_ < 0.0) dampingAlpha_ = 0.0;
203 gezelter 1528 // throw warning
204     sprintf( painCave.errMsg,
205 gezelter 1750 "Electrostatic::initialize: dampingAlpha was not specified in the\n"
206     "\tinput file. A default value of %f (1/ang) will be used for the\n"
207     "\tcutoff of %f (ang).\n",
208 gezelter 1528 dampingAlpha_, cutoffRadius_);
209     painCave.severity = OPENMD_INFO;
210     painCave.isFatal = 0;
211     simError();
212     } else {
213     dampingAlpha_ = simParams_->getDampingAlpha();
214     }
215     haveDampingAlpha_ = true;
216     }
217    
218 gezelter 1915
219 gezelter 1895 Etypes.clear();
220     Etids.clear();
221     FQtypes.clear();
222     FQtids.clear();
223     ElectrostaticMap.clear();
224     Jij.clear();
225     nElectro_ = 0;
226     nFlucq_ = 0;
227    
228     Etids.resize( forceField_->getNAtomType(), -1);
229     FQtids.resize( forceField_->getNAtomType(), -1);
230    
231     set<AtomType*>::iterator at;
232     for (at = simTypes_.begin(); at != simTypes_.end(); ++at) {
233     if ((*at)->isElectrostatic()) nElectro_++;
234     if ((*at)->isFluctuatingCharge()) nFlucq_++;
235     }
236 gezelter 1528
237 gezelter 1895 Jij.resize(nFlucq_);
238    
239     for (at = simTypes_.begin(); at != simTypes_.end(); ++at) {
240     if ((*at)->isElectrostatic()) addType(*at);
241 gezelter 1879 }
242    
243     if (summationMethod_ == esm_REACTION_FIELD) {
244     preRF_ = (dielectric_ - 1.0) /
245     ((2.0 * dielectric_ + 1.0) * pow(cutoffRadius_,3) );
246 gezelter 1502 }
247    
248 gezelter 1879 RealType b0c, b1c, b2c, b3c, b4c, b5c;
249     RealType db0c_1, db0c_2, db0c_3, db0c_4, db0c_5;
250     RealType a2, expTerm, invArootPi;
251    
252     RealType r = cutoffRadius_;
253     RealType r2 = r * r;
254     RealType ric = 1.0 / r;
255     RealType ric2 = ric * ric;
256 gezelter 1502
257 gezelter 1879 if (screeningMethod_ == DAMPED) {
258     a2 = dampingAlpha_ * dampingAlpha_;
259     invArootPi = 1.0 / (dampingAlpha_ * sqrt(M_PI));
260     expTerm = exp(-a2 * r2);
261     // values of Smith's B_l functions at the cutoff radius:
262     b0c = erfc(dampingAlpha_ * r) / r;
263     b1c = ( b0c + 2.0*a2 * expTerm * invArootPi) / r2;
264     b2c = (3.0 * b1c + pow(2.0*a2, 2) * expTerm * invArootPi) / r2;
265     b3c = (5.0 * b2c + pow(2.0*a2, 3) * expTerm * invArootPi) / r2;
266     b4c = (7.0 * b3c + pow(2.0*a2, 4) * expTerm * invArootPi) / r2;
267     b5c = (9.0 * b4c + pow(2.0*a2, 5) * expTerm * invArootPi) / r2;
268 gezelter 1900 // Half the Smith self piece:
269     selfMult1_ = - a2 * invArootPi;
270     selfMult2_ = - 2.0 * a2 * a2 * invArootPi / 3.0;
271     selfMult4_ = - 4.0 * a2 * a2 * a2 * invArootPi / 5.0;
272 gezelter 1502 } else {
273 gezelter 1879 a2 = 0.0;
274     b0c = 1.0 / r;
275     b1c = ( b0c) / r2;
276     b2c = (3.0 * b1c) / r2;
277     b3c = (5.0 * b2c) / r2;
278     b4c = (7.0 * b3c) / r2;
279     b5c = (9.0 * b4c) / r2;
280 gezelter 1900 selfMult1_ = 0.0;
281     selfMult2_ = 0.0;
282     selfMult4_ = 0.0;
283 gezelter 1502 }
284 gezelter 1879
285     // higher derivatives of B_0 at the cutoff radius:
286     db0c_1 = -r * b1c;
287     db0c_2 = -b1c + r2 * b2c;
288     db0c_3 = 3.0*r*b2c - r2*r*b3c;
289     db0c_4 = 3.0*b2c - 6.0*r2*b3c + r2*r2*b4c;
290 gezelter 1900 db0c_5 = -15.0*r*b3c + 10.0*r2*r*b4c - r2*r2*r*b5c;
291 gezelter 1879
292 gezelter 1915 if (summationMethod_ != esm_EWALD_FULL) {
293     selfMult1_ -= b0c;
294     selfMult2_ += (db0c_2 + 2.0*db0c_1*ric) / 3.0;
295     selfMult4_ -= (db0c_4 + 4.0*db0c_3*ric) / 15.0;
296     }
297    
298 gezelter 1879 // working variables for the splines:
299     RealType ri, ri2;
300     RealType b0, b1, b2, b3, b4, b5;
301     RealType db0_1, db0_2, db0_3, db0_4, db0_5;
302     RealType f, fc, f0;
303     RealType g, gc, g0, g1, g2, g3, g4;
304     RealType h, hc, h1, h2, h3, h4;
305     RealType s, sc, s2, s3, s4;
306     RealType t, tc, t3, t4;
307     RealType u, uc, u4;
308    
309     // working variables for Taylor expansion:
310     RealType rmRc, rmRc2, rmRc3, rmRc4;
311    
312     // Approximate using splines using a maximum of 0.1 Angstroms
313     // between points.
314     int nptest = int((cutoffRadius_ + 2.0) / 0.1);
315     np_ = (np_ > nptest) ? np_ : nptest;
316    
317 gezelter 1613 // Add a 2 angstrom safety window to deal with cutoffGroups that
318     // have charged atoms longer than the cutoffRadius away from each
319 gezelter 1879 // other. Splining is almost certainly the best choice here.
320     // Direct calls to erfc would be preferrable if it is a very fast
321     // implementation.
322 gezelter 1613
323 gezelter 1879 RealType dx = (cutoffRadius_ + 2.0) / RealType(np_);
324    
325     // Storage vectors for the computed functions
326     vector<RealType> rv;
327     vector<RealType> v01v;
328     vector<RealType> v11v;
329     vector<RealType> v21v, v22v;
330     vector<RealType> v31v, v32v;
331     vector<RealType> v41v, v42v, v43v;
332    
333     for (int i = 1; i < np_ + 1; i++) {
334     r = RealType(i) * dx;
335     rv.push_back(r);
336    
337     ri = 1.0 / r;
338     ri2 = ri * ri;
339    
340     r2 = r * r;
341     expTerm = exp(-a2 * r2);
342    
343     // Taylor expansion factors (no need for factorials this way):
344     rmRc = r - cutoffRadius_;
345     rmRc2 = rmRc * rmRc / 2.0;
346     rmRc3 = rmRc2 * rmRc / 3.0;
347     rmRc4 = rmRc3 * rmRc / 4.0;
348    
349     // values of Smith's B_l functions at r:
350     if (screeningMethod_ == DAMPED) {
351     b0 = erfc(dampingAlpha_ * r) * ri;
352     b1 = ( b0 + 2.0*a2 * expTerm * invArootPi) * ri2;
353     b2 = (3.0 * b1 + pow(2.0*a2, 2) * expTerm * invArootPi) * ri2;
354     b3 = (5.0 * b2 + pow(2.0*a2, 3) * expTerm * invArootPi) * ri2;
355     b4 = (7.0 * b3 + pow(2.0*a2, 4) * expTerm * invArootPi) * ri2;
356     b5 = (9.0 * b4 + pow(2.0*a2, 5) * expTerm * invArootPi) * ri2;
357     } else {
358     b0 = ri;
359     b1 = ( b0) * ri2;
360     b2 = (3.0 * b1) * ri2;
361     b3 = (5.0 * b2) * ri2;
362     b4 = (7.0 * b3) * ri2;
363     b5 = (9.0 * b4) * ri2;
364     }
365    
366     // higher derivatives of B_0 at r:
367     db0_1 = -r * b1;
368     db0_2 = -b1 + r2 * b2;
369     db0_3 = 3.0*r*b2 - r2*r*b3;
370     db0_4 = 3.0*b2 - 6.0*r2*b3 + r2*r2*b4;
371     db0_5 = -15.0*r*b3 + 10.0*r2*r*b4 - r2*r2*r*b5;
372    
373     f = b0;
374     fc = b0c;
375     f0 = f - fc - rmRc*db0c_1;
376    
377     g = db0_1;
378     gc = db0c_1;
379     g0 = g - gc;
380     g1 = g0 - rmRc *db0c_2;
381     g2 = g1 - rmRc2*db0c_3;
382     g3 = g2 - rmRc3*db0c_4;
383     g4 = g3 - rmRc4*db0c_5;
384    
385     h = db0_2;
386     hc = db0c_2;
387     h1 = h - hc;
388     h2 = h1 - rmRc *db0c_3;
389     h3 = h2 - rmRc2*db0c_4;
390     h4 = h3 - rmRc3*db0c_5;
391    
392     s = db0_3;
393     sc = db0c_3;
394     s2 = s - sc;
395     s3 = s2 - rmRc *db0c_4;
396     s4 = s3 - rmRc2*db0c_5;
397    
398     t = db0_4;
399     tc = db0c_4;
400     t3 = t - tc;
401     t4 = t3 - rmRc *db0c_5;
402    
403     u = db0_5;
404     uc = db0c_5;
405     u4 = u - uc;
406    
407     // in what follows below, the various v functions are used for
408     // potentials and torques, while the w functions show up in the
409     // forces.
410    
411     switch (summationMethod_) {
412     case esm_SHIFTED_FORCE:
413    
414     v01 = f - fc - rmRc*gc;
415     v11 = g - gc - rmRc*hc;
416     v21 = g*ri - gc*ric - rmRc*(hc - gc*ric)*ric;
417     v22 = h - g*ri - (hc - gc*ric) - rmRc*(sc - (hc - gc*ric)*ric);
418 gezelter 1894 v31 = (h-g*ri)*ri - (hc-gc*ric)*ric - rmRc*(sc-2.0*(hc-gc*ric)*ric)*ric;
419 gezelter 1879 v32 = (s - 3.0*(h-g*ri)*ri) - (sc - 3.0*(hc-gc*ric)*ric)
420     - rmRc*(tc - 3.0*(sc-2.0*(hc-gc*ric)*ric)*ric);
421     v41 = (h - g*ri)*ri2 - (hc - gc*ric)*ric2
422     - rmRc*(sc - 3.0*(hc-gc*ric)*ric)*ric2;
423     v42 = (s-3.0*(h-g*ri)*ri)*ri - (sc-3.0*(hc-gc*ric)*ric)*ric
424     - rmRc*(tc - (4.0*sc - 9.0*(hc - gc*ric)*ric)*ric)*ric;
425    
426     v43 = (t - 3.0*(2.0*s - 5.0*(h - g*ri)*ri)*ri)
427     - (tc - 3.0*(2.0*sc - 5.0*(hc - gc*ric)*ric)*ric)
428     - rmRc*(uc-3.0*(2.0*tc - (7.0*sc - 15.0*(hc - gc*ric)*ric)*ric)*ric);
429    
430     dv01 = g - gc;
431     dv11 = h - hc;
432     dv21 = (h - g*ri)*ri - (hc - gc*ric)*ric;
433     dv22 = (s - (h - g*ri)*ri) - (sc - (hc - gc*ric)*ric);
434     dv31 = (s - 2.0*(h-g*ri)*ri)*ri - (sc - 2.0*(hc-gc*ric)*ric)*ric;
435     dv32 = (t - 3.0*(s-2.0*(h-g*ri)*ri)*ri)
436     - (tc - 3.0*(sc-2.0*(hc-gc*ric)*ric)*ric);
437     dv41 = (s - 3.0*(h - g*ri)*ri)*ri2 - (sc - 3.0*(hc - gc*ric)*ric)*ric2;
438     dv42 = (t - (4.0*s - 9.0*(h-g*ri)*ri)*ri)*ri
439     - (tc - (4.0*sc - 9.0*(hc-gc*ric)*ric)*ric)*ric;
440     dv43 = (u - 3.0*(2.0*t - (7.0*s - 15.0*(h - g*ri)*ri)*ri)*ri)
441     - (uc - 3.0*(2.0*tc - (7.0*sc - 15.0*(hc - gc*ric)*ric)*ric)*ric);
442    
443     break;
444    
445     case esm_TAYLOR_SHIFTED:
446    
447     v01 = f0;
448     v11 = g1;
449     v21 = g2 * ri;
450     v22 = h2 - v21;
451     v31 = (h3 - g3 * ri) * ri;
452     v32 = s3 - 3.0*v31;
453     v41 = (h4 - g4 * ri) * ri2;
454     v42 = s4 * ri - 3.0*v41;
455     v43 = t4 - 6.0*v42 - 3.0*v41;
456    
457     dv01 = g0;
458     dv11 = h1;
459     dv21 = (h2 - g2*ri)*ri;
460     dv22 = (s2 - (h2 - g2*ri)*ri);
461     dv31 = (s3 - 2.0*(h3-g3*ri)*ri)*ri;
462     dv32 = (t3 - 3.0*(s3-2.0*(h3-g3*ri)*ri)*ri);
463     dv41 = (s4 - 3.0*(h4 - g4*ri)*ri)*ri2;
464     dv42 = (t4 - (4.0*s4 - 9.0*(h4-g4*ri)*ri)*ri)*ri;
465     dv43 = (u4 - 3.0*(2.0*t4 - (7.0*s4 - 15.0*(h4 - g4*ri)*ri)*ri)*ri);
466    
467     break;
468    
469     case esm_SHIFTED_POTENTIAL:
470    
471     v01 = f - fc;
472     v11 = g - gc;
473     v21 = g*ri - gc*ric;
474     v22 = h - g*ri - (hc - gc*ric);
475 gezelter 1894 v31 = (h-g*ri)*ri - (hc-gc*ric)*ric;
476 gezelter 1879 v32 = (s - 3.0*(h-g*ri)*ri) - (sc - 3.0*(hc-gc*ric)*ric);
477     v41 = (h - g*ri)*ri2 - (hc - gc*ric)*ric2;
478     v42 = (s-3.0*(h-g*ri)*ri)*ri - (sc-3.0*(hc-gc*ric)*ric)*ric;
479     v43 = (t - 3.0*(2.0*s - 5.0*(h - g*ri)*ri)*ri)
480     - (tc - 3.0*(2.0*sc - 5.0*(hc - gc*ric)*ric)*ric);
481    
482     dv01 = g;
483     dv11 = h;
484     dv21 = (h - g*ri)*ri;
485     dv22 = (s - (h - g*ri)*ri);
486     dv31 = (s - 2.0*(h-g*ri)*ri)*ri;
487     dv32 = (t - 3.0*(s-2.0*(h-g*ri)*ri)*ri);
488     dv41 = (s - 3.0*(h - g*ri)*ri)*ri2;
489     dv42 = (t - (4.0*s - 9.0*(h-g*ri)*ri)*ri)*ri;
490     dv43 = (u - 3.0*(2.0*t - (7.0*s - 15.0*(h - g*ri)*ri)*ri)*ri);
491    
492     break;
493    
494     case esm_SWITCHING_FUNCTION:
495     case esm_HARD:
496 gezelter 1915 case esm_EWALD_FULL:
497 gezelter 1879
498     v01 = f;
499     v11 = g;
500     v21 = g*ri;
501     v22 = h - g*ri;
502     v31 = (h-g*ri)*ri;
503     v32 = (s - 3.0*(h-g*ri)*ri);
504     v41 = (h - g*ri)*ri2;
505     v42 = (s-3.0*(h-g*ri)*ri)*ri;
506     v43 = (t - 3.0*(2.0*s - 5.0*(h - g*ri)*ri)*ri);
507    
508     dv01 = g;
509     dv11 = h;
510     dv21 = (h - g*ri)*ri;
511     dv22 = (s - (h - g*ri)*ri);
512     dv31 = (s - 2.0*(h-g*ri)*ri)*ri;
513     dv32 = (t - 3.0*(s-2.0*(h-g*ri)*ri)*ri);
514     dv41 = (s - 3.0*(h - g*ri)*ri)*ri2;
515     dv42 = (t - (4.0*s - 9.0*(h-g*ri)*ri)*ri)*ri;
516     dv43 = (u - 3.0*(2.0*t - (7.0*s - 15.0*(h - g*ri)*ri)*ri)*ri);
517    
518     break;
519    
520     case esm_REACTION_FIELD:
521    
522     // following DL_POLY's lead for shifting the image charge potential:
523     f = b0 + preRF_ * r2;
524     fc = b0c + preRF_ * cutoffRadius_ * cutoffRadius_;
525    
526     g = db0_1 + preRF_ * 2.0 * r;
527     gc = db0c_1 + preRF_ * 2.0 * cutoffRadius_;
528    
529     h = db0_2 + preRF_ * 2.0;
530     hc = db0c_2 + preRF_ * 2.0;
531    
532     v01 = f - fc;
533     v11 = g - gc;
534     v21 = g*ri - gc*ric;
535     v22 = h - g*ri - (hc - gc*ric);
536 gezelter 1894 v31 = (h-g*ri)*ri - (hc-gc*ric)*ric;
537 gezelter 1879 v32 = (s - 3.0*(h-g*ri)*ri) - (sc - 3.0*(hc-gc*ric)*ric);
538     v41 = (h - g*ri)*ri2 - (hc - gc*ric)*ric2;
539     v42 = (s-3.0*(h-g*ri)*ri)*ri - (sc-3.0*(hc-gc*ric)*ric)*ric;
540     v43 = (t - 3.0*(2.0*s - 5.0*(h - g*ri)*ri)*ri)
541     - (tc - 3.0*(2.0*sc - 5.0*(hc - gc*ric)*ric)*ric);
542    
543     dv01 = g;
544     dv11 = h;
545     dv21 = (h - g*ri)*ri;
546     dv22 = (s - (h - g*ri)*ri);
547     dv31 = (s - 2.0*(h-g*ri)*ri)*ri;
548     dv32 = (t - 3.0*(s-2.0*(h-g*ri)*ri)*ri);
549     dv41 = (s - 3.0*(h - g*ri)*ri)*ri2;
550     dv42 = (t - (4.0*s - 9.0*(h-g*ri)*ri)*ri)*ri;
551     dv43 = (u - 3.0*(2.0*t - (7.0*s - 15.0*(h - g*ri)*ri)*ri)*ri);
552    
553     break;
554    
555     case esm_EWALD_PME:
556     case esm_EWALD_SPME:
557     default :
558     map<string, ElectrostaticSummationMethod>::iterator i;
559     std::string meth;
560     for (i = summationMap_.begin(); i != summationMap_.end(); ++i) {
561     if ((*i).second == summationMethod_) meth = (*i).first;
562     }
563     sprintf( painCave.errMsg,
564     "Electrostatic::initialize: electrostaticSummationMethod %s \n"
565     "\thas not been implemented yet. Please select one of:\n"
566     "\t\"hard\", \"shifted_potential\", or \"shifted_force\"\n",
567     meth.c_str() );
568     painCave.isFatal = 1;
569     simError();
570     break;
571     }
572    
573     // Add these computed values to the storage vectors for spline creation:
574     v01v.push_back(v01);
575     v11v.push_back(v11);
576     v21v.push_back(v21);
577     v22v.push_back(v22);
578     v31v.push_back(v31);
579     v32v.push_back(v32);
580     v41v.push_back(v41);
581     v42v.push_back(v42);
582     v43v.push_back(v43);
583 gezelter 1502 }
584    
585 gezelter 1879 // construct the spline structures and fill them with the values we've
586     // computed:
587    
588     v01s = new CubicSpline();
589     v01s->addPoints(rv, v01v);
590     v11s = new CubicSpline();
591     v11s->addPoints(rv, v11v);
592     v21s = new CubicSpline();
593     v21s->addPoints(rv, v21v);
594     v22s = new CubicSpline();
595     v22s->addPoints(rv, v22v);
596     v31s = new CubicSpline();
597     v31s->addPoints(rv, v31v);
598     v32s = new CubicSpline();
599     v32s->addPoints(rv, v32v);
600     v41s = new CubicSpline();
601     v41s->addPoints(rv, v41v);
602     v42s = new CubicSpline();
603     v42s->addPoints(rv, v42v);
604     v43s = new CubicSpline();
605     v43s->addPoints(rv, v43v);
606    
607     haveElectroSplines_ = true;
608    
609 gezelter 1502 initialized_ = true;
610     }
611    
612     void Electrostatic::addType(AtomType* atomType){
613 gezelter 1895
614 gezelter 1502 ElectrostaticAtomData electrostaticAtomData;
615     electrostaticAtomData.is_Charge = false;
616     electrostaticAtomData.is_Dipole = false;
617     electrostaticAtomData.is_Quadrupole = false;
618 gezelter 1723 electrostaticAtomData.is_Fluctuating = false;
619 gezelter 1502
620 gezelter 1710 FixedChargeAdapter fca = FixedChargeAdapter(atomType);
621 gezelter 1502
622 gezelter 1710 if (fca.isFixedCharge()) {
623 gezelter 1502 electrostaticAtomData.is_Charge = true;
624 gezelter 1720 electrostaticAtomData.fixedCharge = fca.getCharge();
625 gezelter 1502 }
626    
627 gezelter 1710 MultipoleAdapter ma = MultipoleAdapter(atomType);
628     if (ma.isMultipole()) {
629     if (ma.isDipole()) {
630 gezelter 1502 electrostaticAtomData.is_Dipole = true;
631 gezelter 1879 electrostaticAtomData.dipole = ma.getDipole();
632 gezelter 1502 }
633 gezelter 1710 if (ma.isQuadrupole()) {
634 gezelter 1502 electrostaticAtomData.is_Quadrupole = true;
635 gezelter 1879 electrostaticAtomData.quadrupole = ma.getQuadrupole();
636 gezelter 1502 }
637     }
638    
639 gezelter 1718 FluctuatingChargeAdapter fqa = FluctuatingChargeAdapter(atomType);
640 gezelter 1502
641 gezelter 1718 if (fqa.isFluctuatingCharge()) {
642 gezelter 1720 electrostaticAtomData.is_Fluctuating = true;
643     electrostaticAtomData.electronegativity = fqa.getElectronegativity();
644     electrostaticAtomData.hardness = fqa.getHardness();
645     electrostaticAtomData.slaterN = fqa.getSlaterN();
646     electrostaticAtomData.slaterZeta = fqa.getSlaterZeta();
647 gezelter 1718 }
648    
649 gezelter 1895 int atid = atomType->getIdent();
650     int etid = Etypes.size();
651     int fqtid = FQtypes.size();
652    
653     pair<set<int>::iterator,bool> ret;
654     ret = Etypes.insert( atid );
655 gezelter 1502 if (ret.second == false) {
656     sprintf( painCave.errMsg,
657     "Electrostatic already had a previous entry with ident %d\n",
658 gezelter 1895 atid);
659 gezelter 1502 painCave.severity = OPENMD_INFO;
660     painCave.isFatal = 0;
661     simError();
662     }
663    
664 gezelter 1895 Etids[ atid ] = etid;
665     ElectrostaticMap.push_back(electrostaticAtomData);
666 gezelter 1718
667 gezelter 1895 if (electrostaticAtomData.is_Fluctuating) {
668     ret = FQtypes.insert( atid );
669     if (ret.second == false) {
670     sprintf( painCave.errMsg,
671     "Electrostatic already had a previous fluctuating charge entry with ident %d\n",
672     atid );
673     painCave.severity = OPENMD_INFO;
674     painCave.isFatal = 0;
675     simError();
676     }
677     FQtids[atid] = fqtid;
678     Jij[fqtid].resize(nFlucq_);
679    
680     // Now, iterate over all known fluctuating and add to the coulomb integral map:
681    
682     std::set<int>::iterator it;
683     for( it = FQtypes.begin(); it != FQtypes.end(); ++it) {
684     int etid2 = Etids[ (*it) ];
685     int fqtid2 = FQtids[ (*it) ];
686     ElectrostaticAtomData eaData2 = ElectrostaticMap[ etid2 ];
687 gezelter 1718 RealType a = electrostaticAtomData.slaterZeta;
688 gezelter 1720 RealType b = eaData2.slaterZeta;
689 gezelter 1718 int m = electrostaticAtomData.slaterN;
690 gezelter 1720 int n = eaData2.slaterN;
691 gezelter 1895
692 gezelter 1718 // Create the spline of the coulombic integral for s-type
693     // Slater orbitals. Add a 2 angstrom safety window to deal
694     // with cutoffGroups that have charged atoms longer than the
695     // cutoffRadius away from each other.
696 gezelter 1895
697 gezelter 1720 RealType rval;
698 gezelter 1718 RealType dr = (cutoffRadius_ + 2.0) / RealType(np_ - 1);
699     vector<RealType> rvals;
700 gezelter 1879 vector<RealType> Jvals;
701     // don't start at i = 0, as rval = 0 is undefined for the
702     // slater overlap integrals.
703 gezelter 1761 for (int i = 1; i < np_+1; i++) {
704 gezelter 1718 rval = RealType(i) * dr;
705     rvals.push_back(rval);
706 gezelter 1879 Jvals.push_back(sSTOCoulInt( a, b, m, n, rval *
707     PhysicalConstants::angstromToBohr ) *
708     PhysicalConstants::hartreeToKcal );
709 gezelter 1718 }
710    
711 gezelter 1879 CubicSpline* J = new CubicSpline();
712     J->addPoints(rvals, Jvals);
713 gezelter 1895 Jij[fqtid][fqtid2] = J;
714     Jij[fqtid2].resize( nFlucq_ );
715     Jij[fqtid2][fqtid] = J;
716     }
717     }
718 gezelter 1502 return;
719     }
720    
721 gezelter 1584 void Electrostatic::setCutoffRadius( RealType rCut ) {
722     cutoffRadius_ = rCut;
723 gezelter 1528 haveCutoffRadius_ = true;
724 gezelter 1502 }
725 gezelter 1584
726 gezelter 1502 void Electrostatic::setElectrostaticSummationMethod( ElectrostaticSummationMethod esm ) {
727     summationMethod_ = esm;
728     }
729     void Electrostatic::setElectrostaticScreeningMethod( ElectrostaticScreeningMethod sm ) {
730     screeningMethod_ = sm;
731     }
732     void Electrostatic::setDampingAlpha( RealType alpha ) {
733     dampingAlpha_ = alpha;
734     haveDampingAlpha_ = true;
735     }
736     void Electrostatic::setReactionFieldDielectric( RealType dielectric ){
737     dielectric_ = dielectric;
738     haveDielectric_ = true;
739     }
740    
741 gezelter 1536 void Electrostatic::calcForce(InteractionData &idat) {
742 gezelter 1502
743 gezelter 1893 if (!initialized_) initialize();
744    
745 gezelter 1895 data1 = ElectrostaticMap[Etids[idat.atid1]];
746     data2 = ElectrostaticMap[Etids[idat.atid2]];
747 gezelter 1502
748 gezelter 1893 U = 0.0; // Potential
749     F.zero(); // Force
750     Ta.zero(); // Torque on site a
751     Tb.zero(); // Torque on site b
752     Ea.zero(); // Electric field at site a
753     Eb.zero(); // Electric field at site b
754     dUdCa = 0.0; // fluctuating charge force at site a
755     dUdCb = 0.0; // fluctuating charge force at site a
756 gezelter 1879
757     // Indirect interactions mediated by the reaction field.
758 gezelter 1893 indirect_Pot = 0.0; // Potential
759     indirect_F.zero(); // Force
760     indirect_Ta.zero(); // Torque on site a
761     indirect_Tb.zero(); // Torque on site b
762 gezelter 1587
763 gezelter 1879 // Excluded potential that is still computed for fluctuating charges
764 gezelter 1893 excluded_Pot= 0.0;
765 gezelter 1879
766    
767 gezelter 1502 // some variables we'll need independent of electrostatic type:
768    
769 gezelter 1879 ri = 1.0 / *(idat.rij);
770 gezelter 1893 rhat = *(idat.d) * ri;
771 gezelter 1879
772 gezelter 1502 // logicals
773    
774 gezelter 1893 a_is_Charge = data1.is_Charge;
775     a_is_Dipole = data1.is_Dipole;
776     a_is_Quadrupole = data1.is_Quadrupole;
777     a_is_Fluctuating = data1.is_Fluctuating;
778 gezelter 1502
779 gezelter 1893 b_is_Charge = data2.is_Charge;
780     b_is_Dipole = data2.is_Dipole;
781     b_is_Quadrupole = data2.is_Quadrupole;
782     b_is_Fluctuating = data2.is_Fluctuating;
783 gezelter 1879
784     // Obtain all of the required radial function values from the
785     // spline structures:
786 gezelter 1502
787 gezelter 1879 // needed for fields (and forces):
788     if (a_is_Charge || b_is_Charge) {
789     v01s->getValueAndDerivativeAt( *(idat.rij), v01, dv01);
790     }
791     if (a_is_Dipole || b_is_Dipole) {
792     v11s->getValueAndDerivativeAt( *(idat.rij), v11, dv11);
793     v11or = ri * v11;
794     }
795     if (a_is_Quadrupole || b_is_Quadrupole || (a_is_Dipole && b_is_Dipole)) {
796     v21s->getValueAndDerivativeAt( *(idat.rij), v21, dv21);
797     v22s->getValueAndDerivativeAt( *(idat.rij), v22, dv22);
798     v22or = ri * v22;
799     }
800 gezelter 1721
801 gezelter 1879 // needed for potentials (and forces and torques):
802     if ((a_is_Dipole && b_is_Quadrupole) ||
803     (b_is_Dipole && a_is_Quadrupole)) {
804     v31s->getValueAndDerivativeAt( *(idat.rij), v31, dv31);
805     v32s->getValueAndDerivativeAt( *(idat.rij), v32, dv32);
806     v31or = v31 * ri;
807     v32or = v32 * ri;
808     }
809     if (a_is_Quadrupole && b_is_Quadrupole) {
810     v41s->getValueAndDerivativeAt( *(idat.rij), v41, dv41);
811     v42s->getValueAndDerivativeAt( *(idat.rij), v42, dv42);
812     v43s->getValueAndDerivativeAt( *(idat.rij), v43, dv43);
813     v42or = v42 * ri;
814     v43or = v43 * ri;
815     }
816    
817     // calculate the single-site contributions (fields, etc).
818    
819     if (a_is_Charge) {
820     C_a = data1.fixedCharge;
821    
822     if (a_is_Fluctuating) {
823     C_a += *(idat.flucQ1);
824 gezelter 1721 }
825    
826 gezelter 1587 if (idat.excluded) {
827 gezelter 1879 *(idat.skippedCharge2) += C_a;
828     } else {
829     // only do the field if we're not excluded:
830     Eb -= C_a * pre11_ * dv01 * rhat;
831 gezelter 1587 }
832     }
833 gezelter 1879
834     if (a_is_Dipole) {
835     D_a = *(idat.dipole1);
836     rdDa = dot(rhat, D_a);
837     rxDa = cross(rhat, D_a);
838     if (!idat.excluded)
839     Eb -= pre12_ * ((dv11-v11or) * rdDa * rhat + v11or * D_a);
840 gezelter 1502 }
841    
842 gezelter 1879 if (a_is_Quadrupole) {
843     Q_a = *(idat.quadrupole1);
844     trQa = Q_a.trace();
845     Qar = Q_a * rhat;
846     rQa = rhat * Q_a;
847     rdQar = dot(rhat, Qar);
848     rxQar = cross(rhat, Qar);
849     if (!idat.excluded)
850     Eb -= pre14_ * (trQa * rhat * dv21 + 2.0 * Qar * v22or
851     + rdQar * rhat * (dv22 - 2.0*v22or));
852     }
853    
854     if (b_is_Charge) {
855     C_b = data2.fixedCharge;
856 gezelter 1502
857 gezelter 1879 if (b_is_Fluctuating)
858     C_b += *(idat.flucQ2);
859    
860 gezelter 1587 if (idat.excluded) {
861 gezelter 1879 *(idat.skippedCharge1) += C_b;
862     } else {
863     // only do the field if we're not excluded:
864     Ea += C_b * pre11_ * dv01 * rhat;
865 gezelter 1587 }
866     }
867 gezelter 1502
868 gezelter 1879 if (b_is_Dipole) {
869     D_b = *(idat.dipole2);
870     rdDb = dot(rhat, D_b);
871     rxDb = cross(rhat, D_b);
872     if (!idat.excluded)
873     Ea += pre12_ * ((dv11-v11or) * rdDb * rhat + v11or * D_b);
874 gezelter 1502 }
875    
876 gezelter 1879 if (b_is_Quadrupole) {
877     Q_b = *(idat.quadrupole2);
878     trQb = Q_b.trace();
879     Qbr = Q_b * rhat;
880     rQb = rhat * Q_b;
881     rdQbr = dot(rhat, Qbr);
882     rxQbr = cross(rhat, Qbr);
883     if (!idat.excluded)
884     Ea += pre14_ * (trQb * rhat * dv21 + 2.0 * Qbr * v22or
885     + rdQbr * rhat * (dv22 - 2.0*v22or));
886 gezelter 1721 }
887 gezelter 1502
888 gezelter 1879 if ((a_is_Fluctuating || b_is_Fluctuating) && idat.excluded) {
889 gezelter 1895 J = Jij[FQtids[idat.atid1]][FQtids[idat.atid2]];
890 gezelter 1879 }
891    
892     if (a_is_Charge) {
893 gezelter 1502
894 gezelter 1879 if (b_is_Charge) {
895     pref = pre11_ * *(idat.electroMult);
896     U += C_a * C_b * pref * v01;
897     F += C_a * C_b * pref * dv01 * rhat;
898    
899     // If this is an excluded pair, there are still indirect
900     // interactions via the reaction field we must worry about:
901 gezelter 1616
902 gezelter 1879 if (summationMethod_ == esm_REACTION_FIELD && idat.excluded) {
903     rfContrib = preRF_ * pref * C_a * C_b * *(idat.r2);
904     indirect_Pot += rfContrib;
905     indirect_F += rfContrib * 2.0 * ri * rhat;
906 gezelter 1502 }
907    
908 gezelter 1879 // Fluctuating charge forces are handled via Coulomb integrals
909     // for excluded pairs (i.e. those connected via bonds) and
910     // with the standard charge-charge interaction otherwise.
911 gezelter 1502
912 gezelter 1879 if (idat.excluded) {
913     if (a_is_Fluctuating || b_is_Fluctuating) {
914     coulInt = J->getValueAt( *(idat.rij) );
915     if (a_is_Fluctuating) dUdCa += coulInt * C_b;
916     if (b_is_Fluctuating) dUdCb += coulInt * C_a;
917     excluded_Pot += C_a * C_b * coulInt;
918     }
919 gezelter 1502 } else {
920 gezelter 1879 if (a_is_Fluctuating) dUdCa += C_b * pref * v01;
921     if (a_is_Fluctuating) dUdCb += C_a * pref * v01;
922 gezelter 1721 }
923 gezelter 1502 }
924    
925 gezelter 1879 if (b_is_Dipole) {
926     pref = pre12_ * *(idat.electroMult);
927     U += C_a * pref * v11 * rdDb;
928     F += C_a * pref * ((dv11 - v11or) * rdDb * rhat + v11or * D_b);
929     Tb += C_a * pref * v11 * rxDb;
930 gezelter 1502
931 gezelter 1879 if (a_is_Fluctuating) dUdCa += pref * v11 * rdDb;
932 gezelter 1502
933 gezelter 1879 // Even if we excluded this pair from direct interactions, we
934     // still have the reaction-field-mediated charge-dipole
935     // interaction:
936 gezelter 1502
937 gezelter 1879 if (summationMethod_ == esm_REACTION_FIELD && idat.excluded) {
938     rfContrib = C_a * pref * preRF_ * 2.0 * *(idat.rij);
939     indirect_Pot += rfContrib * rdDb;
940     indirect_F += rfContrib * D_b / (*idat.rij);
941     indirect_Tb += C_a * pref * preRF_ * rxDb;
942 gezelter 1502 }
943     }
944    
945 gezelter 1879 if (b_is_Quadrupole) {
946     pref = pre14_ * *(idat.electroMult);
947     U += C_a * pref * (v21 * trQb + v22 * rdQbr);
948     F += C_a * pref * (trQb * dv21 * rhat + 2.0 * Qbr * v22or);
949     F += C_a * pref * rdQbr * rhat * (dv22 - 2.0*v22or);
950     Tb += C_a * pref * 2.0 * rxQbr * v22;
951 gezelter 1502
952 gezelter 1879 if (a_is_Fluctuating) dUdCa += pref * (v21 * trQb + v22 * rdQbr);
953 gezelter 1502 }
954     }
955    
956 gezelter 1879 if (a_is_Dipole) {
957 gezelter 1502
958 gezelter 1879 if (b_is_Charge) {
959     pref = pre12_ * *(idat.electroMult);
960 gezelter 1502
961 gezelter 1879 U -= C_b * pref * v11 * rdDa;
962     F -= C_b * pref * ((dv11-v11or) * rdDa * rhat + v11or * D_a);
963     Ta -= C_b * pref * v11 * rxDa;
964 gezelter 1502
965 gezelter 1879 if (b_is_Fluctuating) dUdCb -= pref * v11 * rdDa;
966 gezelter 1587
967 gezelter 1879 // Even if we excluded this pair from direct interactions,
968     // we still have the reaction-field-mediated charge-dipole
969     // interaction:
970     if (summationMethod_ == esm_REACTION_FIELD && idat.excluded) {
971     rfContrib = C_b * pref * preRF_ * 2.0 * *(idat.rij);
972     indirect_Pot -= rfContrib * rdDa;
973     indirect_F -= rfContrib * D_a / (*idat.rij);
974     indirect_Ta -= C_b * pref * preRF_ * rxDa;
975     }
976     }
977 gezelter 1587
978 gezelter 1879 if (b_is_Dipole) {
979     pref = pre22_ * *(idat.electroMult);
980     DadDb = dot(D_a, D_b);
981     DaxDb = cross(D_a, D_b);
982 gezelter 1502
983 gezelter 1879 U -= pref * (DadDb * v21 + rdDa * rdDb * v22);
984     F -= pref * (dv21 * DadDb * rhat + v22or * (rdDb * D_a + rdDa * D_b));
985     F -= pref * (rdDa * rdDb) * (dv22 - 2.0*v22or) * rhat;
986     Ta += pref * ( v21 * DaxDb - v22 * rdDb * rxDa);
987     Tb += pref * (-v21 * DaxDb - v22 * rdDa * rxDb);
988 gezelter 1723
989 gezelter 1879 // Even if we excluded this pair from direct interactions, we
990     // still have the reaction-field-mediated dipole-dipole
991     // interaction:
992     if (summationMethod_ == esm_REACTION_FIELD && idat.excluded) {
993     rfContrib = -pref * preRF_ * 2.0;
994     indirect_Pot += rfContrib * DadDb;
995     indirect_Ta += rfContrib * DaxDb;
996     indirect_Tb -= rfContrib * DaxDb;
997 gezelter 1723 }
998 gezelter 1502 }
999    
1000 gezelter 1879 if (b_is_Quadrupole) {
1001     pref = pre24_ * *(idat.electroMult);
1002     DadQb = D_a * Q_b;
1003     DadQbr = dot(D_a, Qbr);
1004     DaxQbr = cross(D_a, Qbr);
1005 gezelter 1502
1006 gezelter 1879 U -= pref * ((trQb*rdDa + 2.0*DadQbr)*v31 + rdDa*rdQbr*v32);
1007     F -= pref * (trQb*D_a + 2.0*DadQb) * v31or;
1008     F -= pref * (trQb*rdDa + 2.0*DadQbr) * (dv31-v31or) * rhat;
1009     F -= pref * (D_a*rdQbr + 2.0*rdDa*rQb) * v32or;
1010     F -= pref * (rdDa * rdQbr * rhat * (dv32-3.0*v32or));
1011     Ta += pref * ((-trQb*rxDa + 2.0 * DaxQbr)*v31 - rxDa*rdQbr*v32);
1012     Tb += pref * ((2.0*cross(DadQb, rhat) - 2.0*DaxQbr)*v31
1013     - 2.0*rdDa*rxQbr*v32);
1014     }
1015     }
1016 gezelter 1502
1017 gezelter 1879 if (a_is_Quadrupole) {
1018     if (b_is_Charge) {
1019     pref = pre14_ * *(idat.electroMult);
1020     U += C_b * pref * (v21 * trQa + v22 * rdQar);
1021     F += C_b * pref * (trQa * rhat * dv21 + 2.0 * Qar * v22or);
1022     F += C_b * pref * rdQar * rhat * (dv22 - 2.0*v22or);
1023     Ta += C_b * pref * 2.0 * rxQar * v22;
1024 gezelter 1502
1025 gezelter 1879 if (b_is_Fluctuating) dUdCb += pref * (v21 * trQa + v22 * rdQar);
1026     }
1027     if (b_is_Dipole) {
1028     pref = pre24_ * *(idat.electroMult);
1029     DbdQa = D_b * Q_a;
1030     DbdQar = dot(D_b, Qar);
1031     DbxQar = cross(D_b, Qar);
1032 gezelter 1502
1033 gezelter 1879 U += pref * ((trQa*rdDb + 2.0*DbdQar)*v31 + rdDb*rdQar*v32);
1034     F += pref * (trQa*D_b + 2.0*DbdQa) * v31or;
1035     F += pref * (trQa*rdDb + 2.0*DbdQar) * (dv31-v31or) * rhat;
1036     F += pref * (D_b*rdQar + 2.0*rdDb*rQa) * v32or;
1037     F += pref * (rdDb * rdQar * rhat * (dv32-3.0*v32or));
1038     Ta += pref * ((-2.0*cross(DbdQa, rhat) + 2.0*DbxQar)*v31
1039     + 2.0*rdDb*rxQar*v32);
1040     Tb += pref * ((trQa*rxDb - 2.0 * DbxQar)*v31 + rxDb*rdQar*v32);
1041 gezelter 1502 }
1042 gezelter 1879 if (b_is_Quadrupole) {
1043     pref = pre44_ * *(idat.electroMult); // yes
1044     QaQb = Q_a * Q_b;
1045     trQaQb = QaQb.trace();
1046     rQaQb = rhat * QaQb;
1047     QaQbr = QaQb * rhat;
1048     QaxQb = cross(Q_a, Q_b);
1049     rQaQbr = dot(rQa, Qbr);
1050     rQaxQbr = cross(rQa, Qbr);
1051    
1052     U += pref * (trQa * trQb + 2.0 * trQaQb) * v41;
1053     U += pref * (trQa * rdQbr + trQb * rdQar + 4.0 * rQaQbr) * v42;
1054     U += pref * (rdQar * rdQbr) * v43;
1055 gezelter 1502
1056 gezelter 1879 F += pref * rhat * (trQa * trQb + 2.0 * trQaQb)*dv41;
1057     F += pref*rhat*(trQa*rdQbr + trQb*rdQar + 4.0*rQaQbr)*(dv42-2.0*v42or);
1058     F += pref * rhat * (rdQar * rdQbr)*(dv43 - 4.0*v43or);
1059 gezelter 1502
1060 gezelter 1879 F += pref * 2.0 * (trQb*rQa + trQa*rQb) * v42or;
1061     F += pref * 4.0 * (rQaQb + QaQbr) * v42or;
1062     F += pref * 2.0 * (rQa*rdQbr + rdQar*rQb) * v43or;
1063 gezelter 1502
1064 gezelter 1879 Ta += pref * (- 4.0 * QaxQb * v41);
1065     Ta += pref * (- 2.0 * trQb * cross(rQa, rhat)
1066     + 4.0 * cross(rhat, QaQbr)
1067     - 4.0 * rQaxQbr) * v42;
1068     Ta += pref * 2.0 * cross(rhat,Qar) * rdQbr * v43;
1069 gezelter 1502
1070    
1071 gezelter 1879 Tb += pref * (+ 4.0 * QaxQb * v41);
1072     Tb += pref * (- 2.0 * trQa * cross(rQb, rhat)
1073     - 4.0 * cross(rQaQb, rhat)
1074     + 4.0 * rQaxQbr) * v42;
1075     // Possible replacement for line 2 above:
1076     // + 4.0 * cross(rhat, QbQar)
1077 gezelter 1502
1078 gezelter 1879 Tb += pref * 2.0 * cross(rhat,Qbr) * rdQar * v43;
1079 gezelter 1502
1080     }
1081     }
1082    
1083 gezelter 1879 if (idat.doElectricField) {
1084     *(idat.eField1) += Ea * *(idat.electroMult);
1085     *(idat.eField2) += Eb * *(idat.electroMult);
1086     }
1087 gezelter 1502
1088 gezelter 1879 if (a_is_Fluctuating) *(idat.dVdFQ1) += dUdCa * *(idat.sw);
1089     if (b_is_Fluctuating) *(idat.dVdFQ2) += dUdCb * *(idat.sw);
1090    
1091 gezelter 1587 if (!idat.excluded) {
1092    
1093 gezelter 1879 *(idat.vpair) += U;
1094     (*(idat.pot))[ELECTROSTATIC_FAMILY] += U * *(idat.sw);
1095     *(idat.f1) += F * *(idat.sw);
1096 gezelter 1587
1097 gezelter 1879 if (a_is_Dipole || a_is_Quadrupole)
1098     *(idat.t1) += Ta * *(idat.sw);
1099 gezelter 1587
1100 gezelter 1879 if (b_is_Dipole || b_is_Quadrupole)
1101     *(idat.t2) += Tb * *(idat.sw);
1102    
1103 gezelter 1587 } else {
1104    
1105     // only accumulate the forces and torques resulting from the
1106     // indirect reaction field terms.
1107 gezelter 1616
1108 gezelter 1879 *(idat.vpair) += indirect_Pot;
1109     (*(idat.excludedPot))[ELECTROSTATIC_FAMILY] += excluded_Pot;
1110     (*(idat.pot))[ELECTROSTATIC_FAMILY] += *(idat.sw) * indirect_Pot;
1111     *(idat.f1) += *(idat.sw) * indirect_F;
1112 gezelter 1761
1113 gezelter 1879 if (a_is_Dipole || a_is_Quadrupole)
1114     *(idat.t1) += *(idat.sw) * indirect_Ta;
1115    
1116     if (b_is_Dipole || b_is_Quadrupole)
1117     *(idat.t2) += *(idat.sw) * indirect_Tb;
1118 gezelter 1502 }
1119     return;
1120 gezelter 1879 }
1121 gezelter 1502
1122 gezelter 1545 void Electrostatic::calcSelfCorrection(SelfData &sdat) {
1123 gezelter 1879
1124 gezelter 1502 if (!initialized_) initialize();
1125 gezelter 1586
1126 gezelter 1895 ElectrostaticAtomData data = ElectrostaticMap[Etids[sdat.atid]];
1127 gezelter 1879
1128 gezelter 1502 // logicals
1129     bool i_is_Charge = data.is_Charge;
1130     bool i_is_Dipole = data.is_Dipole;
1131 gezelter 1900 bool i_is_Quadrupole = data.is_Quadrupole;
1132 jmichalk 1734 bool i_is_Fluctuating = data.is_Fluctuating;
1133 gezelter 1879 RealType C_a = data.fixedCharge;
1134 gezelter 1900 RealType self(0.0), preVal, DdD, trQ, trQQ;
1135    
1136     if (i_is_Dipole) {
1137     DdD = data.dipole.lengthSquare();
1138     }
1139    
1140 jmichalk 1734 if (i_is_Fluctuating) {
1141 gezelter 1879 C_a += *(sdat.flucQ);
1142 jmichalk 1734 // dVdFQ is really a force, so this is negative the derivative
1143     *(sdat.dVdFQ) -= *(sdat.flucQ) * data.hardness + data.electronegativity;
1144 gezelter 1761 (*(sdat.excludedPot))[ELECTROSTATIC_FAMILY] += (*sdat.flucQ) *
1145     (*(sdat.flucQ) * data.hardness * 0.5 + data.electronegativity);
1146 jmichalk 1734 }
1147 gezelter 1502
1148 gezelter 1879 switch (summationMethod_) {
1149     case esm_REACTION_FIELD:
1150    
1151     if (i_is_Charge) {
1152     // Self potential [see Wang and Hermans, "Reaction Field
1153     // Molecular Dynamics Simulation with Friedman’s Image Charge
1154     // Method," J. Phys. Chem. 99, 12001-12007 (1995).]
1155     preVal = pre11_ * preRF_ * C_a * C_a;
1156     (*(sdat.pot))[ELECTROSTATIC_FAMILY] -= 0.5 * preVal / cutoffRadius_;
1157     }
1158    
1159 gezelter 1502 if (i_is_Dipole) {
1160 gezelter 1900 (*(sdat.pot))[ELECTROSTATIC_FAMILY] -= pre22_ * preRF_ * DdD;
1161 gezelter 1502 }
1162 gezelter 1879
1163     break;
1164    
1165     case esm_SHIFTED_FORCE:
1166     case esm_SHIFTED_POTENTIAL:
1167 gezelter 1907 case esm_TAYLOR_SHIFTED:
1168 gezelter 1900 if (i_is_Charge)
1169     self += selfMult1_ * pre11_ * C_a * (C_a + *(sdat.skippedCharge));
1170     if (i_is_Dipole)
1171     self += selfMult2_ * pre22_ * DdD;
1172     if (i_is_Quadrupole) {
1173     trQ = data.quadrupole.trace();
1174     trQQ = (data.quadrupole * data.quadrupole).trace();
1175     self += selfMult4_ * pre44_ * (2.0*trQQ + trQ*trQ);
1176     if (i_is_Charge)
1177     self -= selfMult2_ * pre14_ * 2.0 * C_a * trQ;
1178 gezelter 1502 }
1179 gezelter 1900 (*(sdat.pot))[ELECTROSTATIC_FAMILY] += self;
1180 gezelter 1879 break;
1181     default:
1182     break;
1183 gezelter 1502 }
1184     }
1185 gezelter 1879
1186 gezelter 1545 RealType Electrostatic::getSuggestedCutoffRadius(pair<AtomType*, AtomType*> atypes) {
1187 gezelter 1505 // This seems to work moderately well as a default. There's no
1188     // inherent scale for 1/r interactions that we can standardize.
1189     // 12 angstroms seems to be a reasonably good guess for most
1190     // cases.
1191     return 12.0;
1192     }
1193 gezelter 1915
1194    
1195     void Electrostatic::ReciprocalSpaceSum () {
1196    
1197     RealType kPot = 0.0;
1198     RealType kVir = 0.0;
1199    
1200     const RealType mPoleConverter = 0.20819434; // converts from the
1201     // internal units of
1202     // Debye (for dipoles)
1203     // or Debye-angstroms
1204     // (for quadrupoles) to
1205     // electron angstroms or
1206     // electron-angstroms^2
1207    
1208     const RealType eConverter = 332.0637778; // convert the
1209     // Charge-Charge
1210     // electrostatic
1211     // interactions into kcal /
1212     // mol assuming distances
1213     // are measured in
1214     // angstroms.
1215    
1216     Mat3x3d hmat = info_->getSnapshotManager()->getCurrentSnapshot()->getHmat();
1217     Vector3d box = hmat.diagonals();
1218     RealType boxMax = box.max();
1219    
1220     //int kMax = int(pow(dampingAlpha_,2)*cutoffRadius_ * boxMax / M_PI);
1221     const int kMax = 5;
1222     int kSqMax = kMax*kMax + 2;
1223    
1224     int kLimit = kMax+1;
1225     int kLim2 = 2*kMax+1;
1226     int kSqLim = kSqMax;
1227    
1228     vector<RealType> AK(kSqLim+1, 0.0);
1229     RealType xcl = 2.0 * M_PI / box.x();
1230     RealType ycl = 2.0 * M_PI / box.y();
1231     RealType zcl = 2.0 * M_PI / box.z();
1232     RealType rcl = 2.0 * M_PI / boxMax;
1233     RealType rvol = 2.0 * M_PI /(box.x() * box.y() * box.z());
1234    
1235     if(dampingAlpha_ < 1.0e-12) return;
1236    
1237     RealType ralph = -0.25/pow(dampingAlpha_,2);
1238    
1239     // Calculate and store exponential factors
1240    
1241     vector<vector<Vector3d> > eCos;
1242     vector<vector<Vector3d> > eSin;
1243    
1244     int nMax = info_->getNAtoms();
1245    
1246     eCos.resize(kLimit+1);
1247     eSin.resize(kLimit+1);
1248     for (int j = 0; j < kLimit+1; j++) {
1249     eCos[j].resize(nMax);
1250     eSin[j].resize(nMax);
1251     }
1252    
1253     Vector3d t( 2.0 * M_PI );
1254     t.Vdiv(t, box);
1255    
1256     SimInfo::MoleculeIterator mi;
1257     Molecule::AtomIterator ai;
1258     int i;
1259     Vector3d r;
1260     Vector3d tt;
1261     Vector3d w;
1262     Vector3d u;
1263    
1264     for (Molecule* mol = info_->beginMolecule(mi); mol != NULL;
1265     mol = info_->nextMolecule(mi)) {
1266     for(Atom* atom = mol->beginAtom(ai); atom != NULL;
1267     atom = mol->nextAtom(ai)) {
1268    
1269     i = atom->getLocalIndex();
1270     r = atom->getPos();
1271     info_->getSnapshotManager()->getCurrentSnapshot()->wrapVector(r);
1272    
1273     tt.Vmul(t, r);
1274    
1275     eCos[1][i] = Vector3d(1.0, 1.0, 1.0);
1276     eSin[1][i] = Vector3d(0.0, 0.0, 0.0);
1277     eCos[2][i] = Vector3d(cos(tt.x()), cos(tt.y()), cos(tt.z()));
1278     eSin[2][i] = Vector3d(sin(tt.x()), sin(tt.y()), sin(tt.z()));
1279     u = 2.0 * eCos[1][i];
1280     eCos[3][i].Vmul(u, eCos[2][i]);
1281     eSin[3][i].Vmul(u, eSin[2][i]);
1282    
1283     for(int l = 3; l <= kLimit; l++) {
1284     w.Vmul(u, eCos[l-1][i]);
1285     eCos[l][i] = w - eCos[l-2][i];
1286     w.Vmul(u, eSin[l-1][i]);
1287     eSin[l][i] = w - eSin[l-2][i];
1288     }
1289     }
1290     }
1291    
1292     // Calculate and store AK coefficients:
1293    
1294     RealType eksq = 1.0;
1295     RealType expf = 0.0;
1296     if (ralph < 0.0) expf = exp(ralph*rcl*rcl);
1297     for (i = 1; i <= kSqLim; i++) {
1298     RealType rksq = float(i)*rcl*rcl;
1299     eksq = expf*eksq;
1300     AK[i] = eConverter * eksq/rksq;
1301     }
1302    
1303     /*
1304     * Loop over all k vectors k = 2 pi (ll/Lx, mm/Ly, nn/Lz)
1305     * the values of ll, mm and nn are selected so that the symmetry of
1306     * reciprocal lattice is taken into account i.e. the following
1307     * rules apply.
1308     *
1309     * ll ranges over the values 0 to kMax only.
1310     *
1311     * mm ranges over 0 to kMax when ll=0 and over
1312     * -kMax to kMax otherwise.
1313     * nn ranges over 1 to kMax when ll=mm=0 and over
1314     * -kMax to kMax otherwise.
1315     *
1316     * Hence the result of the summation must be doubled at the end.
1317     */
1318    
1319     std::vector<RealType> clm(nMax, 0.0);
1320     std::vector<RealType> slm(nMax, 0.0);
1321     std::vector<RealType> ckr(nMax, 0.0);
1322     std::vector<RealType> skr(nMax, 0.0);
1323     std::vector<RealType> ckc(nMax, 0.0);
1324     std::vector<RealType> cks(nMax, 0.0);
1325     std::vector<RealType> dkc(nMax, 0.0);
1326     std::vector<RealType> dks(nMax, 0.0);
1327     std::vector<RealType> qkc(nMax, 0.0);
1328     std::vector<RealType> qks(nMax, 0.0);
1329     std::vector<Vector3d> dxk(nMax, V3Zero);
1330     std::vector<Vector3d> qxk(nMax, V3Zero);
1331    
1332     int mMin = kLimit;
1333     int nMin = kLimit + 1;
1334     for (int l = 1; l <= kLimit; l++) {
1335     int ll =l - 1;
1336     RealType rl = xcl * float(ll);
1337     for (int mmm = mMin; mmm <= kLim2; mmm++) {
1338     int mm = mmm - kLimit;
1339     int m = abs(mm) + 1;
1340     RealType rm = ycl * float(mm);
1341     // Set temporary products of exponential terms
1342     for (Molecule* mol = info_->beginMolecule(mi); mol != NULL;
1343     mol = info_->nextMolecule(mi)) {
1344     for(Atom* atom = mol->beginAtom(ai); atom != NULL;
1345     atom = mol->nextAtom(ai)) {
1346    
1347     i = atom->getLocalIndex();
1348     if(mm < 0) {
1349     clm[i] = eCos[l][i].x()*eCos[m][i].y()
1350     + eSin[l][i].x()*eSin[m][i].y();
1351     slm[i] = eCos[l][i].x()*eCos[m][i].y()
1352     - eSin[m][i].y()*eCos[l][i].x();
1353     } else {
1354     clm[i] = eCos[l][i].x()*eCos[m][i].y()
1355     - eSin[l][i].x()*eSin[m][i].y();
1356     slm[i] = eSin[l][i].x()*eCos[m][i].y()
1357     + eSin[m][i].y()*eCos[l][i].x();
1358     }
1359     }
1360     }
1361     for (int nnn = nMin; nnn <= kLim2; nnn++) {
1362     int nn = nnn - kLimit;
1363     int n = abs(nn) + 1;
1364     RealType rn = zcl * float(nn);
1365     // Test on magnitude of k vector:
1366     int kk=ll*ll + mm*mm + nn*nn;
1367     if(kk <= kSqLim) {
1368     Vector3d kVec = Vector3d(rl, rm, rn);
1369     Mat3x3d k2 = outProduct(kVec, kVec);
1370     // Calculate exp(ikr) terms
1371     for (Molecule* mol = info_->beginMolecule(mi); mol != NULL;
1372     mol = info_->nextMolecule(mi)) {
1373     for(Atom* atom = mol->beginAtom(ai); atom != NULL;
1374     atom = mol->nextAtom(ai)) {
1375     i = atom->getLocalIndex();
1376    
1377     if (nn < 0) {
1378     ckr[i]=clm[i]*eCos[n][i].z()+slm[i]*eSin[n][i].z();
1379     skr[i]=slm[i]*eCos[n][i].z()-clm[i]*eSin[n][i].z();
1380     } else {
1381     ckr[i]=clm[i]*eCos[n][i].z()-slm[i]*eSin[n][i].z();
1382     skr[i]=slm[i]*eCos[n][i].z()+clm[i]*eSin[n][i].z();
1383     }
1384     }
1385     }
1386    
1387     // Calculate scalar and vector products for each site:
1388    
1389     for (Molecule* mol = info_->beginMolecule(mi); mol != NULL;
1390     mol = info_->nextMolecule(mi)) {
1391     for(Atom* atom = mol->beginAtom(ai); atom != NULL;
1392     atom = mol->nextAtom(ai)) {
1393     i = atom->getGlobalIndex();
1394     int atid = atom->getAtomType()->getIdent();
1395     ElectrostaticAtomData data = ElectrostaticMap[Etids[atid]];
1396    
1397     if (data.is_Charge) {
1398     RealType C = data.fixedCharge;
1399     if (atom->isFluctuatingCharge()) C += atom->getFlucQPos();
1400     ckc[i] = C * ckr[i];
1401     cks[i] = C * cks[i];
1402     }
1403    
1404     if (data.is_Dipole) {
1405     Vector3d D = atom->getDipole() * mPoleConverter;
1406     RealType dk = dot(kVec, D);
1407     dxk[i] = cross(kVec, D);
1408     dkc[i] = dk * ckr[i];
1409     dks[i] = dk * skr[i];
1410     }
1411     if (data.is_Quadrupole) {
1412     Mat3x3d Q = atom->getQuadrupole();
1413     Q *= mPoleConverter;
1414     RealType qk = -( Q * k2 ).trace();
1415     qxk[i] = -2.0 * cross(k2, Q);
1416     qkc[i] = qk * ckr[i];
1417     qks[i] = qk * skr[i];
1418     }
1419     }
1420     }
1421    
1422     // calculate vector sums
1423    
1424     RealType ckcs = std::accumulate(ckc.begin(),ckc.end(),0.0);
1425     RealType ckss = std::accumulate(cks.begin(),cks.end(),0.0);
1426     RealType dkcs = std::accumulate(dkc.begin(),dkc.end(),0.0);
1427     RealType dkss = std::accumulate(dks.begin(),dks.end(),0.0);
1428     RealType qkcs = std::accumulate(qkc.begin(),qkc.end(),0.0);
1429     RealType qkss = std::accumulate(qks.begin(),qks.end(),0.0);
1430    
1431     #ifdef IS_MPI
1432     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &ckcs, 1, MPI::REALTYPE,
1433     MPI::SUM);
1434     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &ckss, 1, MPI::REALTYPE,
1435     MPI::SUM);
1436     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &dkcs, 1, MPI::REALTYPE,
1437     MPI::SUM);
1438     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &dkss, 1, MPI::REALTYPE,
1439     MPI::SUM);
1440     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &qkcs, 1, MPI::REALTYPE,
1441     MPI::SUM);
1442     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &qkss, 1, MPI::REALTYPE,
1443     MPI::SUM);
1444     #endif
1445    
1446     // Accumulate potential energy and virial contribution:
1447    
1448     //cerr << "l, m, n = " << l << " " << m << " " << n << "\n";
1449     cerr << "kVec = " << kVec << "\n";
1450     cerr << "ckss = " << ckss << " ckcs = " << ckcs << "\n";
1451     kPot += 2.0 * rvol * AK[kk]*((ckss+dkcs-qkss)*(ckss+dkcs-qkss)
1452     + (ckcs-dkss-qkcs)*(ckcs-dkss-qkss));
1453     //cerr << "kspace pot = " << kPot << "\n";
1454     kVir -= 2.0 * rvol * AK[kk]*(ckcs*ckcs+ckss*ckss
1455     +4.0*(ckss*dkcs-ckcs*dkss)
1456     +3.0*(dkcs*dkcs+dkss*dkss)
1457     -6.0*(ckss*qkss+ckcs*qkcs)
1458     +8.0*(dkss*qkcs-dkcs*qkss)
1459     +5.0*(qkss*qkss+qkcs*qkcs));
1460    
1461     // Calculate force and torque for each site:
1462    
1463     for (Molecule* mol = info_->beginMolecule(mi); mol != NULL;
1464     mol = info_->nextMolecule(mi)) {
1465     for(Atom* atom = mol->beginAtom(ai); atom != NULL;
1466     atom = mol->nextAtom(ai)) {
1467    
1468     i = atom->getLocalIndex();
1469     int atid = atom->getAtomType()->getIdent();
1470     ElectrostaticAtomData data = ElectrostaticMap[Etids[atid]];
1471    
1472     RealType qfrc = AK[kk]*((cks[i]+dkc[i]-qks[i])*(ckcs-dkss-qkcs)
1473     - (ckc[i]-dks[i]-qkc[i])*(ckss+dkcs-qkss));
1474     RealType qtrq1 = AK[kk]*(skr[i]*(ckcs-dkss-qkcs)
1475     -ckr[i]*(ckss+dkcs-qkss));
1476     RealType qtrq2 = 2.0*AK[kk]*(ckr[i]*(ckcs-dkss-qkcs)+
1477     skr[i]*(ckss+dkcs-qkss));
1478    
1479    
1480     atom->addFrc( 4.0 * rvol * qfrc * kVec );
1481    
1482     if (data.is_Dipole) {
1483     atom->addTrq( 4.0 * rvol * qtrq1 * dxk[i] );
1484     }
1485     if (data.is_Quadrupole) {
1486     atom->addTrq( 4.0 * rvol * qtrq2 * qxk[i] );
1487     }
1488     }
1489     }
1490     }
1491     }
1492     }
1493     }
1494     }
1495 gezelter 1502 }

Properties

Name Value
svn:eol-style native