ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/trunk/src/nonbonded/SC.cpp
Revision: 1895
Committed: Mon Jul 1 21:09:37 2013 UTC (11 years, 10 months ago) by gezelter
File size: 11330 byte(s)
Log Message:
Speed!

File Contents

# Content
1 /*
2 * Copyright (c) 2005 The University of Notre Dame. All Rights Reserved.
3 *
4 * The University of Notre Dame grants you ("Licensee") a
5 * non-exclusive, royalty free, license to use, modify and
6 * redistribute this software in source and binary code form, provided
7 * that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the
15 * distribution.
16 *
17 * This software is provided "AS IS," without a warranty of any
18 * kind. All express or implied conditions, representations and
19 * warranties, including any implied warranty of merchantability,
20 * fitness for a particular purpose or non-infringement, are hereby
21 * excluded. The University of Notre Dame and its licensors shall not
22 * be liable for any damages suffered by licensee as a result of
23 * using, modifying or distributing the software or its
24 * derivatives. In no event will the University of Notre Dame or its
25 * licensors be liable for any lost revenue, profit or data, or for
26 * direct, indirect, special, consequential, incidental or punitive
27 * damages, however caused and regardless of the theory of liability,
28 * arising out of the use of or inability to use software, even if the
29 * University of Notre Dame has been advised of the possibility of
30 * such damages.
31 *
32 * SUPPORT OPEN SCIENCE! If you use OpenMD or its source code in your
33 * research, please cite the appropriate papers when you publish your
34 * work. Good starting points are:
35 *
36 * [1] Meineke, et al., J. Comp. Chem. 26, 252-271 (2005).
37 * [2] Fennell & Gezelter, J. Chem. Phys. 124, 234104 (2006).
38 * [3] Sun, Lin & Gezelter, J. Chem. Phys. 128, 234107 (2008).
39 * [4] Kuang & Gezelter, J. Chem. Phys. 133, 164101 (2010).
40 * [5] Vardeman, Stocker & Gezelter, J. Chem. Theory Comput. 7, 834 (2011).
41 */
42
43 #include <stdio.h>
44 #include <string.h>
45
46 #include <cmath>
47 #include "nonbonded/SC.hpp"
48 #include "utils/simError.h"
49 #include "types/NonBondedInteractionType.hpp"
50
51 namespace OpenMD {
52
53
54 SC::SC() : name_("SC"), initialized_(false), forceField_(NULL),
55 scRcut_(0.0), np_(3000) {}
56
57 SC::~SC() {
58 initialized_ = false;
59
60 MixingMap.clear();
61 SCtypes.clear();
62 SCdata.clear();
63 SCtids.clear();
64 }
65
66 RealType SC::getM(AtomType* atomType1, AtomType* atomType2) {
67 SuttonChenAdapter sca1 = SuttonChenAdapter(atomType1);
68 SuttonChenAdapter sca2 = SuttonChenAdapter(atomType2);
69 RealType m1 = sca1.getM();
70 RealType m2 = sca2.getM();
71 return 0.5 * (m1 + m2);
72 }
73
74 RealType SC::getN(AtomType* atomType1, AtomType* atomType2) {
75 SuttonChenAdapter sca1 = SuttonChenAdapter(atomType1);
76 SuttonChenAdapter sca2 = SuttonChenAdapter(atomType2);
77 RealType n1 = sca1.getN();
78 RealType n2 = sca2.getN();
79 return 0.5 * (n1 + n2);
80 }
81
82 RealType SC::getAlpha(AtomType* atomType1, AtomType* atomType2) {
83 SuttonChenAdapter sca1 = SuttonChenAdapter(atomType1);
84 SuttonChenAdapter sca2 = SuttonChenAdapter(atomType2);
85 RealType alpha1 = sca1.getAlpha();
86 RealType alpha2 = sca2.getAlpha();
87
88 ForceFieldOptions& fopts = forceField_->getForceFieldOptions();
89 std::string DistanceMix = fopts.getDistanceMixingRule();
90 toUpper(DistanceMix);
91
92 if (DistanceMix == "GEOMETRIC")
93 return sqrt(alpha1 * alpha2);
94 else
95 return 0.5 * (alpha1 + alpha2);
96 }
97
98 RealType SC::getEpsilon(AtomType* atomType1, AtomType* atomType2) {
99 SuttonChenAdapter sca1 = SuttonChenAdapter(atomType1);
100 SuttonChenAdapter sca2 = SuttonChenAdapter(atomType2);
101 RealType epsilon1 = sca1.getEpsilon();
102 RealType epsilon2 = sca2.getEpsilon();
103 return sqrt(epsilon1 * epsilon2);
104 }
105
106 void SC::initialize() {
107 // find all of the SC atom Types:
108 SCtypes.clear();
109 SCtids.clear();
110 SCdata.clear();
111 MixingMap.clear();
112 nSC_ = 0;
113
114 SCtids.resize( forceField_->getNAtomType(), -1);
115
116 set<AtomType*>::iterator at;
117 for (at = simTypes_.begin(); at != simTypes_.end(); ++at) {
118 if ((*at)->isSC()) nSC_++;
119 }
120 SCdata.resize(nSC_);
121 MixingMap.resize(nSC_);
122 for (at = simTypes_.begin(); at != simTypes_.end(); ++at) {
123 if ((*at)->isSC()) addType((*at));
124 }
125 initialized_ = true;
126 }
127
128
129
130 void SC::addType(AtomType* atomType){
131
132 SuttonChenAdapter sca = SuttonChenAdapter(atomType);
133 SCAtomData scAtomData;
134
135 scAtomData.c = sca.getC();
136 scAtomData.m = sca.getM();
137 scAtomData.n = sca.getN();
138 scAtomData.alpha = sca.getAlpha();
139 scAtomData.epsilon = sca.getEpsilon();
140 scAtomData.rCut = 2.0 * scAtomData.alpha;
141
142 // add it to the map:
143 int atid = atomType->getIdent();
144 int sctid = SCtypes.size();
145
146 pair<set<int>::iterator,bool> ret;
147 ret = SCtypes.insert( atid );
148 if (ret.second == false) {
149 sprintf( painCave.errMsg,
150 "SC already had a previous entry with ident %d\n",
151 atid );
152 painCave.severity = OPENMD_INFO;
153 painCave.isFatal = 0;
154 simError();
155 }
156
157 SCtids[atid] = sctid;
158 SCdata[sctid] = scAtomData;
159 MixingMap[sctid].resize(nSC_);
160
161 // Now, iterate over all known types and add to the mixing map:
162
163 std::set<int>::iterator it;
164 for( it = SCtypes.begin(); it != SCtypes.end(); ++it) {
165
166 int sctid2 = SCtids[ (*it) ];
167 AtomType* atype2 = forceField_->getAtomType( (*it) );
168
169 SCInteractionData mixer;
170
171 mixer.alpha = getAlpha(atomType, atype2);
172 mixer.rCut = 2.0 * mixer.alpha;
173 mixer.epsilon = getEpsilon(atomType, atype2);
174 mixer.m = getM(atomType, atype2);
175 mixer.n = getN(atomType, atype2);
176
177 RealType dr = mixer.rCut / (np_ - 1);
178 vector<RealType> rvals;
179 vector<RealType> vvals;
180 vector<RealType> phivals;
181
182 rvals.push_back(0.0);
183 vvals.push_back(0.0);
184 phivals.push_back(0.0);
185
186 for (int k = 1; k < np_; k++) {
187 RealType r = dr * k;
188 rvals.push_back(r);
189 vvals.push_back( mixer.epsilon * pow(mixer.alpha/r, mixer.n) );
190 phivals.push_back( pow(mixer.alpha/r, mixer.m) );
191 }
192
193 mixer.vCut = mixer.epsilon * pow(mixer.alpha/mixer.rCut, mixer.n);
194
195 CubicSpline* V = new CubicSpline();
196 V->addPoints(rvals, vvals);
197
198 CubicSpline* phi = new CubicSpline();
199 phi->addPoints(rvals, phivals);
200
201 mixer.V = V;
202 mixer.phi = phi;
203
204 mixer.explicitlySet = false;
205
206 MixingMap[sctid2].resize( nSC_ );
207
208 MixingMap[sctid][sctid2] = mixer;
209 if (sctid2 != sctid) {
210 MixingMap[sctid2][sctid] = mixer;
211 }
212 }
213 return;
214 }
215
216 void SC::addExplicitInteraction(AtomType* atype1, AtomType* atype2,
217 RealType epsilon, RealType m, RealType n,
218 RealType alpha) {
219
220 // in case these weren't already in the map
221 addType(atype1);
222 addType(atype2);
223
224 SCInteractionData mixer;
225
226 mixer.epsilon = epsilon;
227 mixer.m = m;
228 mixer.n = n;
229 mixer.alpha = alpha;
230 mixer.rCut = 2.0 * mixer.alpha;
231
232 RealType dr = mixer.rCut / (np_ - 1);
233 vector<RealType> rvals;
234 vector<RealType> vvals;
235 vector<RealType> phivals;
236
237 rvals.push_back(0.0);
238 vvals.push_back(0.0);
239 phivals.push_back(0.0);
240
241 for (int k = 1; k < np_; k++) {
242 RealType r = dr * k;
243 rvals.push_back(r);
244 vvals.push_back( mixer.epsilon * pow(mixer.alpha/r, mixer.n) );
245 phivals.push_back( pow(mixer.alpha/r, mixer.m) );
246 }
247
248 mixer.vCut = mixer.epsilon * pow(mixer.alpha/mixer.rCut, mixer.n);
249
250 CubicSpline* V = new CubicSpline();
251 V->addPoints(rvals, vvals);
252
253 CubicSpline* phi = new CubicSpline();
254 phi->addPoints(rvals, phivals);
255
256 mixer.V = V;
257 mixer.phi = phi;
258
259 mixer.explicitlySet = true;
260
261 int sctid1 = SCtids[ atype1->getIdent() ];
262 int sctid2 = SCtids[ atype2->getIdent() ];
263
264 MixingMap[sctid1][sctid2] = mixer;
265 if (sctid2 != sctid1) {
266 MixingMap[sctid2][sctid1] = mixer;
267 }
268 return;
269 }
270
271 void SC::calcDensity(InteractionData &idat) {
272
273 if (!initialized_) initialize();
274 int sctid1 = SCtids[idat.atid1];
275 int sctid2 = SCtids[idat.atid2];
276
277 SCInteractionData &mixer = MixingMap[sctid1][sctid2];
278
279 RealType rcij = mixer.rCut;
280
281 if ( *(idat.rij) < rcij) {
282 RealType rho = mixer.phi->getValueAt( *(idat.rij) );
283 *(idat.rho1) += rho;
284 *(idat.rho2) += rho;
285 }
286
287 return;
288 }
289
290 void SC::calcFunctional(SelfData &sdat) {
291
292 if (!initialized_) initialize();
293
294 SCAtomData &data1 = SCdata[SCtids[sdat.atid]];
295
296 RealType u = - data1.c * data1.epsilon * sqrt( *(sdat.rho) );
297 *(sdat.frho) = u;
298 *(sdat.dfrhodrho) = 0.5 * *(sdat.frho) / *(sdat.rho);
299
300 (*(sdat.pot))[METALLIC_FAMILY] += u;
301 if (sdat.doParticlePot) {
302 *(sdat.particlePot) += u;
303 }
304
305 return;
306 }
307
308
309 void SC::calcForce(InteractionData &idat) {
310
311 if (!initialized_) initialize();
312
313 int &sctid1 = SCtids[idat.atid1];
314 int &sctid2 = SCtids[idat.atid2];
315
316 SCAtomData &data1 = SCdata[sctid1];
317 SCAtomData &data2 = SCdata[sctid2];
318
319 SCInteractionData &mixer = MixingMap[sctid1][sctid2];
320
321 RealType rcij = mixer.rCut;
322
323 if ( *(idat.rij) < rcij) {
324 RealType vcij = mixer.vCut;
325 RealType rhtmp, drhodr, vptmp, dvpdr;
326
327 mixer.phi->getValueAndDerivativeAt( *(idat.rij), rhtmp, drhodr );
328 mixer.V->getValueAndDerivativeAt( *(idat.rij), vptmp, dvpdr);
329
330 RealType pot_temp = vptmp - vcij;
331 *(idat.vpair) += pot_temp;
332
333 RealType dudr = drhodr * ( *(idat.dfrho1) + *(idat.dfrho2) ) + dvpdr;
334
335 *(idat.f1) += *(idat.d) * dudr / *(idat.rij) ;
336
337 if (idat.doParticlePot) {
338 // particlePot is the difference between the full potential and
339 // the full potential without the presence of a particular
340 // particle (atom1).
341 //
342 // This reduces the density at other particle locations, so we
343 // need to recompute the density at atom2 assuming atom1 didn't
344 // contribute. This then requires recomputing the density
345 // functional for atom2 as well.
346
347 *(idat.particlePot1) -= data2.c * data2.epsilon *
348 sqrt( *(idat.rho2) - rhtmp) + *(idat.frho2);
349
350 *(idat.particlePot2) -= data1.c * data1.epsilon *
351 sqrt( *(idat.rho1) - rhtmp) + *(idat.frho1);
352 }
353
354 (*(idat.pot))[METALLIC_FAMILY] += pot_temp;
355 }
356
357 return;
358 }
359
360 RealType SC::getSuggestedCutoffRadius(pair<AtomType*, AtomType*> atypes) {
361 if (!initialized_) initialize();
362
363 int atid1 = atypes.first->getIdent();
364 int atid2 = atypes.second->getIdent();
365 int &sctid1 = SCtids[atid1];
366 int &sctid2 = SCtids[atid2];
367
368 if (sctid1 == -1 || sctid2 == -1) {
369 return 0.0;
370 } else {
371 return MixingMap[sctid1][sctid2].rCut;
372 }
373 }
374 }

Properties

Name Value
svn:eol-style native