aboutsummaryrefslogtreecommitdiff
path: root/MultiSource/Benchmarks/DOE-ProxyApps-C/CoMD/eam.c
diff options
context:
space:
mode:
Diffstat (limited to 'MultiSource/Benchmarks/DOE-ProxyApps-C/CoMD/eam.c')
-rw-r--r--MultiSource/Benchmarks/DOE-ProxyApps-C/CoMD/eam.c839
1 files changed, 0 insertions, 839 deletions
diff --git a/MultiSource/Benchmarks/DOE-ProxyApps-C/CoMD/eam.c b/MultiSource/Benchmarks/DOE-ProxyApps-C/CoMD/eam.c
deleted file mode 100644
index 1b43698b..00000000
--- a/MultiSource/Benchmarks/DOE-ProxyApps-C/CoMD/eam.c
+++ /dev/null
@@ -1,839 +0,0 @@
-/// \file
-/// Compute forces for the Embedded Atom Model (EAM).
-///
-/// The Embedded Atom Model (EAM) is a widely used model of atomic
-/// interactions in simple metals.
-///
-/// http://en.wikipedia.org/wiki/Embedded_atom_model
-///
-/// In the EAM, the total potential energy is written as a sum of a pair
-/// potential and the embedding energy, F:
-///
-/// \f[
-/// U = \sum_{ij} \varphi(r_{ij}) + \sum_i F({\bar\rho_i})
-/// \f]
-///
-/// The pair potential \f$\varphi_{ij}\f$ is a two-body inter-atomic
-/// potential, similar to the Lennard-Jones potential, and
-/// \f$F(\bar\rho)\f$ is interpreted as the energy required to embed an
-/// atom in an electron field with density \f$\bar\rho\f$. The local
-/// electon density at site i is calulated by summing the "effective
-/// electron density" due to all neighbors of atom i:
-///
-/// \f[
-/// \bar\rho_i = \sum_j \rho_j(r_{ij})
-/// \f]
-///
-/// The force on atom i, \f${\bf F}_i\f$ is given by
-///
-/// \f{eqnarray*}{
-/// {\bf F}_i & = & -\nabla_i \sum_{jk} U(r_{jk})\\
-/// & = & - \sum_j\left\{
-/// \varphi'(r_{ij}) +
-/// [F'(\bar\rho_i) + F'(\bar\rho_j)]\rho'(r_{ij})
-/// \right\} \hat{r}_{ij}
-/// \f}
-///
-/// where primes indicate the derivative of a function with respect to
-/// its argument and \f$\hat{r}_{ij}\f$ is a unit vector in the
-/// direction from atom i to atom j.
-///
-/// The form of this force expression has two significant consequences.
-/// First, unlike with a simple pair potential, it is not possible to
-/// compute the potential energy and the forces on the atoms in a single
-/// loop over the pairs. The terms involving \f$ F'(\bar\rho) \f$
-/// cannot be calculated until \f$ \bar\rho \f$ is known, but
-/// calculating \f$ \bar\rho \f$ requires a loop over the pairs. Hence
-/// the EAM force routine contains three loops.
-///
-/// -# Loop over all pairs, compute the two-body
-/// interaction and the electron density at each atom
-/// -# Loop over all atoms, compute the embedding energy and its
-/// derivative for each atom
-/// -# Loop over all pairs, compute the embedding
-/// energy contribution to the force and add to the two-body force
-///
-/// The second loop over pairs doubles the data motion requirement
-/// relative to a simple pair potential.
-///
-/// The second consequence of the force expression is that computing the
-/// forces on all atoms requires additional communication beyond the
-/// coordinates of all remote atoms within the cutoff distance. This is
-/// again because of the terms involving \f$ F'(\bar\rho_j) \f$. If
-/// atom j is a remote atom, the local task cannot compute \f$
-/// \bar\rho_j \f$. (Such a calculation would require all the neighbors
-/// of atom j, some of which can be up to 2 times the cutoff distance
-/// away from a local atom---outside the typical halo exchange range.)
-///
-/// To obtain the needed remote density we introduce a second halo
-/// exchange after loop number 2 to communicate \f$ F'(\bar\rho) \f$ for
-/// remote atoms. This provides the data we need to complete the third
-/// loop, but at the cost of introducing a communication operation in
-/// the middle of the force routine.
-///
-/// At least two alternate methods can be used to deal with the remote
-/// density problem. One possibility is to extend the halo exchange
-/// radius for the atom exchange to twice the potential cutoff distance.
-/// This is likely undesirable due to large increase in communication
-/// volume. The other possibility is to accumulate partial force terms
-/// on the tasks where they can be computed. In this method, tasks will
-/// compute force contributions for remote atoms, then communicate the
-/// partial forces at the end of the halo exchange. This method has the
-/// advantage that the communication is deffered until after the force
-/// loops, but the disadvantage that three times as much data needs to
-/// be set (three components of the force vector instead of a single
-/// scalar \f$ F'(\bar\rho) \f$.
-
-
-#include "eam.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-#include <assert.h>
-
-#include "constants.h"
-#include "memUtils.h"
-#include "parallel.h"
-#include "linkCells.h"
-#include "CoMDTypes.h"
-#include "performanceTimers.h"
-#include "haloExchange.h"
-
-#define MAX(A,B) ((A) > (B) ? (A) : (B))
-
-/// Handles interpolation of tabular data.
-///
-/// \see initInterpolationObject
-/// \see interpolate
-typedef struct InterpolationObjectSt
-{
- int n; //!< the number of values in the table
- real_t x0; //!< the starting ordinate range
- real_t invDx; //!< the inverse of the table spacing
- real_t* values; //!< the abscissa values
-} InterpolationObject;
-
-/// Derived struct for an EAM potential.
-/// Uses table lookups for function evaluation.
-/// Polymorphic with BasePotential.
-/// \see BasePotential
-typedef struct EamPotentialSt
-{
- real_t cutoff; //!< potential cutoff distance in Angstroms
- real_t mass; //!< mass of atoms in intenal units
- real_t lat; //!< lattice spacing (angs) of unit cell
- char latticeType[8]; //!< lattice type, e.g. FCC, BCC, etc.
- char name[3]; //!< element name
- int atomicNo; //!< atomic number
- int (*force)(SimFlat* s); //!< function pointer to force routine
- void (*print)(FILE* file, BasePotential* pot);
- void (*destroy)(BasePotential** pot); //!< destruction of the potential
- InterpolationObject* phi; //!< Pair energy
- InterpolationObject* rho; //!< Electron Density
- InterpolationObject* f; //!< Embedding Energy
-
- real_t* rhobar; //!< per atom storage for rhobar
- real_t* dfEmbed; //!< per atom storage for derivative of Embedding
- HaloExchange* forceExchange;
- ForceExchangeData* forceExchangeData;
-} EamPotential;
-
-// EAM functionality
-static int eamForce(SimFlat* s);
-static void eamPrint(FILE* file, BasePotential* pot);
-static void eamDestroy(BasePotential** pot);
-static void eamBcastPotential(EamPotential* pot);
-
-
-// Table interpolation functionality
-static InterpolationObject* initInterpolationObject(
- int n, real_t x0, real_t dx, real_t* data);
-static void destroyInterpolationObject(InterpolationObject** table);
-static void interpolate(InterpolationObject* table, real_t r, real_t* f, real_t* df);
-static void bcastInterpolationObject(InterpolationObject** table);
-static void printTableData(InterpolationObject* table, const char* fileName);
-
-
-// Read potential tables from files.
-static void eamReadSetfl(EamPotential* pot, const char* dir, const char* potName);
-static void eamReadFuncfl(EamPotential* pot, const char* dir, const char* potName);
-static void fileNotFound(const char* callSite, const char* filename);
-static void notAlloyReady(const char* callSite);
-static void typeNotSupported(const char* callSite, const char* type);
-
-
-/// Allocate and initialize the EAM potential data structure.
-///
-/// \param [in] dir The directory in which potential table files are found.
-/// \param [in] file The name of the potential table file.
-/// \param [in] type The file format of the potential file (setfl or funcfl).
-BasePotential* initEamPot(const char* dir, const char* file, const char* type)
-{
- EamPotential* pot = comdMalloc(sizeof(EamPotential));
- assert(pot);
- pot->force = eamForce;
- pot->print = eamPrint;
- pot->destroy = eamDestroy;
- pot->phi = NULL;
- pot->rho = NULL;
- pot->f = NULL;
-
- // Initialization of the next three items requires information about
- // the parallel decomposition and link cells that isn't available
- // with the potential is initialized. Hence, we defer their
- // initialization until the first time we call the force routine.
- pot->dfEmbed = NULL;
- pot->rhobar = NULL;
- pot->forceExchange = NULL;
-
- if (getMyRank() == 0)
- {
- if (strcmp(type, "setfl" ) == 0)
- eamReadSetfl(pot, dir, file);
- else if (strcmp(type,"funcfl") == 0)
- eamReadFuncfl(pot, dir, file);
- else
- typeNotSupported("initEamPot", type);
- }
- eamBcastPotential(pot);
-
- return (BasePotential*) pot;
-}
-
-/// Calculate potential energy and forces for the EAM potential.
-///
-/// Three steps are required:
-///
-/// -# Loop over all atoms and their neighbors, compute the two-body
-/// interaction and the electron density at each atom
-/// -# Loop over all atoms, compute the embedding energy and its
-/// derivative for each atom
-/// -# Loop over all atoms and their neighbors, compute the embedding
-/// energy contribution to the force and add to the two-body force
-///
-int eamForce(SimFlat* s)
-{
- EamPotential* pot = (EamPotential*) s->pot;
- assert(pot);
-
- // set up halo exchange and internal storage on first call to forces.
- if (pot->forceExchange == NULL)
- {
- int maxTotalAtoms = MAXATOMS*s->boxes->nTotalBoxes;
- pot->dfEmbed = comdMalloc(maxTotalAtoms*sizeof(real_t));
- pot->rhobar = comdMalloc(maxTotalAtoms*sizeof(real_t));
- pot->forceExchange = initForceHaloExchange(s->domain, s->boxes);
- pot->forceExchangeData = comdMalloc(sizeof(ForceExchangeData));
- pot->forceExchangeData->dfEmbed = pot->dfEmbed;
- pot->forceExchangeData->boxes = s->boxes;
- }
-
- real_t rCut2 = pot->cutoff*pot->cutoff;
-
- // zero forces / energy / rho /rhoprime
- real_t etot = 0.0;
- memset(s->atoms->f, 0, s->boxes->nTotalBoxes*MAXATOMS*sizeof(real3));
- memset(s->atoms->U, 0, s->boxes->nTotalBoxes*MAXATOMS*sizeof(real_t));
- memset(pot->dfEmbed, 0, s->boxes->nTotalBoxes*MAXATOMS*sizeof(real_t));
- memset(pot->rhobar, 0, s->boxes->nTotalBoxes*MAXATOMS*sizeof(real_t));
-
- int nbrBoxes[27];
- // loop over local boxes
- for (int iBox=0; iBox<s->boxes->nLocalBoxes; iBox++)
- {
- int nIBox = s->boxes->nAtoms[iBox];
- int nNbrBoxes = getNeighborBoxes(s->boxes, iBox, nbrBoxes);
- // loop over neighbor boxes of iBox (some may be halo boxes)
- for (int jTmp=0; jTmp<nNbrBoxes; jTmp++)
- {
- int jBox = nbrBoxes[jTmp];
- if (jBox < iBox ) continue;
-
- int nJBox = s->boxes->nAtoms[jBox];
- // loop over atoms in iBox
- for (int iOff=MAXATOMS*iBox,ii=0; ii<nIBox; ii++,iOff++)
- {
- // loop over atoms in jBox
- for (int jOff=MAXATOMS*jBox,ij=0; ij<nJBox; ij++,jOff++)
- {
- if ( (iBox==jBox) &&(ij <= ii) ) continue;
-
- double r2 = 0.0;
- real3 dr;
- for (int k=0; k<3; k++)
- {
- dr[k]=s->atoms->r[iOff][k]-s->atoms->r[jOff][k];
- r2+=dr[k]*dr[k];
- }
- if(r2>rCut2) continue;
-
- double r = sqrt(r2);
-
- real_t phiTmp, dPhi, rhoTmp, dRho;
- interpolate(pot->phi, r, &phiTmp, &dPhi);
- interpolate(pot->rho, r, &rhoTmp, &dRho);
-
- for (int k=0; k<3; k++)
- {
- s->atoms->f[iOff][k] -= dPhi*dr[k]/r;
- s->atoms->f[jOff][k] += dPhi*dr[k]/r;
- }
-
- // update energy terms
- // calculate energy contribution based on whether
- // the neighbor box is local or remote
- if (jBox < s->boxes->nLocalBoxes)
- etot += phiTmp;
- else
- etot += 0.5*phiTmp;
-
- s->atoms->U[iOff] += 0.5*phiTmp;
- s->atoms->U[jOff] += 0.5*phiTmp;
-
- // accumulate rhobar for each atom
- pot->rhobar[iOff] += rhoTmp;
- pot->rhobar[jOff] += rhoTmp;
-
- } // loop over atoms in jBox
- } // loop over atoms in iBox
- } // loop over neighbor boxes
- } // loop over local boxes
-
- // Compute Embedding Energy
- // loop over all local boxes
- for (int iBox=0; iBox<s->boxes->nLocalBoxes; iBox++)
- {
- int iOff;
- int nIBox = s->boxes->nAtoms[iBox];
-
- // loop over atoms in iBox
- for (int iOff=MAXATOMS*iBox,ii=0; ii<nIBox; ii++,iOff++)
- {
- real_t fEmbed, dfEmbed;
- interpolate(pot->f, pot->rhobar[iOff], &fEmbed, &dfEmbed);
- pot->dfEmbed[iOff] = dfEmbed; // save derivative for halo exchange
- etot += fEmbed;
- s->atoms->U[iOff] += fEmbed;
- }
- }
-
- // exchange derivative of the embedding energy with repsect to rhobar
- startTimer(eamHaloTimer);
- haloExchange(pot->forceExchange, pot->forceExchangeData);
- stopTimer(eamHaloTimer);
-
- // third pass
- // loop over local boxes
- for (int iBox=0; iBox<s->boxes->nLocalBoxes; iBox++)
- {
- int nIBox = s->boxes->nAtoms[iBox];
- int nNbrBoxes = getNeighborBoxes(s->boxes, iBox, nbrBoxes);
- // loop over neighbor boxes of iBox (some may be halo boxes)
- for (int jTmp=0; jTmp<nNbrBoxes; jTmp++)
- {
- int jBox = nbrBoxes[jTmp];
- if(jBox < iBox) continue;
-
- int nJBox = s->boxes->nAtoms[jBox];
- // loop over atoms in iBox
- for (int iOff=MAXATOMS*iBox,ii=0; ii<nIBox; ii++,iOff++)
- {
- // loop over atoms in jBox
- for (int jOff=MAXATOMS*jBox,ij=0; ij<nJBox; ij++,jOff++)
- {
- if ((iBox==jBox) && (ij <= ii)) continue;
-
- double r2 = 0.0;
- real3 dr;
- for (int k=0; k<3; k++)
- {
- dr[k]=s->atoms->r[iOff][k]-s->atoms->r[jOff][k];
- r2+=dr[k]*dr[k];
- }
- if(r2>=rCut2) continue;
-
- real_t r = sqrt(r2);
-
- real_t rhoTmp, dRho;
- interpolate(pot->rho, r, &rhoTmp, &dRho);
-
- for (int k=0; k<3; k++)
- {
- s->atoms->f[iOff][k] -= (pot->dfEmbed[iOff]+pot->dfEmbed[jOff])*dRho*dr[k]/r;
- s->atoms->f[jOff][k] += (pot->dfEmbed[iOff]+pot->dfEmbed[jOff])*dRho*dr[k]/r;
- }
-
- } // loop over atoms in jBox
- } // loop over atoms in iBox
- } // loop over neighbor boxes
- } // loop over local boxes
-
- s->ePotential = (real_t) etot;
-
- return 0;
-}
-
-void eamPrint(FILE* file, BasePotential* pot)
-{
- EamPotential *eamPot = (EamPotential*) pot;
- fprintf(file, " Potential type : EAM\n");
- fprintf(file, " Species name : %s\n", eamPot->name);
- fprintf(file, " Atomic number : %d\n", eamPot->atomicNo);
- fprintf(file, " Mass : "FMT1" amu\n", eamPot->mass/amuToInternalMass); // print in amu
- fprintf(file, " Lattice type : %s\n", eamPot->latticeType);
- fprintf(file, " Lattice spacing : "FMT1" Angstroms\n", eamPot->lat);
- fprintf(file, " Cutoff : "FMT1" Angstroms\n", eamPot->cutoff);
-}
-
-void eamDestroy(BasePotential** pPot)
-{
- if ( ! pPot ) return;
- EamPotential* pot = *(EamPotential**)pPot;
- if ( ! pot ) return;
- destroyInterpolationObject(&(pot->phi));
- destroyInterpolationObject(&(pot->rho));
- destroyInterpolationObject(&(pot->f));
- destroyHaloExchange(&(pot->forceExchange));
- comdFree(pot);
- *pPot = NULL;
-
- return;
-}
-
-/// Broadcasts an EamPotential from rank 0 to all other ranks.
-/// If the table coefficients are read from a file only rank 0 does the
-/// read. Hence we need to broadcast the potential to all other ranks.
-void eamBcastPotential(EamPotential* pot)
-{
- assert(pot);
-
- struct
- {
- real_t cutoff, mass, lat;
- char latticeType[8];
- char name[3];
- int atomicNo;
- } buf;
- if (getMyRank() == 0)
- {
- buf.cutoff = pot->cutoff;
- buf.mass = pot->mass;
- buf.lat = pot->lat;
- buf.atomicNo = pot->atomicNo;
- strcpy(buf.latticeType, pot->latticeType);
- strcpy(buf.name, pot->name);
- }
- bcastParallel(&buf, sizeof(buf), 0);
- pot->cutoff = buf.cutoff;
- pot->mass = buf.mass;
- pot->lat = buf.lat;
- pot->atomicNo = buf.atomicNo;
- strcpy(pot->latticeType, buf.latticeType);
- strcpy(pot->name, buf.name);
-
- bcastInterpolationObject(&pot->phi);
- bcastInterpolationObject(&pot->rho);
- bcastInterpolationObject(&pot->f);
-}
-
-/// Builds a structure to store interpolation data for a tabular
-/// function. Interpolation must be supported on the range
-/// \f$[x_0, x_n]\f$, where \f$x_n = n*dx\f$.
-///
-/// \see interpolate
-/// \see bcastInterpolationObject
-/// \see destroyInterpolationObject
-///
-/// \param [in] n number of values in the table.
-/// \param [in] x0 minimum ordinate value of the table.
-/// \param [in] dx spacing of the ordinate values.
-/// \param [in] data abscissa values. An array of size n.
-InterpolationObject* initInterpolationObject(
- int n, real_t x0, real_t dx, real_t* data)
-{
- InterpolationObject* table =
- (InterpolationObject *)comdMalloc(sizeof(InterpolationObject)) ;
- assert(table);
-
- table->values = (real_t*)comdCalloc(1, (n+3)*sizeof(real_t));
- assert(table->values);
-
- table->values++;
- table->n = n;
- table->invDx = 1.0/dx;
- table->x0 = x0;
-
- for (int ii=0; ii<n; ++ii)
- table->values[ii] = data[ii];
-
- table->values[-1] = table->values[0];
- table->values[n+1] = table->values[n] = table->values[n-1];
-
- return table;
-}
-
-void destroyInterpolationObject(InterpolationObject** a)
-{
- if ( ! a ) return;
- if ( ! *a ) return;
- if ( (*a)->values)
- {
- (*a)->values--;
- comdFree((*a)->values);
- }
- comdFree(*a);
- *a = NULL;
-
- return;
-}
-
-/// Interpolate a table to determine f(r) and its derivative f'(r).
-///
-/// The forces on the particle are much more sensitive to the derivative
-/// of the potential than on the potential itself. It is therefore
-/// absolutely essential that the interpolated derivatives are smooth
-/// and continuous. This function uses simple quadratic interpolation
-/// to find f(r). Since quadric interpolants don't have smooth
-/// derivatives, f'(r) is computed using a 4 point finite difference
-/// stencil.
-///
-/// Interpolation is used heavily by the EAM force routine so this
-/// function is a potential performance hot spot. Feel free to
-/// reimplement this function (and initInterpolationObject if necessay)
-/// with any higher performing implementation of interpolation, as long
-/// as the alternate implmentation that has the required smoothness
-/// properties. Cubic splines are one common alternate choice.
-///
-/// \param [in] table Interpolation table.
-/// \param [in] r Point where function value is needed.
-/// \param [out] f The interpolated value of f(r).
-/// \param [out] df The interpolated value of df(r)/dr.
-void interpolate(InterpolationObject* table, real_t r, real_t* f, real_t* df)
-{
- const real_t* tt = table->values; // alias
-
- if ( r < table->x0 ) r = table->x0;
-
- r = (r-table->x0)*(table->invDx) ;
- int ii = (int)floor(r);
- if (ii > table->n)
- {
- ii = table->n;
- r = table->n / table->invDx;
- }
- // reset r to fractional distance
- r = r - floor(r);
-
- real_t g1 = tt[ii+1] - tt[ii-1];
- real_t g2 = tt[ii+2] - tt[ii];
-
- *f = tt[ii] + 0.5*r*(g1 + r*(tt[ii+1] + tt[ii-1] - 2.0*tt[ii]) );
-
- *df = 0.5*(g1 + r*(g2-g1))*table->invDx;
-}
-
-/// Broadcasts an InterpolationObject from rank 0 to all other ranks.
-///
-/// It is commonly the case that the data needed to create the
-/// interpolation table is available on only one task (for example, only
-/// one task has read the data from a file). Broadcasting the table
-/// eliminates the need to put broadcast code in multiple table readers.
-///
-/// \see eamBcastPotential
-void bcastInterpolationObject(InterpolationObject** table)
-{
- struct
- {
- int n;
- real_t x0, invDx;
- } buf;
-
- if (getMyRank() == 0)
- {
- buf.n = (*table)->n;
- buf.x0 = (*table)->x0;
- buf.invDx = (*table)->invDx;
- }
- bcastParallel(&buf, sizeof(buf), 0);
-
- if (getMyRank() != 0)
- {
- assert(*table == NULL);
- *table = comdMalloc(sizeof(InterpolationObject));
- (*table)->n = buf.n;
- (*table)->x0 = buf.x0;
- (*table)->invDx = buf.invDx;
- (*table)->values = comdMalloc(sizeof(real_t) * (buf.n+3) );
- (*table)->values++;
- }
-
- int valuesSize = sizeof(real_t) * ((*table)->n+3);
- bcastParallel((*table)->values-1, valuesSize, 0);
-}
-
-void printTableData(InterpolationObject* table, const char* fileName)
-{
- if (!printRank()) return;
-
- FILE* potData;
- potData = fopen(fileName,"w");
- real_t dR = 1.0/table->invDx;
- for (int i = 0; i<table->n; i++)
- {
- real_t r = table->x0+i*dR;
- fprintf(potData, "%d %e %e\n", i, r, table->values[i]);
- }
- fclose(potData);
-}
-
-/// Reads potential data from a setfl file and populates
-/// corresponding members and InterpolationObjects in an EamPotential.
-///
-/// setfl is a file format for tabulated potential functions used by
-/// the original EAM code DYNAMO. A setfl file contains EAM
-/// potentials for multiple elements.
-///
-/// The contents of a setfl file are:
-///
-/// | Line Num | Description
-/// | :------: | :----------
-/// | 1 - 3 | comments
-/// | 4 | ntypes type1 type2 ... typen
-/// | 5 | nrho drho nr dr rcutoff
-/// | F, rho | Following line 5 there is a block for each atom type with F, and rho.
-/// | b1 | ielem(i) amass(i) latConst(i) latType(i)
-/// | b2 | embedding function values F(rhobar) starting at rhobar=0
-/// | ... | (nrho values. Multiple values per line allowed.)
-/// | bn | electron density, starting at r=0
-/// | ... | (nr values. Multiple values per line allowed.)
-/// | repeat | Return to b1 for each atom type.
-/// | phi | phi_ij for (1,1), (2,1), (2,2), (3,1), (3,2), (3,3), (4,1), ...,
-/// | p1 | pair potential between type i and type j, starting at r=0
-/// | ... | (nr values. Multiple values per line allowed.)
-/// | repeat | Return to p1 for each phi_ij
-///
-/// Where:
-/// - ntypes : number of element types in the potential
-/// - nrho : number of points the embedding energy F(rhobar)
-/// - drho : table spacing for rhobar
-/// - nr : number of points for rho(r) and phi(r)
-/// - dr : table spacing for r in Angstroms
-/// - rcutoff : cut-off distance in Angstroms
-/// - ielem(i) : atomic number for element(i)
-/// - amass(i) : atomic mass for element(i) in AMU
-/// - latConst(i) : lattice constant for element(i) in Angstroms
-/// - latType(i) : lattice type for element(i)
-///
-/// setfl format stores r*phi(r), so we need to converted to the pair
-/// potential phi(r). In the file, phi(r)*r is in eV*Angstroms.
-/// NB: phi is not defined for r = 0
-///
-/// F(rhobar) is in eV.
-///
-void eamReadSetfl(EamPotential* pot, const char* dir, const char* potName)
-{
- char tmp[4096];
- sprintf(tmp, "%s/%s", dir, potName);
-
- FILE* potFile = fopen(tmp, "r");
- if (potFile == NULL)
- fileNotFound("eamReadSetfl", tmp);
-
- // read the first 3 lines (comments)
- fgets(tmp, sizeof(tmp), potFile);
- fgets(tmp, sizeof(tmp), potFile);
- fgets(tmp, sizeof(tmp), potFile);
-
- // line 4
- fgets(tmp, sizeof(tmp), potFile);
- int nElems;
- sscanf(tmp, "%d", &nElems);
- if( nElems != 1 )
- notAlloyReady("eamReadSetfl");
-
- //line 5
- int nRho, nR;
- double dRho, dR, cutoff;
- // The same cutoff is used by all alloys, NB: cutoff = nR * dR is redundant
- fgets(tmp, sizeof(tmp), potFile);
- sscanf(tmp, "%d %le %d %le %le", &nRho, &dRho, &nR, &dR, &cutoff);
- pot->cutoff = cutoff;
-
- // **** THIS CODE IS RESTRICTED TO ONE ELEMENT
- // Per-atom header
- fgets(tmp, sizeof(tmp), potFile);
- int nAtomic;
- double mass, lat;
- char latticeType[8];
- sscanf(tmp, "%d %le %le %s", &nAtomic, &mass, &lat, latticeType);
- pot->atomicNo = nAtomic;
- pot->lat = lat;
- pot->mass = mass * amuToInternalMass; // file has mass in AMU.
- strcpy(pot->latticeType, latticeType);
-
- // allocate read buffer
- int bufSize = MAX(nRho, nR);
- real_t* buf = comdMalloc(bufSize * sizeof(real_t));
- real_t x0 = 0.0;
-
- // Read embedding energy F(rhobar)
- for (int ii=0; ii<nRho; ++ii)
- fscanf(potFile, FMT1, buf+ii);
- pot->f = initInterpolationObject(nRho, x0, dRho, buf);
-
- // Read electron density rho(r)
- for (int ii=0; ii<nR; ++ii)
- fscanf(potFile, FMT1, buf+ii);
- pot->rho = initInterpolationObject(nR, x0, dR, buf);
-
- // Read phi(r)*r and convert to phi(r)
- for (int ii=0; ii<nR; ++ii)
- fscanf(potFile, FMT1, buf+ii);
- for (int ii=1; ii<nR; ++ii)
- {
- real_t r = x0 + ii*dR;
- buf[ii] /= r;
- }
- buf[0] = buf[1] + (buf[1] - buf[2]); // Linear interpolation to get phi[0].
- pot->phi = initInterpolationObject(nR, x0, dR, buf);
-
- comdFree(buf);
-
- // write to text file for comparison, currently commented out
-/* printPot(pot->f, "SetflDataF.txt"); */
-/* printPot(pot->rho, "SetflDataRho.txt"); */
-/* printPot(pot->phi, "SetflDataPhi.txt"); */
-}
-
-/// Reads potential data from a funcfl file and populates
-/// corresponding members and InterpolationObjects in an EamPotential.
-///
-/// funcfl is a file format for tabulated potential functions used by
-/// the original EAM code DYNAMO. A funcfl file contains an EAM
-/// potential for a single element.
-///
-/// The contents of a funcfl file are:
-///
-/// | Line Num | Description
-/// | :------: | :----------
-/// | 1 | comments
-/// | 2 | elem amass latConstant latType
-/// | 3 | nrho drho nr dr rcutoff
-/// | 4 | embedding function values F(rhobar) starting at rhobar=0
-/// | ... | (nrho values. Multiple values per line allowed.)
-/// | x' | electrostatic interation Z(r) starting at r=0
-/// | ... | (nr values. Multiple values per line allowed.)
-/// | y' | electron density values rho(r) starting at r=0
-/// | ... | (nr values. Multiple values per line allowed.)
-///
-/// Where:
-/// - elem : atomic number for this element
-/// - amass : atomic mass for this element in AMU
-/// - latConstant : lattice constant for this elemnent in Angstroms
-/// - lattticeType : lattice type for this element (e.g. FCC)
-/// - nrho : number of values for the embedding function, F(rhobar)
-/// - drho : table spacing for rhobar
-/// - nr : number of values for Z(r) and rho(r)
-/// - dr : table spacing for r in Angstroms
-/// - rcutoff : potential cut-off distance in Angstroms
-///
-/// funcfl format stores the "electrostatic interation" Z(r). This needs to
-/// be converted to the pair potential phi(r).
-/// using the formula
-/// \f[phi = Z(r) * Z(r) / r\f]
-/// NB: phi is not defined for r = 0
-///
-/// Z(r) is in atomic units (i.e., sqrt[Hartree * bohr]) so it is
-/// necesary to convert to eV.
-///
-/// F(rhobar) is in eV.
-///
-void eamReadFuncfl(EamPotential* pot, const char* dir, const char* potName)
-{
- char tmp[4096];
-
- sprintf(tmp, "%s/%s", dir, potName);
- FILE* potFile = fopen(tmp, "r");
- if (potFile == NULL)
- fileNotFound("eamReadFuncfl", tmp);
-
- // line 1
- fgets(tmp, sizeof(tmp), potFile);
- char name[3];
- sscanf(tmp, "%s", name);
- strcpy(pot->name, name);
-
- // line 2
- int nAtomic;
- double mass, lat;
- char latticeType[8];
- fgets(tmp,sizeof(tmp),potFile);
- sscanf(tmp, "%d %le %le %s", &nAtomic, &mass, &lat, latticeType);
- pot->atomicNo = nAtomic;
- pot->lat = lat;
- pot->mass = mass*amuToInternalMass; // file has mass in AMU.
- strcpy(pot->latticeType, latticeType);
-
- // line 3
- int nRho, nR;
- double dRho, dR, cutoff;
- fgets(tmp,sizeof(tmp),potFile);
- sscanf(tmp, "%d %le %d %le %le", &nRho, &dRho, &nR, &dR, &cutoff);
- pot->cutoff = cutoff;
- real_t x0 = 0.0; // tables start at zero.
-
- // allocate read buffer
- int bufSize = MAX(nRho, nR);
- real_t* buf = comdMalloc(bufSize * sizeof(real_t));
-
- // read embedding energy
- for (int ii=0; ii<nRho; ++ii)
- fscanf(potFile, FMT1, buf+ii);
- pot->f = initInterpolationObject(nRho, x0, dRho, buf);
-
- // read Z(r) and convert to phi(r)
- for (int ii=0; ii<nR; ++ii)
- fscanf(potFile, FMT1, buf+ii);
- for (int ii=1; ii<nR; ++ii)
- {
- real_t r = x0 + ii*dR;
- buf[ii] *= buf[ii] / r;
- buf[ii] *= hartreeToEv * bohrToAngs; // convert to eV
- }
- buf[0] = buf[1] + (buf[1] - buf[2]); // linear interpolation to get phi[0].
- pot->phi = initInterpolationObject(nR, x0, dR, buf);
-
- // read electron density rho
- for (int ii=0; ii<nR; ++ii)
- fscanf(potFile, FMT1, buf+ii);
- pot->rho = initInterpolationObject(nR, x0, dR, buf);
-
- comdFree(buf);
-
-/* printPot(pot->f, "funcflDataF.txt"); */
-/* printPot(pot->rho, "funcflDataRho.txt"); */
-/* printPot(pot->phi, "funcflDataPhi.txt"); */
-}
-
-void fileNotFound(const char* callSite, const char* filename)
-{
- fprintf(screenOut,
- "%s: Can't open file %s. Fatal Error.\n", callSite, filename);
- exit(-1);
-}
-
-void notAlloyReady(const char* callSite)
-{
- fprintf(screenOut,
- "%s: CoMD 1.1 does not support alloys and cannot\n"
- " read setfl files with multiple species. Fatal Error.\n", callSite);
- exit(-1);
-}
-
-void typeNotSupported(const char* callSite, const char* type)
-{
- fprintf(screenOut,
- "%s: Potential type %s not supported. Fatal Error.\n", callSite, type);
- exit(-1);
-}