ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/trunk/src/nonbonded/EAM.cpp
Revision: 1927
Committed: Wed Aug 14 20:19:19 2013 UTC (11 years, 11 months ago) by gezelter
File size: 14816 byte(s)
Log Message:
FlucRho/EAM initial commit

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

Properties

Name Value
svn:eol-style native