ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/branches/development/src/nonbonded/EAM.cpp
Revision: 1710
Committed: Fri May 18 21:44:02 2012 UTC (12 years, 11 months ago) by gezelter
File size: 13231 byte(s)
Log Message:
Added an adapter layer between the AtomType and the rest of the code to 
handle the bolt-on capabilities of new types. 

Fixed a long-standing bug in how storageLayout was being set to the maximum
possible value.

Started to add infrastructure for Polarizable and fluc-Q calculations.

File Contents

# User Rev Content
1 gezelter 1478 /*
2     * Copyright (c) 2005 The University of Notre Dame. All Rights Reserved.
3     *
4     * The University of Notre Dame grants you ("Licensee") a
5     * non-exclusive, royalty free, license to use, modify and
6     * redistribute this software in source and binary code form, provided
7     * that the following conditions are met:
8     *
9     * 1. Redistributions of source code must retain the above copyright
10     * notice, this list of conditions and the following disclaimer.
11     *
12     * 2. Redistributions in binary form must reproduce the above copyright
13     * notice, this list of conditions and the following disclaimer in the
14     * documentation and/or other materials provided with the
15     * distribution.
16     *
17     * This software is provided "AS IS," without a warranty of any
18     * kind. All express or implied conditions, representations and
19     * warranties, including any implied warranty of merchantability,
20     * fitness for a particular purpose or non-infringement, are hereby
21     * excluded. The University of Notre Dame and its licensors shall not
22     * be liable for any damages suffered by licensee as a result of
23     * using, modifying or distributing the software or its
24     * derivatives. In no event will the University of Notre Dame or its
25     * licensors be liable for any lost revenue, profit or data, or for
26     * direct, indirect, special, consequential, incidental or punitive
27     * damages, however caused and regardless of the theory of liability,
28     * arising out of the use of or inability to use software, even if the
29     * University of Notre Dame has been advised of the possibility of
30     * such damages.
31     *
32     * SUPPORT OPEN SCIENCE! If you use OpenMD or its source code in your
33     * research, please cite the appropriate papers when you publish your
34     * work. Good starting points are:
35     *
36     * [1] Meineke, et al., J. Comp. Chem. 26, 252-271 (2005).
37     * [2] Fennell & Gezelter, J. Chem. Phys. 124, 234104 (2006).
38     * [3] Sun, Lin & Gezelter, J. Chem. Phys. 128, 24107 (2008).
39 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 1478 */
42    
43     #include <stdio.h>
44     #include <string.h>
45    
46     #include <cmath>
47     #include "nonbonded/EAM.hpp"
48     #include "utils/simError.h"
49 gezelter 1479 #include "types/NonBondedInteractionType.hpp"
50 gezelter 1478
51    
52     namespace OpenMD {
53    
54 gezelter 1502 EAM::EAM() : name_("EAM"), initialized_(false), forceField_(NULL),
55 gezelter 1586 mixMeth_(eamJohnson), eamRcut_(0.0), haveCutoffRadius_(false) {}
56 gezelter 1478
57 gezelter 1710 CubicSpline* EAM::getPhi(AtomType* atomType1, AtomType* atomType2) {
58     EAMAdapter ea1 = EAMAdapter(atomType1);
59     EAMAdapter ea2 = EAMAdapter(atomType2);
60     CubicSpline* z1 = ea1.getZ();
61     CubicSpline* z2 = ea2.getZ();
62 gezelter 1478
63     // make the r grid:
64    
65    
66 gezelter 1481 // we need phi out to the largest value we'll encounter in the radial space;
67    
68     RealType rmax = 0.0;
69 gezelter 1710 rmax = max(rmax, ea1.getRcut());
70     rmax = max(rmax, ea1.getNr() * ea1.getDr());
71 gezelter 1478
72 gezelter 1710 rmax = max(rmax, ea2.getRcut());
73     rmax = max(rmax, ea2.getNr() * ea2.getDr());
74 gezelter 1481
75 gezelter 1478 // use the smallest dr (finest grid) to build our grid:
76    
77 gezelter 1710 RealType dr = min(ea1.getDr(), ea2.getDr());
78 gezelter 1481
79     int nr = int(rmax/dr + 0.5);
80    
81 gezelter 1478 vector<RealType> rvals;
82 gezelter 1481 for (int i = 0; i < nr; i++) rvals.push_back(RealType(i*dr));
83 gezelter 1478
84     // construct the pair potential:
85    
86     vector<RealType> phivals;
87     RealType phi;
88     RealType r;
89     RealType zi, zj;
90    
91     phivals.push_back(0.0);
92    
93     for (int i = 1; i < rvals.size(); i++ ) {
94     r = rvals[i];
95    
96 gezelter 1502 // only use z(r) if we're inside this atom's cutoff radius,
97     // otherwise, we'll use zero for the charge. This effectively
98     // means that our phi grid goes out beyond the cutoff of the
99     // pair potential
100 gezelter 1481
101 gezelter 1710 zi = r <= ea1.getRcut() ? z1->getValueAt(r) : 0.0;
102     zj = r <= ea2.getRcut() ? z2->getValueAt(r) : 0.0;
103 gezelter 1481
104 gezelter 1478 phi = 331.999296 * (zi * zj) / r;
105 gezelter 1481
106 gezelter 1478 phivals.push_back(phi);
107     }
108    
109     CubicSpline* cs = new CubicSpline();
110     cs->addPoints(rvals, phivals);
111     return cs;
112     }
113    
114 gezelter 1586 void EAM::setCutoffRadius( RealType rCut ) {
115     eamRcut_ = rCut;
116     haveCutoffRadius_ = true;
117     }
118    
119 gezelter 1478 void EAM::initialize() {
120    
121     // set up the mixing method:
122 gezelter 1479 ForceFieldOptions& fopts = forceField_->getForceFieldOptions();
123 gezelter 1481 string EAMMixMeth = fopts.getEAMMixingMethod();
124 gezelter 1480 toUpper(EAMMixMeth);
125    
126 gezelter 1478 if (EAMMixMeth == "JOHNSON")
127     mixMeth_ = eamJohnson;
128     else if (EAMMixMeth == "DAW")
129     mixMeth_ = eamDaw;
130     else
131     mixMeth_ = eamUnknown;
132    
133     // find all of the EAM atom Types:
134     ForceField::AtomTypeContainer* atomTypes = forceField_->getAtomTypes();
135     ForceField::AtomTypeContainer::MapTypeIterator i;
136     AtomType* at;
137    
138     for (at = atomTypes->beginType(i); at != NULL;
139     at = atomTypes->nextType(i)) {
140    
141     if (at->isEAM())
142     addType(at);
143     }
144    
145     // find all of the explicit EAM interactions (setfl):
146     ForceField::NonBondedInteractionTypeContainer* nbiTypes = forceField_->getNonBondedInteractionTypes();
147     ForceField::NonBondedInteractionTypeContainer::MapTypeIterator j;
148     NonBondedInteractionType* nbt;
149    
150     for (nbt = nbiTypes->beginType(j); nbt != NULL;
151     nbt = nbiTypes->nextType(j)) {
152    
153     if (nbt->isEAM()) {
154    
155 gezelter 1481 pair<AtomType*, AtomType*> atypes = nbt->getAtomTypes();
156 gezelter 1478
157     GenericData* data = nbt->getPropertyByName("EAM");
158     if (data == NULL) {
159     sprintf( painCave.errMsg, "EAM::rebuildMixingMap could not find\n"
160     "\tEAM parameters for %s - %s interaction.\n",
161     atypes.first->getName().c_str(),
162     atypes.second->getName().c_str());
163     painCave.severity = OPENMD_ERROR;
164     painCave.isFatal = 1;
165     simError();
166     }
167    
168     EAMMixingData* eamData = dynamic_cast<EAMMixingData*>(data);
169     if (eamData == NULL) {
170     sprintf( painCave.errMsg,
171     "EAM::rebuildMixingMap could not convert GenericData to\n"
172     "\tEAMMixingData for %s - %s interaction.\n",
173     atypes.first->getName().c_str(),
174     atypes.second->getName().c_str());
175     painCave.severity = OPENMD_ERROR;
176     painCave.isFatal = 1;
177     simError();
178     }
179    
180 gezelter 1479 EAMMixingParam eamParam = eamData->getData();
181 gezelter 1478
182 gezelter 1479 vector<RealType> phiAB = eamParam.phi;
183 gezelter 1478 RealType dr = eamParam.dr;
184     int nr = eamParam.nr;
185    
186     addExplicitInteraction(atypes.first, atypes.second, dr, nr, phiAB);
187     }
188     }
189     initialized_ = true;
190     }
191    
192    
193    
194     void EAM::addType(AtomType* atomType){
195    
196 gezelter 1710 EAMAdapter ea = EAMAdapter(atomType);
197 gezelter 1478 EAMAtomData eamAtomData;
198    
199 gezelter 1710 eamAtomData.rho = ea.getRho();
200     eamAtomData.F = ea.getF();
201     eamAtomData.Z = ea.getZ();
202     eamAtomData.rcut = ea.getRcut();
203    
204 gezelter 1478 // add it to the map:
205    
206 gezelter 1481 pair<map<int,AtomType*>::iterator,bool> ret;
207 gezelter 1710 ret = EAMlist.insert( pair<int, AtomType*>(atomType->getIdent(), atomType) );
208 gezelter 1478 if (ret.second == false) {
209     sprintf( painCave.errMsg,
210     "EAM already had a previous entry with ident %d\n",
211 gezelter 1710 atomType->getIdent());
212 gezelter 1478 painCave.severity = OPENMD_INFO;
213     painCave.isFatal = 0;
214     simError();
215     }
216    
217     EAMMap[atomType] = eamAtomData;
218    
219     // Now, iterate over all known types and add to the mixing map:
220    
221 gezelter 1481 map<AtomType*, EAMAtomData>::iterator it;
222 gezelter 1478 for( it = EAMMap.begin(); it != EAMMap.end(); ++it) {
223    
224 gezelter 1479 AtomType* atype2 = (*it).first;
225 gezelter 1478
226     EAMInteractionData mixer;
227     mixer.phi = getPhi(atomType, atype2);
228     mixer.explicitlySet = false;
229    
230 gezelter 1481 pair<AtomType*, AtomType*> key1, key2;
231     key1 = make_pair(atomType, atype2);
232     key2 = make_pair(atype2, atomType);
233 gezelter 1478
234     MixingMap[key1] = mixer;
235     if (key2 != key1) {
236     MixingMap[key2] = mixer;
237     }
238     }
239     return;
240     }
241    
242     void EAM::addExplicitInteraction(AtomType* atype1, AtomType* atype2,
243     RealType dr, int nr,
244     vector<RealType> phiVals) {
245    
246     // in case these weren't already in the map
247     addType(atype1);
248     addType(atype2);
249    
250     EAMInteractionData mixer;
251     CubicSpline* cs = new CubicSpline();
252 gezelter 1479 vector<RealType> rVals;
253 gezelter 1478
254 gezelter 1479 for (int i = 0; i < nr; i++) rVals.push_back(i * dr);
255 gezelter 1478
256     cs->addPoints(rVals, phiVals);
257     mixer.phi = cs;
258     mixer.explicitlySet = true;
259    
260 gezelter 1481 pair<AtomType*, AtomType*> key1, key2;
261     key1 = make_pair(atype1, atype2);
262     key2 = make_pair(atype2, atype1);
263 gezelter 1478
264     MixingMap[key1] = mixer;
265     if (key2 != key1) {
266     MixingMap[key2] = mixer;
267     }
268     return;
269     }
270    
271 gezelter 1545 void EAM::calcDensity(InteractionData &idat) {
272 gezelter 1479
273 gezelter 1478 if (!initialized_) initialize();
274 gezelter 1479
275 gezelter 1571 EAMAtomData data1 = EAMMap[idat.atypes.first];
276     EAMAtomData data2 = EAMMap[idat.atypes.second];
277 gezelter 1586
278     if (haveCutoffRadius_)
279     if ( *(idat.rij) > eamRcut_) return;
280    
281 gezelter 1629 if ( *(idat.rij) < data1.rcut)
282 gezelter 1575 *(idat.rho1) += data1.rho->getValueAt( *(idat.rij));
283 gezelter 1629
284 gezelter 1586
285 gezelter 1629 if ( *(idat.rij) < data2.rcut)
286     *(idat.rho2) += data2.rho->getValueAt( *(idat.rij));
287    
288     return;
289 gezelter 1478 }
290 gezelter 1586
291 gezelter 1545 void EAM::calcFunctional(SelfData &sdat) {
292 gezelter 1586
293 gezelter 1478 if (!initialized_) initialize();
294    
295 gezelter 1554 EAMAtomData data1 = EAMMap[ sdat.atype ];
296 gezelter 1478
297 gezelter 1554 pair<RealType, RealType> result = data1.F->getValueAndDerivativeAt( *(sdat.rho) );
298 gezelter 1478
299 gezelter 1554 *(sdat.frho) = result.first;
300     *(sdat.dfrhodrho) = result.second;
301 gezelter 1575
302 gezelter 1586 (*(sdat.pot))[METALLIC_FAMILY] += result.first;
303 gezelter 1575 *(sdat.particlePot) += result.first;
304    
305 gezelter 1478 return;
306     }
307    
308    
309 gezelter 1536 void EAM::calcForce(InteractionData &idat) {
310 gezelter 1478
311     if (!initialized_) initialize();
312 gezelter 1481
313 gezelter 1586 if (haveCutoffRadius_)
314     if ( *(idat.rij) > eamRcut_) return;
315    
316 gezelter 1478 pair<RealType, RealType> res;
317    
318 gezelter 1586 EAMAtomData data1 = EAMMap[idat.atypes.first];
319     EAMAtomData data2 = EAMMap[idat.atypes.second];
320    
321     // get type-specific cutoff radii
322    
323     RealType rci = data1.rcut;
324     RealType rcj = data2.rcut;
325    
326     RealType rha(0.0), drha(0.0), rhb(0.0), drhb(0.0);
327     RealType pha(0.0), dpha(0.0), phb(0.0), dphb(0.0);
328     RealType phab(0.0), dvpdr(0.0);
329     RealType drhoidr, drhojdr, dudr;
330    
331     if ( *(idat.rij) < rci) {
332     res = data1.rho->getValueAndDerivativeAt( *(idat.rij));
333     rha = res.first;
334     drha = res.second;
335    
336     res = MixingMap[make_pair(idat.atypes.first, idat.atypes.first)].phi->getValueAndDerivativeAt( *(idat.rij) );
337     pha = res.first;
338     dpha = res.second;
339     }
340    
341     if ( *(idat.rij) < rcj) {
342     res = data2.rho->getValueAndDerivativeAt( *(idat.rij) );
343     rhb = res.first;
344     drhb = res.second;
345    
346     res = MixingMap[make_pair(idat.atypes.second, idat.atypes.second)].phi->getValueAndDerivativeAt( *(idat.rij) );
347     phb = res.first;
348     dphb = res.second;
349     }
350 gezelter 1478
351 gezelter 1586 switch(mixMeth_) {
352     case eamJohnson:
353 gezelter 1478
354 gezelter 1554 if ( *(idat.rij) < rci) {
355 gezelter 1586 phab = phab + 0.5 * (rhb / rha) * pha;
356     dvpdr = dvpdr + 0.5*((rhb/rha)*dpha +
357     pha*((drhb/rha) - (rhb*drha/rha/rha)));
358 gezelter 1478 }
359 gezelter 1586
360    
361    
362 gezelter 1554 if ( *(idat.rij) < rcj) {
363 gezelter 1586 phab = phab + 0.5 * (rha / rhb) * phb;
364     dvpdr = dvpdr + 0.5 * ((rha/rhb)*dphb +
365     phb*((drha/rhb) - (rha*drhb/rhb/rhb)));
366 gezelter 1478 }
367    
368 gezelter 1586 break;
369    
370     case eamDaw:
371     res = MixingMap[idat.atypes].phi->getValueAndDerivativeAt( *(idat.rij));
372     phab = res.first;
373     dvpdr = res.second;
374    
375     break;
376     case eamUnknown:
377     default:
378    
379     sprintf(painCave.errMsg,
380     "EAM::calcForce hit a mixing method it doesn't know about!\n"
381     );
382     painCave.severity = OPENMD_ERROR;
383     painCave.isFatal = 1;
384     simError();
385    
386     }
387    
388     drhoidr = drha;
389     drhojdr = drhb;
390    
391     dudr = drhojdr* *(idat.dfrho1) + drhoidr* *(idat.dfrho2) + dvpdr;
392    
393     *(idat.f1) += *(idat.d) * dudr / *(idat.rij);
394 gezelter 1478
395 gezelter 1586 // particlePot is the difference between the full potential and
396     // the full potential without the presence of a particular
397     // particle (atom1).
398     //
399     // This reduces the density at other particle locations, so we
400     // need to recompute the density at atom2 assuming atom1 didn't
401     // contribute. This then requires recomputing the density
402     // functional for atom2 as well.
403    
404     *(idat.particlePot1) += data2.F->getValueAt( *(idat.rho2) - rha )
405     - *(idat.frho2);
406    
407     *(idat.particlePot2) += data1.F->getValueAt( *(idat.rho1) - rhb)
408     - *(idat.frho1);
409    
410     (*(idat.pot))[METALLIC_FAMILY] += phab;
411    
412     *(idat.vpair) += phab;
413    
414 gezelter 1478 return;
415    
416     }
417 gezelter 1505
418 gezelter 1545 RealType EAM::getSuggestedCutoffRadius(pair<AtomType*, AtomType*> atypes) {
419 gezelter 1505 if (!initialized_) initialize();
420    
421     RealType cut = 0.0;
422    
423     map<AtomType*, EAMAtomData>::iterator it;
424    
425 gezelter 1545 it = EAMMap.find(atypes.first);
426 gezelter 1505 if (it != EAMMap.end()) {
427     EAMAtomData data1 = (*it).second;
428     cut = data1.rcut;
429     }
430    
431 gezelter 1545 it = EAMMap.find(atypes.second);
432 gezelter 1505 if (it != EAMMap.end()) {
433     EAMAtomData data2 = (*it).second;
434     if (data2.rcut > cut)
435     cut = data2.rcut;
436     }
437    
438     return cut;
439     }
440 gezelter 1478 }
441    

Properties

Name Value
svn:eol-style native