CoMD
A Mini-app for Co-Design of Classical Molecular Dynamics.
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
eam.c
Go to the documentation of this file.
1 /// \file
2 /// Compute forces for the Embedded Atom Model (EAM).
3 ///
4 /// The Embedded Atom Model (EAM) is a widely used model of atomic
5 /// interactions in simple metals.
6 ///
7 /// http://en.wikipedia.org/wiki/Embedded_atom_model
8 ///
9 /// In the EAM, the total potential energy is written as a sum of a pair
10 /// potential and the embedding energy, F:
11 ///
12 /// \f[
13 /// U = \sum_{ij} \varphi(r_{ij}) + \sum_i F({\bar\rho_i})
14 /// \f]
15 ///
16 /// The pair potential \f$\varphi_{ij}\f$ is a two-body inter-atomic
17 /// potential, similar to the Lennard-Jones potential, and
18 /// \f$F(\bar\rho)\f$ is interpreted as the energy required to embed an
19 /// atom in an electron field with density \f$\bar\rho\f$. The local
20 /// electon density at site i is calulated by summing the "effective
21 /// electron density" due to all neighbors of atom i:
22 ///
23 /// \f[
24 /// \bar\rho_i = \sum_j \rho_j(r_{ij})
25 /// \f]
26 ///
27 /// The force on atom i, \f${\bf F}_i\f$ is given by
28 ///
29 /// \f{eqnarray*}{
30 /// {\bf F}_i & = & -\nabla_i \sum_{jk} U(r_{jk})\\
31 /// & = & - \sum_j\left\{
32 /// \varphi'(r_{ij}) +
33 /// [F'(\bar\rho_i) + F'(\bar\rho_j)]\rho'(r_{ij})
34 /// \right\} \hat{r}_{ij}
35 /// \f}
36 ///
37 /// where primes indicate the derivative of a function with respect to
38 /// its argument and \f$\hat{r}_{ij}\f$ is a unit vector in the
39 /// direction from atom i to atom j.
40 ///
41 /// The form of this force expression has two significant consequences.
42 /// First, unlike with a simple pair potential, it is not possible to
43 /// compute the potential energy and the forces on the atoms in a single
44 /// loop over the pairs. The terms involving \f$ F'(\bar\rho) \f$
45 /// cannot be calculated until \f$ \bar\rho \f$ is known, but
46 /// calculating \f$ \bar\rho \f$ requires a loop over the pairs. Hence
47 /// the EAM force routine contains three loops.
48 ///
49 /// -# Loop over all pairs, compute the two-body
50 /// interaction and the electron density at each atom
51 /// -# Loop over all atoms, compute the embedding energy and its
52 /// derivative for each atom
53 /// -# Loop over all pairs, compute the embedding
54 /// energy contribution to the force and add to the two-body force
55 ///
56 /// The second loop over pairs doubles the data motion requirement
57 /// relative to a simple pair potential.
58 ///
59 /// The second consequence of the force expression is that computing the
60 /// forces on all atoms requires additional communication beyond the
61 /// coordinates of all remote atoms within the cutoff distance. This is
62 /// again because of the terms involving \f$ F'(\bar\rho_j) \f$. If
63 /// atom j is a remote atom, the local task cannot compute \f$
64 /// \bar\rho_j \f$. (Such a calculation would require all the neighbors
65 /// of atom j, some of which can be up to 2 times the cutoff distance
66 /// away from a local atom---outside the typical halo exchange range.)
67 ///
68 /// To obtain the needed remote density we introduce a second halo
69 /// exchange after loop number 2 to communicate \f$ F'(\bar\rho) \f$ for
70 /// remote atoms. This provides the data we need to complete the third
71 /// loop, but at the cost of introducing a communication operation in
72 /// the middle of the force routine.
73 ///
74 /// At least two alternate methods can be used to deal with the remote
75 /// density problem. One possibility is to extend the halo exchange
76 /// radius for the atom exchange to twice the potential cutoff distance.
77 /// This is likely undesirable due to large increase in communication
78 /// volume. The other possibility is to accumulate partial force terms
79 /// on the tasks where they can be computed. In this method, tasks will
80 /// compute force contributions for remote atoms, then communicate the
81 /// partial forces at the end of the halo exchange. This method has the
82 /// advantage that the communication is deffered until after the force
83 /// loops, but the disadvantage that three times as much data needs to
84 /// be set (three components of the force vector instead of a single
85 /// scalar \f$ F'(\bar\rho) \f$.
86 
87 
88 #include "eam.h"
89 
90 #include <stdlib.h>
91 #include <string.h>
92 #include <math.h>
93 #include <assert.h>
94 
95 #include "constants.h"
96 #include "memUtils.h"
97 #include "parallel.h"
98 #include "linkCells.h"
99 #include "CoMDTypes.h"
100 #include "performanceTimers.h"
101 #include "haloExchange.h"
102 
103 #define MAX(A,B) ((A) > (B) ? (A) : (B))
104 
105 /// Handles interpolation of tabular data.
106 ///
107 /// \see initInterpolationObject
108 /// \see interpolate
109 typedef struct InterpolationObjectSt
110 {
111  int n; //!< the number of values in the table
112  real_t x0; //!< the starting ordinate range
113  real_t invDx; //!< the inverse of the table spacing
114  real_t* values; //!< the abscissa values
116 
117 /// Derived struct for an EAM potential.
118 /// Uses table lookups for function evaluation.
119 /// Polymorphic with BasePotential.
120 /// \see BasePotential
121 typedef struct EamPotentialSt
122 {
123  real_t cutoff; //!< potential cutoff distance in Angstroms
124  real_t mass; //!< mass of atoms in intenal units
125  real_t lat; //!< lattice spacing (angs) of unit cell
126  char latticeType[8]; //!< lattice type, e.g. FCC, BCC, etc.
127  char name[3]; //!< element name
128  int atomicNo; //!< atomic number
129  int (*force)(SimFlat* s); //!< function pointer to force routine
130  void (*print)(FILE* file, BasePotential* pot);
131  void (*destroy)(BasePotential** pot); //!< destruction of the potential
132  InterpolationObject* phi; //!< Pair energy
133  InterpolationObject* rho; //!< Electron Density
134  InterpolationObject* f; //!< Embedding Energy
135 
136  real_t* rhobar; //!< per atom storage for rhobar
137  real_t* dfEmbed; //!< per atom storage for derivative of Embedding
140 } EamPotential;
141 
142 // EAM functionality
143 static int eamForce(SimFlat* s);
144 static void eamPrint(FILE* file, BasePotential* pot);
145 static void eamDestroy(BasePotential** pot);
146 static void eamBcastPotential(EamPotential* pot);
147 
148 
149 // Table interpolation functionality
151  int n, real_t x0, real_t dx, real_t* data);
153 static void interpolate(InterpolationObject* table, real_t r, real_t* f, real_t* df);
154 static void bcastInterpolationObject(InterpolationObject** table);
155 static void printTableData(InterpolationObject* table, const char* fileName);
156 
157 
158 // Read potential tables from files.
159 static void eamReadSetfl(EamPotential* pot, const char* dir, const char* potName);
160 static void eamReadFuncfl(EamPotential* pot, const char* dir, const char* potName);
161 static void fileNotFound(const char* callSite, const char* filename);
162 static void notAlloyReady(const char* callSite);
163 static void typeNotSupported(const char* callSite, const char* type);
164 
165 
166 /// Allocate and initialize the EAM potential data structure.
167 ///
168 /// \param [in] dir The directory in which potential table files are found.
169 /// \param [in] file The name of the potential table file.
170 /// \param [in] type The file format of the potential file (setfl or funcfl).
171 BasePotential* initEamPot(const char* dir, const char* file, const char* type)
172 {
173  EamPotential* pot = comdMalloc(sizeof(EamPotential));
174  assert(pot);
175  pot->force = eamForce;
176  pot->print = eamPrint;
177  pot->destroy = eamDestroy;
178  pot->phi = NULL;
179  pot->rho = NULL;
180  pot->f = NULL;
181 
182  // Initialization of the next three items requires information about
183  // the parallel decomposition and link cells that isn't available
184  // with the potential is initialized. Hence, we defer their
185  // initialization until the first time we call the force routine.
186  pot->dfEmbed = NULL;
187  pot->rhobar = NULL;
188  pot->forceExchange = NULL;
189 
190  if (getMyRank() == 0)
191  {
192  if (strcmp(type, "setfl" ) == 0)
193  eamReadSetfl(pot, dir, file);
194  else if (strcmp(type,"funcfl") == 0)
195  eamReadFuncfl(pot, dir, file);
196  else
197  typeNotSupported("initEamPot", type);
198  }
199  eamBcastPotential(pot);
200 
201  return (BasePotential*) pot;
202 }
203 
204 /// Calculate potential energy and forces for the EAM potential.
205 ///
206 /// Three steps are required:
207 ///
208 /// -# Loop over all atoms and their neighbors, compute the two-body
209 /// interaction and the electron density at each atom
210 /// -# Loop over all atoms, compute the embedding energy and its
211 /// derivative for each atom
212 /// -# Loop over all atoms and their neighbors, compute the embedding
213 /// energy contribution to the force and add to the two-body force
214 ///
216 {
217  EamPotential* pot = (EamPotential*) s->pot;
218  assert(pot);
219 
220  // set up halo exchange and internal storage on first call to forces.
221  if (pot->forceExchange == NULL)
222  {
223  int maxTotalAtoms = MAXATOMS*s->boxes->nTotalBoxes;
224  pot->dfEmbed = comdMalloc(maxTotalAtoms*sizeof(real_t));
225  pot->rhobar = comdMalloc(maxTotalAtoms*sizeof(real_t));
228  pot->forceExchangeData->dfEmbed = pot->dfEmbed;
229  pot->forceExchangeData->boxes = s->boxes;
230  }
231 
232  real_t rCut2 = pot->cutoff*pot->cutoff;
233 
234  // zero forces / energy / rho /rhoprime
235  real_t etot = 0.0;
236  memset(s->atoms->f, 0, s->boxes->nTotalBoxes*MAXATOMS*sizeof(real3));
237  memset(s->atoms->U, 0, s->boxes->nTotalBoxes*MAXATOMS*sizeof(real_t));
238  memset(pot->dfEmbed, 0, s->boxes->nTotalBoxes*MAXATOMS*sizeof(real_t));
239  memset(pot->rhobar, 0, s->boxes->nTotalBoxes*MAXATOMS*sizeof(real_t));
240 
241  int nbrBoxes[27];
242  // loop over local boxes
243  for (int iBox=0; iBox<s->boxes->nLocalBoxes; iBox++)
244  {
245  int nIBox = s->boxes->nAtoms[iBox];
246  int nNbrBoxes = getNeighborBoxes(s->boxes, iBox, nbrBoxes);
247  // loop over neighbor boxes of iBox (some may be halo boxes)
248  for (int jTmp=0; jTmp<nNbrBoxes; jTmp++)
249  {
250  int jBox = nbrBoxes[jTmp];
251  if (jBox < iBox ) continue;
252 
253  int nJBox = s->boxes->nAtoms[jBox];
254  // loop over atoms in iBox
255  for (int iOff=MAXATOMS*iBox,ii=0; ii<nIBox; ii++,iOff++)
256  {
257  // loop over atoms in jBox
258  for (int jOff=MAXATOMS*jBox,ij=0; ij<nJBox; ij++,jOff++)
259  {
260  if ( (iBox==jBox) &&(ij <= ii) ) continue;
261 
262  double r2 = 0.0;
263  real3 dr;
264  for (int k=0; k<3; k++)
265  {
266  dr[k]=s->atoms->r[iOff][k]-s->atoms->r[jOff][k];
267  r2+=dr[k]*dr[k];
268  }
269  if(r2>rCut2) continue;
270 
271  double r = sqrt(r2);
272 
273  real_t phiTmp, dPhi, rhoTmp, dRho;
274  interpolate(pot->phi, r, &phiTmp, &dPhi);
275  interpolate(pot->rho, r, &rhoTmp, &dRho);
276 
277  for (int k=0; k<3; k++)
278  {
279  s->atoms->f[iOff][k] -= dPhi*dr[k]/r;
280  s->atoms->f[jOff][k] += dPhi*dr[k]/r;
281  }
282 
283  // update energy terms
284  // calculate energy contribution based on whether
285  // the neighbor box is local or remote
286  if (jBox < s->boxes->nLocalBoxes)
287  etot += phiTmp;
288  else
289  etot += 0.5*phiTmp;
290 
291  s->atoms->U[iOff] += 0.5*phiTmp;
292  s->atoms->U[jOff] += 0.5*phiTmp;
293 
294  // accumulate rhobar for each atom
295  pot->rhobar[iOff] += rhoTmp;
296  pot->rhobar[jOff] += rhoTmp;
297 
298  } // loop over atoms in jBox
299  } // loop over atoms in iBox
300  } // loop over neighbor boxes
301  } // loop over local boxes
302 
303  // Compute Embedding Energy
304  // loop over all local boxes
305  for (int iBox=0; iBox<s->boxes->nLocalBoxes; iBox++)
306  {
307  int iOff;
308  int nIBox = s->boxes->nAtoms[iBox];
309 
310  // loop over atoms in iBox
311  for (int iOff=MAXATOMS*iBox,ii=0; ii<nIBox; ii++,iOff++)
312  {
313  real_t fEmbed, dfEmbed;
314  interpolate(pot->f, pot->rhobar[iOff], &fEmbed, &dfEmbed);
315  pot->dfEmbed[iOff] = dfEmbed; // save derivative for halo exchange
316  etot += fEmbed;
317  s->atoms->U[iOff] += fEmbed;
318  }
319  }
320 
321  // exchange derivative of the embedding energy with repsect to rhobar
325 
326  // third pass
327  // loop over local boxes
328  for (int iBox=0; iBox<s->boxes->nLocalBoxes; iBox++)
329  {
330  int nIBox = s->boxes->nAtoms[iBox];
331  int nNbrBoxes = getNeighborBoxes(s->boxes, iBox, nbrBoxes);
332  // loop over neighbor boxes of iBox (some may be halo boxes)
333  for (int jTmp=0; jTmp<nNbrBoxes; jTmp++)
334  {
335  int jBox = nbrBoxes[jTmp];
336  if(jBox < iBox) continue;
337 
338  int nJBox = s->boxes->nAtoms[jBox];
339  // loop over atoms in iBox
340  for (int iOff=MAXATOMS*iBox,ii=0; ii<nIBox; ii++,iOff++)
341  {
342  // loop over atoms in jBox
343  for (int jOff=MAXATOMS*jBox,ij=0; ij<nJBox; ij++,jOff++)
344  {
345  if ((iBox==jBox) && (ij <= ii)) continue;
346 
347  double r2 = 0.0;
348  real3 dr;
349  for (int k=0; k<3; k++)
350  {
351  dr[k]=s->atoms->r[iOff][k]-s->atoms->r[jOff][k];
352  r2+=dr[k]*dr[k];
353  }
354  if(r2>=rCut2) continue;
355 
356  real_t r = sqrt(r2);
357 
358  real_t rhoTmp, dRho;
359  interpolate(pot->rho, r, &rhoTmp, &dRho);
360 
361  for (int k=0; k<3; k++)
362  {
363  s->atoms->f[iOff][k] -= (pot->dfEmbed[iOff]+pot->dfEmbed[jOff])*dRho*dr[k]/r;
364  s->atoms->f[jOff][k] += (pot->dfEmbed[iOff]+pot->dfEmbed[jOff])*dRho*dr[k]/r;
365  }
366 
367  } // loop over atoms in jBox
368  } // loop over atoms in iBox
369  } // loop over neighbor boxes
370  } // loop over local boxes
371 
372  s->ePotential = (real_t) etot;
373 
374  return 0;
375 }
376 
377 void eamPrint(FILE* file, BasePotential* pot)
378 {
379  EamPotential *eamPot = (EamPotential*) pot;
380  fprintf(file, " Potential type : EAM\n");
381  fprintf(file, " Species name : %s\n", eamPot->name);
382  fprintf(file, " Atomic number : %d\n", eamPot->atomicNo);
383  fprintf(file, " Mass : "FMT1" amu\n", eamPot->mass/amuToInternalMass); // print in amu
384  fprintf(file, " Lattice type : %s\n", eamPot->latticeType);
385  fprintf(file, " Lattice spacing : "FMT1" Angstroms\n", eamPot->lat);
386  fprintf(file, " Cutoff : "FMT1" Angstroms\n", eamPot->cutoff);
387 }
388 
390 {
391  if ( ! pPot ) return;
392  EamPotential* pot = *(EamPotential**)pPot;
393  if ( ! pot ) return;
396  destroyInterpolationObject(&(pot->f));
398  comdFree(pot);
399  *pPot = NULL;
400 
401  return;
402 }
403 
404 /// Broadcasts an EamPotential from rank 0 to all other ranks.
405 /// If the table coefficients are read from a file only rank 0 does the
406 /// read. Hence we need to broadcast the potential to all other ranks.
408 {
409  assert(pot);
410 
411  struct
412  {
413  real_t cutoff, mass, lat;
414  char latticeType[8];
415  char name[3];
416  int atomicNo;
417  } buf;
418  if (getMyRank() == 0)
419  {
420  buf.cutoff = pot->cutoff;
421  buf.mass = pot->mass;
422  buf.lat = pot->lat;
423  buf.atomicNo = pot->atomicNo;
424  strcpy(buf.latticeType, pot->latticeType);
425  strcpy(buf.name, pot->name);
426  }
427  bcastParallel(&buf, sizeof(buf), 0);
428  pot->cutoff = buf.cutoff;
429  pot->mass = buf.mass;
430  pot->lat = buf.lat;
431  pot->atomicNo = buf.atomicNo;
432  strcpy(pot->latticeType, buf.latticeType);
433  strcpy(pot->name, buf.name);
434 
438 }
439 
440 /// Builds a structure to store interpolation data for a tabular
441 /// function. Interpolation must be supported on the range
442 /// \f$[x_0, x_n]\f$, where \f$x_n = n*dx\f$.
443 ///
444 /// \see interpolate
445 /// \see bcastInterpolationObject
446 /// \see destroyInterpolationObject
447 ///
448 /// \param [in] n number of values in the table.
449 /// \param [in] x0 minimum ordinate value of the table.
450 /// \param [in] dx spacing of the ordinate values.
451 /// \param [in] data abscissa values. An array of size n.
453  int n, real_t x0, real_t dx, real_t* data)
454 {
455  InterpolationObject* table =
457  assert(table);
458 
459  table->values = (real_t*)comdCalloc(1, (n+3)*sizeof(real_t));
460  assert(table->values);
461 
462  table->values++;
463  table->n = n;
464  table->invDx = 1.0/dx;
465  table->x0 = x0;
466 
467  for (int ii=0; ii<n; ++ii)
468  table->values[ii] = data[ii];
469 
470  table->values[-1] = table->values[0];
471  table->values[n+1] = table->values[n] = table->values[n-1];
472 
473  return table;
474 }
475 
477 {
478  if ( ! a ) return;
479  if ( ! *a ) return;
480  if ( (*a)->values)
481  {
482  (*a)->values--;
483  comdFree((*a)->values);
484  }
485  comdFree(*a);
486  *a = NULL;
487 
488  return;
489 }
490 
491 /// Interpolate a table to determine f(r) and its derivative f'(r).
492 ///
493 /// The forces on the particle are much more sensitive to the derivative
494 /// of the potential than on the potential itself. It is therefore
495 /// absolutely essential that the interpolated derivatives are smooth
496 /// and continuous. This function uses simple quadratic interpolation
497 /// to find f(r). Since quadric interpolants don't have smooth
498 /// derivatives, f'(r) is computed using a 4 point finite difference
499 /// stencil.
500 ///
501 /// Interpolation is used heavily by the EAM force routine so this
502 /// function is a potential performance hot spot. Feel free to
503 /// reimplement this function (and initInterpolationObject if necessay)
504 /// with any higher performing implementation of interpolation, as long
505 /// as the alternate implmentation that has the required smoothness
506 /// properties. Cubic splines are one common alternate choice.
507 ///
508 /// \param [in] table Interpolation table.
509 /// \param [in] r Point where function value is needed.
510 /// \param [out] f The interpolated value of f(r).
511 /// \param [out] df The interpolated value of df(r)/dr.
513 {
514  const real_t* tt = table->values; // alias
515 
516  if ( r < table->x0 ) r = table->x0;
517 
518  r = (r-table->x0)*(table->invDx) ;
519  int ii = (int)floor(r);
520  if (ii > table->n)
521  {
522  ii = table->n;
523  r = table->n / table->invDx;
524  }
525  // reset r to fractional distance
526  r = r - floor(r);
527 
528  real_t g1 = tt[ii+1] - tt[ii-1];
529  real_t g2 = tt[ii+2] - tt[ii];
530 
531  *f = tt[ii] + 0.5*r*(g1 + r*(tt[ii+1] + tt[ii-1] - 2.0*tt[ii]) );
532 
533  *df = 0.5*(g1 + r*(g2-g1))*table->invDx;
534 }
535 
536 /// Broadcasts an InterpolationObject from rank 0 to all other ranks.
537 ///
538 /// It is commonly the case that the data needed to create the
539 /// interpolation table is available on only one task (for example, only
540 /// one task has read the data from a file). Broadcasting the table
541 /// eliminates the need to put broadcast code in multiple table readers.
542 ///
543 /// \see eamBcastPotential
545 {
546  struct
547  {
548  int n;
549  real_t x0, invDx;
550  } buf;
551 
552  if (getMyRank() == 0)
553  {
554  buf.n = (*table)->n;
555  buf.x0 = (*table)->x0;
556  buf.invDx = (*table)->invDx;
557  }
558  bcastParallel(&buf, sizeof(buf), 0);
559 
560  if (getMyRank() != 0)
561  {
562  assert(*table == NULL);
563  *table = comdMalloc(sizeof(InterpolationObject));
564  (*table)->n = buf.n;
565  (*table)->x0 = buf.x0;
566  (*table)->invDx = buf.invDx;
567  (*table)->values = comdMalloc(sizeof(real_t) * (buf.n+3) );
568  (*table)->values++;
569  }
570 
571  int valuesSize = sizeof(real_t) * ((*table)->n+3);
572  bcastParallel((*table)->values-1, valuesSize, 0);
573 }
574 
575 void printTableData(InterpolationObject* table, const char* fileName)
576 {
577  if (!printRank()) return;
578 
579  FILE* potData;
580  potData = fopen(fileName,"w");
581  real_t dR = 1.0/table->invDx;
582  for (int i = 0; i<table->n; i++)
583  {
584  real_t r = table->x0+i*dR;
585  fprintf(potData, "%d %e %e\n", i, r, table->values[i]);
586  }
587  fclose(potData);
588 }
589 
590 /// Reads potential data from a setfl file and populates
591 /// corresponding members and InterpolationObjects in an EamPotential.
592 ///
593 /// setfl is a file format for tabulated potential functions used by
594 /// the original EAM code DYNAMO. A setfl file contains EAM
595 /// potentials for multiple elements.
596 ///
597 /// The contents of a setfl file are:
598 ///
599 /// | Line Num | Description
600 /// | :------: | :----------
601 /// | 1 - 3 | comments
602 /// | 4 | ntypes type1 type2 ... typen
603 /// | 5 | nrho drho nr dr rcutoff
604 /// | F, rho | Following line 5 there is a block for each atom type with F, and rho.
605 /// | b1 | ielem(i) amass(i) latConst(i) latType(i)
606 /// | b2 | embedding function values F(rhobar) starting at rhobar=0
607 /// | ... | (nrho values. Multiple values per line allowed.)
608 /// | bn | electron density, starting at r=0
609 /// | ... | (nr values. Multiple values per line allowed.)
610 /// | repeat | Return to b1 for each atom type.
611 /// | phi | phi_ij for (1,1), (2,1), (2,2), (3,1), (3,2), (3,3), (4,1), ...,
612 /// | p1 | pair potential between type i and type j, starting at r=0
613 /// | ... | (nr values. Multiple values per line allowed.)
614 /// | repeat | Return to p1 for each phi_ij
615 ///
616 /// Where:
617 /// - ntypes : number of element types in the potential
618 /// - nrho : number of points the embedding energy F(rhobar)
619 /// - drho : table spacing for rhobar
620 /// - nr : number of points for rho(r) and phi(r)
621 /// - dr : table spacing for r in Angstroms
622 /// - rcutoff : cut-off distance in Angstroms
623 /// - ielem(i) : atomic number for element(i)
624 /// - amass(i) : atomic mass for element(i) in AMU
625 /// - latConst(i) : lattice constant for element(i) in Angstroms
626 /// - latType(i) : lattice type for element(i)
627 ///
628 /// setfl format stores r*phi(r), so we need to converted to the pair
629 /// potential phi(r). In the file, phi(r)*r is in eV*Angstroms.
630 /// NB: phi is not defined for r = 0
631 ///
632 /// F(rhobar) is in eV.
633 ///
634 void eamReadSetfl(EamPotential* pot, const char* dir, const char* potName)
635 {
636  char tmp[4096];
637  sprintf(tmp, "%s/%s", dir, potName);
638 
639  FILE* potFile = fopen(tmp, "r");
640  if (potFile == NULL)
641  fileNotFound("eamReadSetfl", tmp);
642 
643  // read the first 3 lines (comments)
644  fgets(tmp, sizeof(tmp), potFile);
645  fgets(tmp, sizeof(tmp), potFile);
646  fgets(tmp, sizeof(tmp), potFile);
647 
648  // line 4
649  fgets(tmp, sizeof(tmp), potFile);
650  int nElems;
651  sscanf(tmp, "%d", &nElems);
652  if( nElems != 1 )
653  notAlloyReady("eamReadSetfl");
654 
655  //line 5
656  int nRho, nR;
657  double dRho, dR, cutoff;
658  // The same cutoff is used by all alloys, NB: cutoff = nR * dR is redundant
659  fgets(tmp, sizeof(tmp), potFile);
660  sscanf(tmp, "%d %le %d %le %le", &nRho, &dRho, &nR, &dR, &cutoff);
661  pot->cutoff = cutoff;
662 
663  // **** THIS CODE IS RESTRICTED TO ONE ELEMENT
664  // Per-atom header
665  fgets(tmp, sizeof(tmp), potFile);
666  int nAtomic;
667  double mass, lat;
668  char latticeType[8];
669  sscanf(tmp, "%d %le %le %s", &nAtomic, &mass, &lat, latticeType);
670  pot->atomicNo = nAtomic;
671  pot->lat = lat;
672  pot->mass = mass * amuToInternalMass; // file has mass in AMU.
673  strcpy(pot->latticeType, latticeType);
674 
675  // allocate read buffer
676  int bufSize = MAX(nRho, nR);
677  real_t* buf = comdMalloc(bufSize * sizeof(real_t));
678  real_t x0 = 0.0;
679 
680  // Read embedding energy F(rhobar)
681  for (int ii=0; ii<nRho; ++ii)
682  fscanf(potFile, FMT1, buf+ii);
683  pot->f = initInterpolationObject(nRho, x0, dRho, buf);
684 
685  // Read electron density rho(r)
686  for (int ii=0; ii<nR; ++ii)
687  fscanf(potFile, FMT1, buf+ii);
688  pot->rho = initInterpolationObject(nR, x0, dR, buf);
689 
690  // Read phi(r)*r and convert to phi(r)
691  for (int ii=0; ii<nR; ++ii)
692  fscanf(potFile, FMT1, buf+ii);
693  for (int ii=1; ii<nR; ++ii)
694  {
695  real_t r = x0 + ii*dR;
696  buf[ii] /= r;
697  }
698  buf[0] = buf[1] + (buf[1] - buf[2]); // Linear interpolation to get phi[0].
699  pot->phi = initInterpolationObject(nR, x0, dR, buf);
700 
701  comdFree(buf);
702 
703  // write to text file for comparison, currently commented out
704 /* printPot(pot->f, "SetflDataF.txt"); */
705 /* printPot(pot->rho, "SetflDataRho.txt"); */
706 /* printPot(pot->phi, "SetflDataPhi.txt"); */
707 }
708 
709 /// Reads potential data from a funcfl file and populates
710 /// corresponding members and InterpolationObjects in an EamPotential.
711 ///
712 /// funcfl is a file format for tabulated potential functions used by
713 /// the original EAM code DYNAMO. A funcfl file contains an EAM
714 /// potential for a single element.
715 ///
716 /// The contents of a funcfl file are:
717 ///
718 /// | Line Num | Description
719 /// | :------: | :----------
720 /// | 1 | comments
721 /// | 2 | elem amass latConstant latType
722 /// | 3 | nrho drho nr dr rcutoff
723 /// | 4 | embedding function values F(rhobar) starting at rhobar=0
724 /// | ... | (nrho values. Multiple values per line allowed.)
725 /// | x' | electrostatic interation Z(r) starting at r=0
726 /// | ... | (nr values. Multiple values per line allowed.)
727 /// | y' | electron density values rho(r) starting at r=0
728 /// | ... | (nr values. Multiple values per line allowed.)
729 ///
730 /// Where:
731 /// - elem : atomic number for this element
732 /// - amass : atomic mass for this element in AMU
733 /// - latConstant : lattice constant for this elemnent in Angstroms
734 /// - lattticeType : lattice type for this element (e.g. FCC)
735 /// - nrho : number of values for the embedding function, F(rhobar)
736 /// - drho : table spacing for rhobar
737 /// - nr : number of values for Z(r) and rho(r)
738 /// - dr : table spacing for r in Angstroms
739 /// - rcutoff : potential cut-off distance in Angstroms
740 ///
741 /// funcfl format stores the "electrostatic interation" Z(r). This needs to
742 /// be converted to the pair potential phi(r).
743 /// using the formula
744 /// \f[phi = Z(r) * Z(r) / r\f]
745 /// NB: phi is not defined for r = 0
746 ///
747 /// Z(r) is in atomic units (i.e., sqrt[Hartree * bohr]) so it is
748 /// necesary to convert to eV.
749 ///
750 /// F(rhobar) is in eV.
751 ///
752 void eamReadFuncfl(EamPotential* pot, const char* dir, const char* potName)
753 {
754  char tmp[4096];
755 
756  sprintf(tmp, "%s/%s", dir, potName);
757  FILE* potFile = fopen(tmp, "r");
758  if (potFile == NULL)
759  fileNotFound("eamReadFuncfl", tmp);
760 
761  // line 1
762  fgets(tmp, sizeof(tmp), potFile);
763  char name[3];
764  sscanf(tmp, "%s", name);
765  strcpy(pot->name, name);
766 
767  // line 2
768  int nAtomic;
769  double mass, lat;
770  char latticeType[8];
771  fgets(tmp,sizeof(tmp),potFile);
772  sscanf(tmp, "%d %le %le %s", &nAtomic, &mass, &lat, latticeType);
773  pot->atomicNo = nAtomic;
774  pot->lat = lat;
775  pot->mass = mass*amuToInternalMass; // file has mass in AMU.
776  strcpy(pot->latticeType, latticeType);
777 
778  // line 3
779  int nRho, nR;
780  double dRho, dR, cutoff;
781  fgets(tmp,sizeof(tmp),potFile);
782  sscanf(tmp, "%d %le %d %le %le", &nRho, &dRho, &nR, &dR, &cutoff);
783  pot->cutoff = cutoff;
784  real_t x0 = 0.0; // tables start at zero.
785 
786  // allocate read buffer
787  int bufSize = MAX(nRho, nR);
788  real_t* buf = comdMalloc(bufSize * sizeof(real_t));
789 
790  // read embedding energy
791  for (int ii=0; ii<nRho; ++ii)
792  fscanf(potFile, FMT1, buf+ii);
793  pot->f = initInterpolationObject(nRho, x0, dRho, buf);
794 
795  // read Z(r) and convert to phi(r)
796  for (int ii=0; ii<nR; ++ii)
797  fscanf(potFile, FMT1, buf+ii);
798  for (int ii=1; ii<nR; ++ii)
799  {
800  real_t r = x0 + ii*dR;
801  buf[ii] *= buf[ii] / r;
802  buf[ii] *= hartreeToEv * bohrToAngs; // convert to eV
803  }
804  buf[0] = buf[1] + (buf[1] - buf[2]); // linear interpolation to get phi[0].
805  pot->phi = initInterpolationObject(nR, x0, dR, buf);
806 
807  // read electron density rho
808  for (int ii=0; ii<nR; ++ii)
809  fscanf(potFile, FMT1, buf+ii);
810  pot->rho = initInterpolationObject(nR, x0, dR, buf);
811 
812  comdFree(buf);
813 
814 /* printPot(pot->f, "funcflDataF.txt"); */
815 /* printPot(pot->rho, "funcflDataRho.txt"); */
816 /* printPot(pot->phi, "funcflDataPhi.txt"); */
817 }
818 
819 void fileNotFound(const char* callSite, const char* filename)
820 {
821  fprintf(screenOut,
822  "%s: Can't open file %s. Fatal Error.\n", callSite, filename);
823  exit(-1);
824 }
825 
826 void notAlloyReady(const char* callSite)
827 {
828  fprintf(screenOut,
829  "%s: CoMD 1.1 does not support alloys and cannot\n"
830  " read setfl files with multiple species. Fatal Error.\n", callSite);
831  exit(-1);
832 }
833 
834 void typeNotSupported(const char* callSite, const char* type)
835 {
836  fprintf(screenOut,
837  "%s: Potential type %s not supported. Fatal Error.\n", callSite, type);
838  exit(-1);
839 }