Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F80305348
pair_agni.cpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Sat, Aug 31, 01:37
Size
14 KB
Mime Type
text/x-c
Expires
Mon, Sep 2, 01:37 (2 d)
Engine
blob
Format
Raw Data
Handle
20063038
Attached To
rLAMMPS lammps
pair_agni.cpp
View Options
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing authors: Axel Kohlmeyer (Temple U), Venkatesh Botu
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_agni.h"
#include "atom.h"
#include "neighbor.h"
#include "neigh_request.h"
#include "force.h"
#include "comm.h"
#include "memory.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "memory.h"
#include "error.h"
#include "citeme.h"
#include "math_special.h"
#include "math_const.h"
using namespace LAMMPS_NS;
using namespace MathSpecial;
static const char cite_pair_agni[] =
"pair agni command:\n\n"
"@article{botu2015adaptive,\n"
" author = {Botu, Venkatesh and Ramprasad, Rampi},\n"
" title = {Adaptive machine learning framework to"
" accelerate ab initio molecular dynamics},\n"
" journal = {International Journal of Quantum Chemistry},\n"
" volume = {115},\n"
" number = {16},\n"
" pages = {1074--1083},\n"
" year = {2015},\n"
" publisher = {Wiley Online Library}\n"
"}\n\n"
"@article{botu2015learning,\n"
" author = {Botu, Venkatesh and Ramprasad, Rampi},\n"
" title = {Learning scheme to predict atomic forces"
" and accelerate materials simulations},\n"
" journal = {Physical Review B},\n"
" volume = {92},\n"
" number = {9},\n"
" pages = {094306},\n"
" year = {2015},\n"
" publisher = {APS}\n"
"}\n\n"
"@article{botu2017jpc,\n"
" author = {Botu, V. and Batra, R. and Chapman, J. and Ramprasad, Rampi},\n"
" journal = {J. Phys. Chem. C},\n"
" volume = {121},\n"
" number = {1},\n"
" pages = {511},\n"
" year = {2017},\n"
"}\n\n";
#define AGNI_VERSION 1
#define MAXLINE 10240
#define MAXWORD 40
/* ---------------------------------------------------------------------- */
PairAGNI::PairAGNI(LAMMPS *lmp) : Pair(lmp)
{
if (lmp->citeme) lmp->citeme->add(cite_pair_agni);
single_enable = 0;
restartinfo = 0;
one_coeff = 1;
manybody_flag = 1;
no_virial_fdotr_compute = 1;
nelements = 0;
elements = NULL;
elem2param = NULL;
nparams = 0;
params = NULL;
map = NULL;
cutmax = 0.0;
}
/* ----------------------------------------------------------------------
check if allocated, since class can be destructed when incomplete
------------------------------------------------------------------------- */
PairAGNI::~PairAGNI()
{
if (elements)
for (int i = 0; i < nelements; i++) delete [] elements[i];
delete [] elements;
if (params) {
for (int i = 0; i < nparams; ++i) {
int n = params[i].numeta;
for (int j = 0; j < n; ++j) {
delete [] params[i].xU[j];
}
delete [] params[i].eta;
delete [] params[i].alpha;
delete [] params[i].xU;
delete [] params[i].yU;
}
memory->destroy(params);
params = NULL;
}
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
delete [] map;
}
}
/* ---------------------------------------------------------------------- */
void PairAGNI::compute(int eflag, int vflag)
{
int i,j,k,ii,jj,inum,jnum,itype;
double xtmp,ytmp,ztmp,delx,dely,delz;
double rsq;
int *ilist,*jlist,*numneigh,**firstneigh;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
int *type = atom->type;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
double fxtmp,fytmp,fztmp;
double *Vx, *Vy, *Vz;
// loop over full neighbor list of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
itype = map[type[i]];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
fxtmp = fytmp = fztmp = 0.0;
const Param &iparam = params[elem2param[itype]];
Vx = new double[iparam.numeta];
Vy = new double[iparam.numeta];
Vz = new double[iparam.numeta];
memset(Vx,0,iparam.numeta*sizeof(double));
memset(Vy,0,iparam.numeta*sizeof(double));
memset(Vz,0,iparam.numeta*sizeof(double));
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if ((rsq > 0.0) && (rsq < iparam.cutsq)) {
const double r = sqrt(rsq);
const double cF = 0.5*(cos((MathConst::MY_PI*r)/iparam.cut)+1.0);
const double wX = cF*delx/r;
const double wY = cF*dely/r;
const double wZ = cF*delz/r;
for (k = 0; k < iparam.numeta; ++k) {
const double e = exp(-(iparam.eta[k]*rsq));
Vx[k] += wX*e;
Vy[k] += wY*e;
Vz[k] += wZ*e;
}
}
}
for (j = 0; j < iparam.numtrain; ++j) {
double kx = 0.0;
double ky = 0.0;
double kz = 0.0;
for(int k = 0; k < iparam.numeta; ++k) {
const double xu = iparam.xU[k][j];
kx += square(Vx[k] - xu);
ky += square(Vy[k] - xu);
kz += square(Vz[k] - xu);
}
const double e = -0.5/(square(iparam.sigma));
fxtmp += iparam.alpha[j]*exp(kx*e);
fytmp += iparam.alpha[j]*exp(ky*e);
fztmp += iparam.alpha[j]*exp(kz*e);
}
fxtmp += iparam.b;
fytmp += iparam.b;
fztmp += iparam.b;
f[i][0] += fxtmp;
f[i][1] += fytmp;
f[i][2] += fztmp;
if (evflag) ev_tally_xyz_full(i,0.0,0.0,fxtmp,fytmp,fztmp,delx,dely,delz);
delete [] Vx;
delete [] Vy;
delete [] Vz;
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ---------------------------------------------------------------------- */
void PairAGNI::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
memory->create(cutsq,n+1,n+1,"pair:cutsq");
map = new int[n+1];
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairAGNI::settings(int narg, char **arg)
{
if (narg != 0) error->all(FLERR,"Illegal pair_style command");
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairAGNI::coeff(int narg, char **arg)
{
int i,j,n;
if (!allocated) allocate();
if (narg != 3 + atom->ntypes)
error->all(FLERR,"Incorrect args for pair coefficients");
// insure I,J args are * *
if (strcmp(arg[0],"*") != 0 || strcmp(arg[1],"*") != 0)
error->all(FLERR,"Incorrect args for pair coefficients");
// read args that map atom types to elements in potential file
// map[i] = which element the Ith atom type is, -1 if NULL
// nelements = # of unique elements
// elements = list of element names
if (elements) {
for (i = 0; i < nelements; i++) delete [] elements[i];
delete [] elements;
}
elements = new char*[atom->ntypes];
for (i = 0; i < atom->ntypes; i++) elements[i] = NULL;
nelements = 0;
for (i = 3; i < narg; i++) {
if (strcmp(arg[i],"NULL") == 0) {
map[i-2] = -1;
continue;
}
for (j = 0; j < nelements; j++)
if (strcmp(arg[i],elements[j]) == 0) break;
map[i-2] = j;
if (j == nelements) {
n = strlen(arg[i]) + 1;
elements[j] = new char[n];
strcpy(elements[j],arg[i]);
nelements++;
}
}
// read potential file and initialize potential parameters
read_file(arg[2]);
setup_params();
// clear setflag since coeff() called once with I,J = * *
n = atom->ntypes;
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
// set setflag i,j for type pairs where both are mapped to elements
int count = 0;
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
if (map[i] >= 0 && map[j] >= 0) {
setflag[i][j] = 1;
count++;
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairAGNI::init_style()
{
// need a full neighbor list
int irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->half = 0;
neighbor->requests[irequest]->full = 1;
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairAGNI::init_one(int i, int j)
{
if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
return cutmax;
}
/* ---------------------------------------------------------------------- */
void PairAGNI::read_file(char *file)
{
memory->sfree(params);
params = NULL;
nparams = 0;
// open file on proc 0 only
// then read line by line and broadcast the line to all MPI ranks
FILE *fp;
if (comm->me == 0) {
fp = force->open_potential(file);
if (fp == NULL) {
char str[128];
sprintf(str,"Cannot open AGNI potential file %s",file);
error->one(FLERR,str);
}
}
int i,j,n,nwords,curparam,wantdata;
char line[MAXLINE],*ptr;
int eof = 0;
char **words = new char*[MAXWORD+1];
while (1) {
n = 0;
if (comm->me == 0) {
ptr = fgets(line,MAXLINE,fp);
if (ptr == NULL) {
eof = 1;
fclose(fp);
} else n = strlen(line) + 1;
}
MPI_Bcast(&eof,1,MPI_INT,0,world);
if (eof) break;
MPI_Bcast(&n,1,MPI_INT,0,world);
MPI_Bcast(line,n,MPI_CHAR,0,world);
// strip comment, skip line if blank
if ((ptr = strchr(line,'#'))) *ptr = '\0';
nwords = atom->count_words(line);
if (nwords == 0) continue;
if (nwords > MAXWORD)
error->all(FLERR,"Increase MAXWORD and recompile");
// words = ptrs to all words in line
nwords = 0;
words[nwords++] = strtok(line," \t\n\r\f");
while ((words[nwords++] = strtok(NULL," \t\n\r\f"))) continue;
--nwords;
if ((nwords == 2) && (strcmp(words[0],"generation") == 0)) {
int ver = atoi(words[1]);
if (ver != AGNI_VERSION)
error->all(FLERR,"Incompatible AGNI potential file version");
if ((ver == 1) && (nelements != 1))
error->all(FLERR,"Cannot handle multi-element systems with this potential");
} else if ((nwords == 2) && (strcmp(words[0],"n_elements") == 0)) {
nparams = atoi(words[1]);
if ((nparams < 1) || params) // sanity check
error->all(FLERR,"Invalid AGNI potential file");
params = memory->create(params,nparams,"pair:params");
memset(params,0,nparams*sizeof(Param));
curparam = -1;
} else if (params && (nwords == nparams+1) && (strcmp(words[0],"element") == 0)) {
wantdata = -1;
for (i = 0; i < nparams; ++i) {
for (j = 0; j < nelements; ++j)
if (strcmp(words[i+1],elements[j]) == 0) break;
if (j == nelements)
error->all(FLERR,"No suitable parameters for requested element found");
else params[i].ielement = j;
}
} else if (params && (nwords == 2) && (strcmp(words[0],"interaction") == 0)) {
for (i = 0; i < nparams; ++i)
if (strcmp(words[1],elements[params[i].ielement]) == 0) curparam = i;
} else if ((curparam >=0) && (nwords == 1) && (strcmp(words[0],"endVar") == 0)) {
int numtrain = params[curparam].numtrain;
int numeta = params[curparam].numeta;
params[curparam].alpha = new double[numtrain];
params[curparam].yU = new double[numtrain];
params[curparam].xU = new double*[numeta];
for (i = 0; i < numeta; ++i)
params[curparam].xU[i] = new double[numtrain];
wantdata = curparam;
curparam = -1;
} else if ((curparam >=0) && (nwords == 2) && (strcmp(words[0],"Rc") == 0)) {
params[curparam].cut = atof(words[1]);
} else if ((curparam >=0) && (nwords == 2) && (strcmp(words[0],"Rs") == 0)) {
; // ignored
} else if ((curparam >=0) && (nwords == 2) && (strcmp(words[0],"neighbors") == 0)) {
; // ignored
} else if ((curparam >=0) && (nwords == 2) && (strcmp(words[0],"sigma") == 0)) {
params[curparam].sigma = atof(words[1]);
} else if ((curparam >=0) && (nwords == 2) && (strcmp(words[0],"lambda") == 0)) {
params[curparam].lambda = atof(words[1]);
} else if ((curparam >=0) && (nwords == 2) && (strcmp(words[0],"b") == 0)) {
params[curparam].b = atof(words[1]);
} else if ((curparam >=0) && (nwords == 2) && (strcmp(words[0],"n_train") == 0)) {
params[curparam].numtrain = atoi(words[1]);
} else if ((curparam >=0) && (nwords > 1) && (strcmp(words[0],"eta") == 0)) {
params[curparam].numeta = nwords-1;
params[curparam].eta = new double[nwords-1];
for (i = 0, j = 1 ; j < nwords; ++i, ++j)
params[curparam].eta[i] = atof(words[j]);
} else if (params && (wantdata >=0) && (nwords == params[wantdata].numeta+3)) {
n = (int) atof(words[0]);
for (i = 0; i < params[wantdata].numeta; ++i) {
params[wantdata].xU[i][n] = atof(words[i+1]);
}
params[wantdata].yU[n] = atof(words[params[wantdata].numeta+1]);
params[wantdata].alpha[n] = atof(words[params[wantdata].numeta+2]);
} else {
if (comm->me == 0)
error->warning(FLERR,"Ignoring unknown content in AGNI potential file.");
}
}
delete [] words;
}
/* ---------------------------------------------------------------------- */
void PairAGNI::setup_params()
{
int i,m,n;
double rtmp;
// set elem2param for all elements
memory->destroy(elem2param);
memory->create(elem2param,nelements,"pair:elem2param");
for (i = 0; i < nelements; i++) {
n = -1;
for (m = 0; m < nparams; m++) {
if (i == params[m].ielement) {
if (n >= 0) error->all(FLERR,"Potential file has duplicate entry");
n = m;
}
}
if (n < 0) error->all(FLERR,"Potential file is missing an entry");
elem2param[i] = n;
}
// compute parameter values derived from inputs
// set cutsq using shortcut to reduce neighbor list for accelerated
// calculations. cut must remain unchanged as it is a potential parameter
// (cut = a*sigma)
cutmax = 0.0;
for (m = 0; m < nparams; m++) {
rtmp = params[m].cut;
params[m].cutsq = rtmp * rtmp;
if (rtmp > cutmax) cutmax = rtmp;
}
}
Event Timeline
Log In to Comment