ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/branches/development/src/nonbonded/EAM.cpp
Revision: 1665
Committed: Tue Nov 22 20:38:56 2011 UTC (13 years, 5 months ago) by gezelter
File size: 15892 byte(s)
Log Message:
updated copyright notices

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     EAMParam EAM::getEAMParam(AtomType* atomType) {
58    
59     // Do sanity checking on the AtomType we were passed before
60     // building any data structures:
61     if (!atomType->isEAM()) {
62     sprintf( painCave.errMsg,
63     "EAM::getEAMParam was passed an atomType (%s) that does not\n"
64     "\tappear to be an embedded atom method (EAM) atom.\n",
65     atomType->getName().c_str());
66     painCave.severity = OPENMD_ERROR;
67     painCave.isFatal = 1;
68     simError();
69     }
70    
71     GenericData* data = atomType->getPropertyByName("EAM");
72     if (data == NULL) {
73     sprintf( painCave.errMsg, "EAM::getEAMParam could not find EAM\n"
74     "\tparameters for atomType %s.\n",
75     atomType->getName().c_str());
76     painCave.severity = OPENMD_ERROR;
77     painCave.isFatal = 1;
78     simError();
79     }
80    
81     EAMParamGenericData* eamData = dynamic_cast<EAMParamGenericData*>(data);
82     if (eamData == NULL) {
83     sprintf( painCave.errMsg,
84     "EAM::getEAMParam could not convert GenericData to EAMParam for\n"
85     "\tatom type %s\n", atomType->getName().c_str());
86     painCave.severity = OPENMD_ERROR;
87     painCave.isFatal = 1;
88     simError();
89     }
90    
91     return eamData->getData();
92     }
93    
94     CubicSpline* EAM::getZ(AtomType* atomType) {
95     EAMParam eamParam = getEAMParam(atomType);
96     int nr = eamParam.nr;
97     RealType dr = eamParam.dr;
98     vector<RealType> rvals;
99    
100 gezelter 1482 for (int i = 0; i < nr; i++) rvals.push_back(RealType(i) * dr);
101 gezelter 1478
102     CubicSpline* cs = new CubicSpline();
103     cs->addPoints(rvals, eamParam.Z);
104     return cs;
105     }
106    
107 gezelter 1479 RealType EAM::getRcut(AtomType* atomType) {
108     EAMParam eamParam = getEAMParam(atomType);
109     return eamParam.rcut;
110     }
111    
112 gezelter 1478 CubicSpline* EAM::getRho(AtomType* atomType) {
113     EAMParam eamParam = getEAMParam(atomType);
114     int nr = eamParam.nr;
115     RealType dr = eamParam.dr;
116     vector<RealType> rvals;
117    
118 gezelter 1482 for (int i = 0; i < nr; i++) rvals.push_back(RealType(i) * dr);
119 gezelter 1478
120     CubicSpline* cs = new CubicSpline();
121     cs->addPoints(rvals, eamParam.rho);
122     return cs;
123     }
124    
125     CubicSpline* EAM::getF(AtomType* atomType) {
126     EAMParam eamParam = getEAMParam(atomType);
127     int nrho = eamParam.nrho;
128     RealType drho = eamParam.drho;
129     vector<RealType> rhovals;
130     vector<RealType> scaledF;
131    
132     for (int i = 0; i < nrho; i++) {
133 gezelter 1482 rhovals.push_back(RealType(i) * drho);
134 gezelter 1478 scaledF.push_back( eamParam.F[i] * 23.06054 );
135     }
136    
137     CubicSpline* cs = new CubicSpline();
138 gezelter 1482 cs->addPoints(rhovals, scaledF);
139 gezelter 1478 return cs;
140     }
141    
142     CubicSpline* EAM::getPhi(AtomType* atomType1, AtomType* atomType2) {
143     EAMParam eamParam1 = getEAMParam(atomType1);
144     EAMParam eamParam2 = getEAMParam(atomType2);
145     CubicSpline* z1 = getZ(atomType1);
146     CubicSpline* z2 = getZ(atomType2);
147    
148     // make the r grid:
149    
150    
151 gezelter 1481 // we need phi out to the largest value we'll encounter in the radial space;
152    
153     RealType rmax = 0.0;
154     rmax = max(rmax, eamParam1.rcut);
155     rmax = max(rmax, eamParam1.nr * eamParam1.dr);
156 gezelter 1478
157 gezelter 1481 rmax = max(rmax, eamParam2.rcut);
158     rmax = max(rmax, eamParam2.nr * eamParam2.dr);
159    
160 gezelter 1478 // use the smallest dr (finest grid) to build our grid:
161    
162 gezelter 1481 RealType dr = min(eamParam1.dr, eamParam2.dr);
163    
164     int nr = int(rmax/dr + 0.5);
165    
166 gezelter 1478 vector<RealType> rvals;
167 gezelter 1481 for (int i = 0; i < nr; i++) rvals.push_back(RealType(i*dr));
168 gezelter 1478
169     // construct the pair potential:
170    
171     vector<RealType> phivals;
172     RealType phi;
173     RealType r;
174     RealType zi, zj;
175    
176     phivals.push_back(0.0);
177    
178     for (int i = 1; i < rvals.size(); i++ ) {
179     r = rvals[i];
180    
181 gezelter 1502 // only use z(r) if we're inside this atom's cutoff radius,
182     // otherwise, we'll use zero for the charge. This effectively
183     // means that our phi grid goes out beyond the cutoff of the
184     // pair potential
185 gezelter 1481
186     zi = r <= eamParam1.rcut ? z1->getValueAt(r) : 0.0;
187     zj = r <= eamParam2.rcut ? z2->getValueAt(r) : 0.0;
188    
189 gezelter 1478 phi = 331.999296 * (zi * zj) / r;
190 gezelter 1481
191 gezelter 1478 phivals.push_back(phi);
192     }
193    
194     CubicSpline* cs = new CubicSpline();
195     cs->addPoints(rvals, phivals);
196     return cs;
197     }
198    
199 gezelter 1586 void EAM::setCutoffRadius( RealType rCut ) {
200     eamRcut_ = rCut;
201     haveCutoffRadius_ = true;
202     }
203    
204 gezelter 1478 void EAM::initialize() {
205    
206     // set up the mixing method:
207 gezelter 1479 ForceFieldOptions& fopts = forceField_->getForceFieldOptions();
208 gezelter 1481 string EAMMixMeth = fopts.getEAMMixingMethod();
209 gezelter 1480 toUpper(EAMMixMeth);
210    
211 gezelter 1478 if (EAMMixMeth == "JOHNSON")
212     mixMeth_ = eamJohnson;
213     else if (EAMMixMeth == "DAW")
214     mixMeth_ = eamDaw;
215     else
216     mixMeth_ = eamUnknown;
217    
218     // find all of the EAM atom Types:
219     ForceField::AtomTypeContainer* atomTypes = forceField_->getAtomTypes();
220     ForceField::AtomTypeContainer::MapTypeIterator i;
221     AtomType* at;
222    
223     for (at = atomTypes->beginType(i); at != NULL;
224     at = atomTypes->nextType(i)) {
225    
226     if (at->isEAM())
227     addType(at);
228     }
229    
230     // find all of the explicit EAM interactions (setfl):
231     ForceField::NonBondedInteractionTypeContainer* nbiTypes = forceField_->getNonBondedInteractionTypes();
232     ForceField::NonBondedInteractionTypeContainer::MapTypeIterator j;
233     NonBondedInteractionType* nbt;
234    
235     for (nbt = nbiTypes->beginType(j); nbt != NULL;
236     nbt = nbiTypes->nextType(j)) {
237    
238     if (nbt->isEAM()) {
239    
240 gezelter 1481 pair<AtomType*, AtomType*> atypes = nbt->getAtomTypes();
241 gezelter 1478
242     GenericData* data = nbt->getPropertyByName("EAM");
243     if (data == NULL) {
244     sprintf( painCave.errMsg, "EAM::rebuildMixingMap could not find\n"
245     "\tEAM parameters for %s - %s interaction.\n",
246     atypes.first->getName().c_str(),
247     atypes.second->getName().c_str());
248     painCave.severity = OPENMD_ERROR;
249     painCave.isFatal = 1;
250     simError();
251     }
252    
253     EAMMixingData* eamData = dynamic_cast<EAMMixingData*>(data);
254     if (eamData == NULL) {
255     sprintf( painCave.errMsg,
256     "EAM::rebuildMixingMap could not convert GenericData to\n"
257     "\tEAMMixingData for %s - %s interaction.\n",
258     atypes.first->getName().c_str(),
259     atypes.second->getName().c_str());
260     painCave.severity = OPENMD_ERROR;
261     painCave.isFatal = 1;
262     simError();
263     }
264    
265 gezelter 1479 EAMMixingParam eamParam = eamData->getData();
266 gezelter 1478
267 gezelter 1479 vector<RealType> phiAB = eamParam.phi;
268 gezelter 1478 RealType dr = eamParam.dr;
269     int nr = eamParam.nr;
270    
271     addExplicitInteraction(atypes.first, atypes.second, dr, nr, phiAB);
272     }
273     }
274     initialized_ = true;
275     }
276    
277    
278    
279     void EAM::addType(AtomType* atomType){
280    
281     EAMAtomData eamAtomData;
282 gezelter 1479
283 gezelter 1478 eamAtomData.rho = getRho(atomType);
284     eamAtomData.F = getF(atomType);
285     eamAtomData.Z = getZ(atomType);
286     eamAtomData.rcut = getRcut(atomType);
287    
288     // add it to the map:
289     AtomTypeProperties atp = atomType->getATP();
290    
291 gezelter 1481 pair<map<int,AtomType*>::iterator,bool> ret;
292     ret = EAMlist.insert( pair<int, AtomType*>(atp.ident, atomType) );
293 gezelter 1478 if (ret.second == false) {
294     sprintf( painCave.errMsg,
295     "EAM already had a previous entry with ident %d\n",
296     atp.ident);
297     painCave.severity = OPENMD_INFO;
298     painCave.isFatal = 0;
299     simError();
300     }
301    
302     EAMMap[atomType] = eamAtomData;
303    
304     // Now, iterate over all known types and add to the mixing map:
305    
306 gezelter 1481 map<AtomType*, EAMAtomData>::iterator it;
307 gezelter 1478 for( it = EAMMap.begin(); it != EAMMap.end(); ++it) {
308    
309 gezelter 1479 AtomType* atype2 = (*it).first;
310 gezelter 1478
311     EAMInteractionData mixer;
312     mixer.phi = getPhi(atomType, atype2);
313     mixer.explicitlySet = false;
314    
315 gezelter 1481 pair<AtomType*, AtomType*> key1, key2;
316     key1 = make_pair(atomType, atype2);
317     key2 = make_pair(atype2, atomType);
318 gezelter 1478
319     MixingMap[key1] = mixer;
320     if (key2 != key1) {
321     MixingMap[key2] = mixer;
322     }
323     }
324     return;
325     }
326    
327     void EAM::addExplicitInteraction(AtomType* atype1, AtomType* atype2,
328     RealType dr, int nr,
329     vector<RealType> phiVals) {
330    
331     // in case these weren't already in the map
332     addType(atype1);
333     addType(atype2);
334    
335     EAMInteractionData mixer;
336     CubicSpline* cs = new CubicSpline();
337 gezelter 1479 vector<RealType> rVals;
338 gezelter 1478
339 gezelter 1479 for (int i = 0; i < nr; i++) rVals.push_back(i * dr);
340 gezelter 1478
341     cs->addPoints(rVals, phiVals);
342     mixer.phi = cs;
343     mixer.explicitlySet = true;
344    
345 gezelter 1481 pair<AtomType*, AtomType*> key1, key2;
346     key1 = make_pair(atype1, atype2);
347     key2 = make_pair(atype2, atype1);
348 gezelter 1478
349     MixingMap[key1] = mixer;
350     if (key2 != key1) {
351     MixingMap[key2] = mixer;
352     }
353     return;
354     }
355    
356 gezelter 1545 void EAM::calcDensity(InteractionData &idat) {
357 gezelter 1479
358 gezelter 1478 if (!initialized_) initialize();
359 gezelter 1479
360 gezelter 1571 EAMAtomData data1 = EAMMap[idat.atypes.first];
361     EAMAtomData data2 = EAMMap[idat.atypes.second];
362 gezelter 1586
363     if (haveCutoffRadius_)
364     if ( *(idat.rij) > eamRcut_) return;
365    
366 gezelter 1629 if ( *(idat.rij) < data1.rcut)
367 gezelter 1575 *(idat.rho1) += data1.rho->getValueAt( *(idat.rij));
368 gezelter 1629
369 gezelter 1586
370 gezelter 1629 if ( *(idat.rij) < data2.rcut)
371     *(idat.rho2) += data2.rho->getValueAt( *(idat.rij));
372    
373     return;
374 gezelter 1478 }
375 gezelter 1586
376 gezelter 1545 void EAM::calcFunctional(SelfData &sdat) {
377 gezelter 1586
378 gezelter 1478 if (!initialized_) initialize();
379    
380 gezelter 1554 EAMAtomData data1 = EAMMap[ sdat.atype ];
381 gezelter 1478
382 gezelter 1554 pair<RealType, RealType> result = data1.F->getValueAndDerivativeAt( *(sdat.rho) );
383 gezelter 1478
384 gezelter 1554 *(sdat.frho) = result.first;
385     *(sdat.dfrhodrho) = result.second;
386 gezelter 1575
387 gezelter 1586 (*(sdat.pot))[METALLIC_FAMILY] += result.first;
388 gezelter 1575 *(sdat.particlePot) += result.first;
389    
390 gezelter 1478 return;
391     }
392    
393    
394 gezelter 1536 void EAM::calcForce(InteractionData &idat) {
395 gezelter 1478
396     if (!initialized_) initialize();
397 gezelter 1481
398 gezelter 1586 if (haveCutoffRadius_)
399     if ( *(idat.rij) > eamRcut_) return;
400    
401 gezelter 1478 pair<RealType, RealType> res;
402    
403 gezelter 1586 EAMAtomData data1 = EAMMap[idat.atypes.first];
404     EAMAtomData data2 = EAMMap[idat.atypes.second];
405    
406     // get type-specific cutoff radii
407    
408     RealType rci = data1.rcut;
409     RealType rcj = data2.rcut;
410    
411     RealType rha(0.0), drha(0.0), rhb(0.0), drhb(0.0);
412     RealType pha(0.0), dpha(0.0), phb(0.0), dphb(0.0);
413     RealType phab(0.0), dvpdr(0.0);
414     RealType drhoidr, drhojdr, dudr;
415    
416     if ( *(idat.rij) < rci) {
417     res = data1.rho->getValueAndDerivativeAt( *(idat.rij));
418     rha = res.first;
419     drha = res.second;
420    
421     res = MixingMap[make_pair(idat.atypes.first, idat.atypes.first)].phi->getValueAndDerivativeAt( *(idat.rij) );
422     pha = res.first;
423     dpha = res.second;
424     }
425    
426     if ( *(idat.rij) < rcj) {
427     res = data2.rho->getValueAndDerivativeAt( *(idat.rij) );
428     rhb = res.first;
429     drhb = res.second;
430    
431     res = MixingMap[make_pair(idat.atypes.second, idat.atypes.second)].phi->getValueAndDerivativeAt( *(idat.rij) );
432     phb = res.first;
433     dphb = res.second;
434     }
435 gezelter 1478
436 gezelter 1586 switch(mixMeth_) {
437     case eamJohnson:
438 gezelter 1478
439 gezelter 1554 if ( *(idat.rij) < rci) {
440 gezelter 1586 phab = phab + 0.5 * (rhb / rha) * pha;
441     dvpdr = dvpdr + 0.5*((rhb/rha)*dpha +
442     pha*((drhb/rha) - (rhb*drha/rha/rha)));
443 gezelter 1478 }
444 gezelter 1586
445    
446    
447 gezelter 1554 if ( *(idat.rij) < rcj) {
448 gezelter 1586 phab = phab + 0.5 * (rha / rhb) * phb;
449     dvpdr = dvpdr + 0.5 * ((rha/rhb)*dphb +
450     phb*((drha/rhb) - (rha*drhb/rhb/rhb)));
451 gezelter 1478 }
452    
453 gezelter 1586 break;
454    
455     case eamDaw:
456     res = MixingMap[idat.atypes].phi->getValueAndDerivativeAt( *(idat.rij));
457     phab = res.first;
458     dvpdr = res.second;
459    
460     break;
461     case eamUnknown:
462     default:
463    
464     sprintf(painCave.errMsg,
465     "EAM::calcForce hit a mixing method it doesn't know about!\n"
466     );
467     painCave.severity = OPENMD_ERROR;
468     painCave.isFatal = 1;
469     simError();
470    
471     }
472    
473     drhoidr = drha;
474     drhojdr = drhb;
475    
476     dudr = drhojdr* *(idat.dfrho1) + drhoidr* *(idat.dfrho2) + dvpdr;
477    
478     *(idat.f1) += *(idat.d) * dudr / *(idat.rij);
479 gezelter 1478
480 gezelter 1586 // particlePot is the difference between the full potential and
481     // the full potential without the presence of a particular
482     // particle (atom1).
483     //
484     // This reduces the density at other particle locations, so we
485     // need to recompute the density at atom2 assuming atom1 didn't
486     // contribute. This then requires recomputing the density
487     // functional for atom2 as well.
488    
489     *(idat.particlePot1) += data2.F->getValueAt( *(idat.rho2) - rha )
490     - *(idat.frho2);
491    
492     *(idat.particlePot2) += data1.F->getValueAt( *(idat.rho1) - rhb)
493     - *(idat.frho1);
494    
495     (*(idat.pot))[METALLIC_FAMILY] += phab;
496    
497     *(idat.vpair) += phab;
498    
499 gezelter 1478 return;
500    
501     }
502 gezelter 1505
503 gezelter 1545 RealType EAM::getSuggestedCutoffRadius(pair<AtomType*, AtomType*> atypes) {
504 gezelter 1505 if (!initialized_) initialize();
505    
506     RealType cut = 0.0;
507    
508     map<AtomType*, EAMAtomData>::iterator it;
509    
510 gezelter 1545 it = EAMMap.find(atypes.first);
511 gezelter 1505 if (it != EAMMap.end()) {
512     EAMAtomData data1 = (*it).second;
513     cut = data1.rcut;
514     }
515    
516 gezelter 1545 it = EAMMap.find(atypes.second);
517 gezelter 1505 if (it != EAMMap.end()) {
518     EAMAtomData data2 = (*it).second;
519     if (data2.rcut > cut)
520     cut = data2.rcut;
521     }
522    
523     return cut;
524     }
525 gezelter 1478 }
526    

Properties

Name Value
svn:eol-style native