934 lines
29 KiB
C++
934 lines
29 KiB
C++
/* ----------------------------------------------------------------------
|
|
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: Valeriu Smirichinski, Ryan Elliott,
|
|
Ellad Tadmor (U Minn)
|
|
------------------------------------------------------------------------- */
|
|
|
|
#include "math.h"
|
|
#include "stdio.h"
|
|
#include "stdlib.h"
|
|
#include "string.h"
|
|
#include "pair_kim.h"
|
|
#include "atom.h"
|
|
#include "comm.h"
|
|
#include "force.h"
|
|
#include "neighbor.h"
|
|
#include "neigh_list.h"
|
|
#include "neigh_request.h"
|
|
#include "update.h"
|
|
#include "memory.h"
|
|
#include "error.h"
|
|
|
|
#include "KIM_API.h"
|
|
|
|
using namespace LAMMPS_NS;
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
PairKIM::PairKIM(LAMMPS *lmp) : Pair(lmp)
|
|
{
|
|
nelements = 0;
|
|
elements = NULL;
|
|
|
|
single_enable = 0;
|
|
restartinfo = 0;
|
|
one_coeff = 1;
|
|
no_virial_fdotr_compute = 1;
|
|
|
|
virialGlobal_ind = -1;
|
|
particleVirial_ind = -1;
|
|
process_dEdr_ind = -1;
|
|
|
|
modelname = NULL;
|
|
testname = NULL;
|
|
|
|
maxall = 0;
|
|
kimtype = NULL;
|
|
fcopy = NULL;
|
|
onebuf = NULL;
|
|
|
|
pointsto = 0;
|
|
memory->create(Rij,3*KIM_API_MAX_NEIGHBORS,"pair:Rij");
|
|
|
|
// reverse comm even if newton off
|
|
|
|
comm_reverse_off = 9;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
PairKIM::~PairKIM()
|
|
{
|
|
if (elements)
|
|
for (int i = 0; i < nelements; i++) delete [] elements[i];
|
|
delete [] elements;
|
|
|
|
delete [] modelname;
|
|
delete [] testname;
|
|
|
|
memory->destroy(kimtype);
|
|
memory->destroy(fcopy);
|
|
memory->destroy(onebuf);
|
|
|
|
if (allocated) {
|
|
memory->destroy(setflag);
|
|
memory->destroy(cutsq);
|
|
delete [] map;
|
|
}
|
|
|
|
memory->destroy(Rij);
|
|
|
|
kim_free();
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void PairKIM::compute(int eflag , int vflag)
|
|
{
|
|
int kimerr;
|
|
|
|
if (eflag || vflag) ev_setup(eflag,vflag);
|
|
else evflag = eflag_global = eflag_atom = vflag_global = vflag_atom = 0;
|
|
|
|
// grow kimtype array if necessary
|
|
// needs to be atom->nmax in length
|
|
|
|
if (atom->nmax > maxall) {
|
|
memory->destroy(kimtype);
|
|
memory->destroy(fcopy);
|
|
maxall = atom->nmax;
|
|
memory->create(kimtype,maxall,"pair:kimtype");
|
|
memory->create(fcopy,maxall,3,"pair:fcopy");
|
|
}
|
|
|
|
// kimtype = KIM atom type for each LAMMPS atom
|
|
// set ielement to valid 0 if map[] stores an un-used -1
|
|
|
|
int *type = atom->type;
|
|
int nall = atom->nlocal + atom->nghost;
|
|
int ielement;
|
|
|
|
for (int i = 0; i < nall; i++) {
|
|
ielement = map[type[i]];
|
|
ielement = MAX(ielement,0);
|
|
kimtype[i] = atypeMapKIM[2*ielement+1];
|
|
}
|
|
|
|
// pass current atom pointers to KIM
|
|
|
|
set_volatiles();
|
|
|
|
// set callback for virial tallying if necessary
|
|
|
|
int process_dEdr_flag = 0;
|
|
if (process_dEdr_ind >= 0 && (vflag_atom || vflag_global))
|
|
process_dEdr_flag = 1;
|
|
|
|
pkim->setm_compute_by_index(&kimerr,12, particleEnergy_ind,
|
|
eflag_atom,1,
|
|
particleVirial_ind,vflag_atom,1,
|
|
virialGlobal_ind,vflag_global,1,
|
|
process_dEdr_ind,process_dEdr_flag,1);
|
|
kim_error(__LINE__,"setm_compute_by_index",kimerr);
|
|
|
|
// KIM initialization
|
|
|
|
init2zero(pkim,&kimerr);
|
|
kim_error(__LINE__,"PairKIM::init2zero(..)",kimerr);
|
|
|
|
// compute energy, forces, virial via KIM model
|
|
|
|
pkim->model_compute(&kimerr);
|
|
kim_error(__LINE__,"PairKIM::pkim->model_compute() error",kimerr);
|
|
|
|
// reverse comm for ghost atoms
|
|
// required even when newton flag is off
|
|
|
|
comm->reverse_comm_pair(this);
|
|
|
|
// sum fcopy to f if running in hybrid mode
|
|
|
|
if (hybrid) {
|
|
double **f = atom->f;
|
|
int nlocal = atom->nlocal;
|
|
for (int i = 0; i < nlocal; i++) {
|
|
f[i][0] += fcopy[i][0];
|
|
f[i][1] += fcopy[i][1];
|
|
f[i][2] += fcopy[i][2];
|
|
}
|
|
}
|
|
|
|
// flip sign of virial
|
|
|
|
if (vflag_global && !pkim->virial_need2add)
|
|
for (int i = 0; i < 6; i++) virial[i] = -1.0*virial[i];
|
|
if (vflag_atom && !pkim->particleVirial_need2add)
|
|
for (int i = 0; i < atom->nlocal; i++)
|
|
for (int j = 0; j < 6; j++) vatom[i][j] = -1.0*vatom[i][j];
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
allocate all arrays
|
|
------------------------------------------------------------------------- */
|
|
|
|
void PairKIM::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 PairKIM::settings(int narg, char **arg)
|
|
{
|
|
if (narg != 1) error->all(FLERR,"Illegal pair_style command");
|
|
|
|
delete [] modelname;
|
|
int n = strlen(arg[0]) + 1;
|
|
modelname = new char[n];
|
|
strcpy(modelname,arg[0]);
|
|
|
|
delete [] testname;
|
|
const char *test = "test_LAMMPS";
|
|
n = strlen(test) + 1;
|
|
testname = new char[n];
|
|
strcpy(testname,test);
|
|
|
|
ev_setup(3,6);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
set coeffs for one or more type pairs
|
|
------------------------------------------------------------------------- */
|
|
|
|
void PairKIM::coeff(int narg, char **arg)
|
|
{
|
|
int i,j,n;
|
|
|
|
if (!allocated) allocate();
|
|
|
|
if (narg != 2 + 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 KIM elements
|
|
// 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 = 2; i < narg; i++) {
|
|
if (strcmp(arg[i],"NULL") == 0) {
|
|
map[i-1] = -1;
|
|
continue;
|
|
}
|
|
for (j = 0; j < nelements; j++)
|
|
if (strcmp(arg[i],elements[j]) == 0) break;
|
|
map[i-1] = j;
|
|
if (j == nelements) {
|
|
n = strlen(arg[i]) + 1;
|
|
elements[j] = new char[n];
|
|
strcpy(elements[j],arg[i]);
|
|
nelements++;
|
|
}
|
|
}
|
|
|
|
// KIM initialization
|
|
|
|
kim_init();
|
|
if (!pkim->model_init())
|
|
kim_error(__LINE__,"KIM API:model_init() failed",-1);
|
|
|
|
// 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 PairKIM::init_style()
|
|
{
|
|
if (force->newton_pair != 0)
|
|
error->all(FLERR,"Pair style kim requires newton pair off");
|
|
|
|
// setup onebuf for neighbors of one atom if needed
|
|
|
|
molecular = atom->molecular;
|
|
if (molecular) {
|
|
memory->destroy(onebuf);
|
|
memory->create(onebuf,neighbor->oneatom,"pair:onebuf");
|
|
}
|
|
|
|
// hybrid = 1 if running with pair hybrid
|
|
|
|
hybrid = 0;
|
|
if (force->pair_match("hybrid",0)) hybrid = 1;
|
|
|
|
// request half or full neighbor list depending on KIM model requirement
|
|
|
|
int irequest = neighbor->request(this);
|
|
if (pkim->requiresFullNeighbors()) {
|
|
neighbor->requests[irequest]->half = 0;
|
|
neighbor->requests[irequest]->full = 1;
|
|
}
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
init for one type pair i,j and corresponding j,i
|
|
------------------------------------------------------------------------- */
|
|
|
|
double PairKIM::init_one(int i, int j)
|
|
{
|
|
if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
|
|
|
|
return cut_global;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
int PairKIM::pack_reverse_comm(int n, int first, double *buf)
|
|
{
|
|
int i,m,last;
|
|
double *fp;
|
|
if (hybrid) fp = &(fcopy[0][0]);
|
|
else fp = &(atom->f[0][0]);
|
|
double *va=&(vatom[0][0]);
|
|
|
|
m = 0;
|
|
last = first + n;
|
|
if (vflag_atom == 1) {
|
|
for (i = first; i < last; i++) {
|
|
buf[m++] = fp[3*i+0];
|
|
buf[m++] = fp[3*i+1];
|
|
buf[m++] = fp[3*i+2];
|
|
|
|
buf[m++] = va[6*i+0];
|
|
buf[m++] = va[6*i+1];
|
|
buf[m++] = va[6*i+2];
|
|
buf[m++] = va[6*i+3];
|
|
buf[m++] = va[6*i+4];
|
|
buf[m++] = va[6*i+5];
|
|
}
|
|
return 9;
|
|
|
|
} else {
|
|
for (i = first; i < last; i++){
|
|
buf[m++] = fp[3*i+0];
|
|
buf[m++] = fp[3*i+1];
|
|
buf[m++] = fp[3*i+2];
|
|
}
|
|
return 3;
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void PairKIM::unpack_reverse_comm(int n, int *list, double *buf)
|
|
{
|
|
int i,j,m;
|
|
double *fp;
|
|
if (hybrid) fp = &(fcopy[0][0]);
|
|
else fp = &(atom->f[0][0]);
|
|
|
|
double *va=&(vatom[0][0]);
|
|
m = 0;
|
|
if (vflag_atom == 1) {
|
|
for (i = 0; i < n; i++) {
|
|
j = list[i];
|
|
fp[3*j+0]+= buf[m++];
|
|
fp[3*j+1]+= buf[m++];
|
|
fp[3*j+2]+= buf[m++];
|
|
|
|
va[j*6+0]+=buf[m++];
|
|
va[j*6+1]+=buf[m++];
|
|
va[j*6+2]+=buf[m++];
|
|
va[j*6+3]+=buf[m++];
|
|
va[j*6+4]+=buf[m++];
|
|
va[j*6+5]+=buf[m++];
|
|
}
|
|
} else {
|
|
for (i = 0; i < n; i++) {
|
|
j = list[i];
|
|
fp[3*j+0]+= buf[m++];
|
|
fp[3*j+1]+= buf[m++];
|
|
fp[3*j+2]+= buf[m++];
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
memory usage of local atom-based arrays
|
|
------------------------------------------------------------------------- */
|
|
|
|
double PairKIM::memory_usage()
|
|
{
|
|
double bytes = maxall * sizeof(int);
|
|
return bytes;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
KIM-specific interface
|
|
------------------------------------------------------------------------- */
|
|
|
|
void PairKIM::kim_error(int ln, const char* msg, int errcode)
|
|
{
|
|
if (errcode == 1) return;
|
|
KIM_API_model::report_error(ln,(char *) __FILE__,
|
|
(char *) msg,errcode);
|
|
error->all(__FILE__,ln,"Internal KIM error");
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
int PairKIM::get_neigh(void **kimmdl,int *mode,int *request,
|
|
int *atom, int *numnei, int **nei1atom, double **pRij)
|
|
{
|
|
double * x;
|
|
|
|
KIM_API_model *pkim = (KIM_API_model *) *kimmdl;
|
|
|
|
// get neighObj from KIM API obj
|
|
// this block will be changed in case of hybride/composite KIM potential
|
|
|
|
int kimerr;
|
|
PairKIM *self = (PairKIM *) pkim->get_test_buffer(&kimerr);
|
|
|
|
*pRij = &(self->Rij[0]);
|
|
|
|
NeighList * neiobj = (NeighList * ) (*pkim)[self->neighObject_ind].data;
|
|
|
|
int * pnAtoms = (int *)(*pkim)[self->numberOfParticles_ind].data;
|
|
if(pkim->support_Rij) x = (double *)(*pkim)[self->coordinates_ind].data;
|
|
int nAtoms = *pnAtoms;
|
|
int j,jj,inum,*ilist,*numneigh,**firstneigh;
|
|
inum = neiobj->inum; //# of I atoms neighbors are stored for
|
|
ilist =neiobj->ilist ; //local indices of I atoms
|
|
numneigh =neiobj-> numneigh ; // # of J neighbors for each I atom
|
|
firstneigh =neiobj->firstneigh ;// ptr to 1st J int value of each I atom
|
|
|
|
if (*mode==0){ //iterator mode
|
|
if (*request== 0){ //restart iterator
|
|
self->pointsto =0;
|
|
*numnei=0;
|
|
return KIM_STATUS_NEIGH_ITER_INIT_OK; //succsesful restart
|
|
} else if (*request==1) { //increment iterator
|
|
if (self->pointsto > inum || inum <0){
|
|
self->error->one(FLERR,"KIM neighbor iterator exceeded range");
|
|
} else if (self->pointsto == inum) {
|
|
self->pointsto = 0;
|
|
*numnei = 0;
|
|
return KIM_STATUS_NEIGH_ITER_PAST_END; //reached end by iterator
|
|
} else {
|
|
*atom = ilist[self->pointsto];
|
|
*numnei = numneigh[*atom];
|
|
|
|
// strip off neighbor mask for molecular systems
|
|
|
|
if (self->molecular) {
|
|
int n = *numnei;
|
|
int *ptr = firstneigh[*atom];
|
|
int *onebuf = self->onebuf;
|
|
for (int i = 0; i < n; i++)
|
|
onebuf[i] = *(ptr++) & NEIGHMASK;
|
|
*nei1atom = onebuf;
|
|
} else *nei1atom = firstneigh[*atom];
|
|
|
|
self->pointsto++;
|
|
if (*numnei > KIM_API_MAX_NEIGHBORS)
|
|
return KIM_STATUS_NEIGH_TOO_MANY_NEIGHBORS;
|
|
if (pkim->support_Rij) {
|
|
for (jj=0; jj < *numnei; jj++) {
|
|
int i = *atom;
|
|
j = (*nei1atom)[jj];
|
|
self->Rij[jj*3 +0] = -x[i*3+0] + x[j*3+0];
|
|
self->Rij[jj*3 +1] = -x[i*3+1] + x[j*3+1];
|
|
self->Rij[jj*3 +2] = -x[i*3+2] + x[j*3+2];
|
|
}
|
|
}
|
|
return KIM_STATUS_OK;//successful increment
|
|
}
|
|
}
|
|
}else if (*mode ==1){//locator mode
|
|
//...
|
|
if (*request >= nAtoms || inum <0) return -1;
|
|
if (*request >= inum) {
|
|
*atom=*request;
|
|
*numnei=0;
|
|
return KIM_STATUS_OK;//successfull but no neighbors in the list
|
|
}
|
|
*atom = *request;
|
|
*numnei = numneigh[*atom];
|
|
|
|
// strip off neighbor mask for molecular systems
|
|
|
|
if (self->molecular) {
|
|
int n = *numnei;
|
|
int *ptr = firstneigh[*atom];
|
|
int *onebuf = self->onebuf;
|
|
for (int i = 0; i < n; i++)
|
|
onebuf[i] = *(ptr++) & NEIGHMASK;
|
|
*nei1atom = onebuf;
|
|
} else *nei1atom = firstneigh[*atom];
|
|
|
|
if (*numnei > KIM_API_MAX_NEIGHBORS)
|
|
return KIM_STATUS_NEIGH_TOO_MANY_NEIGHBORS;
|
|
if (pkim->support_Rij){
|
|
for(int jj=0; jj < *numnei; jj++){
|
|
int i = *atom;
|
|
int j = (*nei1atom)[jj];
|
|
self->Rij[jj*3 +0]=-x[i*3+0] + x[j*3+0];
|
|
self->Rij[jj*3 +1]=-x[i*3+1] + x[j*3+1];
|
|
self->Rij[jj*3 +2]=-x[i*3+2] + x[j*3+2];
|
|
}
|
|
}
|
|
return KIM_STATUS_OK;//successful end
|
|
} else return KIM_STATUS_NEIGH_INVALID_MODE;//invalid mode
|
|
|
|
return -16;//should not get here: unspecified error
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void PairKIM::kim_free()
|
|
{
|
|
int kimerr;
|
|
pkim->model_destroy(&kimerr);
|
|
pkim->free();
|
|
delete pkim;
|
|
delete [] atypeMapKIM;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void PairKIM::kim_init()
|
|
{
|
|
support_atypes = true;
|
|
strcpy(modelfile,"");
|
|
strcpy(testfile,"");
|
|
char * kim_dir =getenv("KIM_DIR");
|
|
char * kim_models_dir = getenv("KIM_MODELS_DIR");
|
|
char * current_path = getenv("PWD");
|
|
if (kim_dir == NULL)
|
|
error->all(FLERR,"KIM_DIR environement variable is unset");
|
|
if (current_path == NULL)
|
|
error->all(FLERR,"PWD environement variable is unset");
|
|
|
|
if (kim_models_dir == NULL) {
|
|
strcat(modelfile,kim_dir);strcat(modelfile,"MODELs/");
|
|
strcat(modelfile,modelname); strcat(modelfile,"/");
|
|
strcat(modelfile,modelname); strcat(modelfile,".kim");
|
|
} else {
|
|
strcat(modelfile,kim_models_dir);strcat(modelfile,modelname);
|
|
strcat(modelfile,"/");
|
|
strcat(modelfile,modelname);
|
|
strcat(modelfile,".kim");
|
|
}
|
|
strcat(testfile,current_path); strcat(testfile,"/");
|
|
strcat(testfile,testname);strcat(testfile,".kim");
|
|
|
|
// now testfile and modelfile are set
|
|
|
|
int kimerr;
|
|
|
|
if (!(strcmp(update->unit_style,"metal")==0))
|
|
this->kim_error(__LINE__,
|
|
"LAMMPS unit_style must be metal to "
|
|
"work with KIM models",-12);
|
|
|
|
// create temporary kim file
|
|
|
|
test_descriptor_string = new char[80*60];
|
|
for (int i=50;i<80*60;i++) test_descriptor_string[i]='\0';
|
|
|
|
// 1. write atomic header and atomic type spec
|
|
|
|
int i_s;
|
|
sprintf(test_descriptor_string,
|
|
"# This file is automatically generated from LAMMPS "
|
|
"pair_style PairKIM command\n");
|
|
i_s=strlen(test_descriptor_string);
|
|
|
|
sprintf(&test_descriptor_string[i_s],"TEST_NAME :=%s\n" ,testname);
|
|
i_s=strlen(test_descriptor_string);
|
|
sprintf(&test_descriptor_string[i_s],"#Unit_Handling := flexible\n\n");
|
|
i_s=strlen(test_descriptor_string);
|
|
sprintf(&test_descriptor_string[i_s],"Unit_length := A\n\n");
|
|
i_s=strlen(test_descriptor_string);
|
|
sprintf(&test_descriptor_string[i_s],"Unit_energy := eV \n\n");
|
|
i_s=strlen(test_descriptor_string);
|
|
sprintf(&test_descriptor_string[i_s],"Unit_charge := e\n\n");
|
|
i_s=strlen(test_descriptor_string);
|
|
sprintf(&test_descriptor_string[i_s],"Unit_temperature := K\n\n");
|
|
i_s=strlen(test_descriptor_string);
|
|
sprintf(&test_descriptor_string[i_s],"Unit_time := fs\n\n");
|
|
i_s=strlen(test_descriptor_string);
|
|
sprintf(&test_descriptor_string[i_s],"SUPPORTED_ATOM/PARTICLES_TYPES:\n");
|
|
i_s=strlen(test_descriptor_string);
|
|
sprintf(&test_descriptor_string[i_s],
|
|
"# Simbol/name Type code\n");
|
|
int code=1;
|
|
for (int i=0; i < nelements; i++){
|
|
i_s=strlen(test_descriptor_string);
|
|
sprintf(&test_descriptor_string[i_s],"%s\t\t\tspec\t\t%d\n",
|
|
elements[i],code++);
|
|
}
|
|
i_s=strlen(test_descriptor_string);
|
|
sprintf(&test_descriptor_string[i_s],"\n");
|
|
|
|
// 2. conventions
|
|
|
|
i_s=strlen(test_descriptor_string);
|
|
sprintf(&test_descriptor_string[i_s], \
|
|
"CONVENTIONS:\n# Name Type\n\n");
|
|
i_s=strlen(test_descriptor_string);
|
|
sprintf(&test_descriptor_string[i_s], "ZeroBasedLists flag\n\n");
|
|
i_s=strlen(test_descriptor_string);
|
|
|
|
// can use iterator or locator neighbor mode, unless hybrid
|
|
|
|
int iterator_only = 0;
|
|
if (force->pair_match("hybrid",0)) iterator_only = 1;
|
|
if (iterator_only)
|
|
sprintf(&test_descriptor_string[i_s],"Neigh_IterAccess flag\n\n");
|
|
else
|
|
sprintf(&test_descriptor_string[i_s],"Neigh_BothAccess flag\n\n");
|
|
|
|
i_s=strlen(test_descriptor_string);
|
|
sprintf(&test_descriptor_string[i_s],"NEIGH_PURE_H flag\n\n");
|
|
i_s=strlen(test_descriptor_string);
|
|
sprintf(&test_descriptor_string[i_s],"NEIGH_PURE_F flag\n\n");
|
|
i_s=strlen(test_descriptor_string);
|
|
sprintf(&test_descriptor_string[i_s],"NEIGH_RVEC_F flag\n\n");
|
|
i_s=strlen(test_descriptor_string);
|
|
sprintf(&test_descriptor_string[i_s],"CLUSTER flag\n\n");
|
|
|
|
// 3. input-output
|
|
|
|
i_s=strlen(test_descriptor_string);
|
|
sprintf(&test_descriptor_string[i_s],"MODEL_INPUT:\n");
|
|
i_s=strlen(test_descriptor_string);
|
|
sprintf(&test_descriptor_string[i_s],
|
|
"# Name Type Unit Shape\n\n");
|
|
i_s=strlen(test_descriptor_string);
|
|
sprintf(&test_descriptor_string[i_s],
|
|
"numberOfParticles integer none []\n\n");
|
|
i_s=strlen(test_descriptor_string);
|
|
sprintf(&test_descriptor_string[i_s],
|
|
"numberContributingParticles integer none []\n\n");
|
|
|
|
if (support_atypes){
|
|
i_s=strlen(test_descriptor_string);
|
|
sprintf(&test_descriptor_string[i_s],
|
|
"numberParticleTypes integer none []\n\n");
|
|
i_s=strlen(test_descriptor_string);
|
|
sprintf(&test_descriptor_string[i_s],
|
|
"particleTypes integer none [numberOfParticles]\n\n");
|
|
}
|
|
i_s=strlen(test_descriptor_string);
|
|
sprintf(&test_descriptor_string[i_s],
|
|
"coordinates real*8 length "
|
|
"[numberOfParticles,3]\n\n");
|
|
i_s=strlen(test_descriptor_string);
|
|
sprintf(&test_descriptor_string[i_s],
|
|
"neighObject pointer none []\n\n");
|
|
i_s=strlen(test_descriptor_string);
|
|
sprintf(&test_descriptor_string[i_s],
|
|
"get_neigh method none []\n\n");
|
|
i_s=strlen(test_descriptor_string);
|
|
sprintf(&test_descriptor_string[i_s], "MODEL_OUPUT:\n");
|
|
i_s=strlen(test_descriptor_string);
|
|
sprintf(&test_descriptor_string[i_s],
|
|
"# Name Type Unit Shape\n\n");
|
|
i_s=strlen(test_descriptor_string);
|
|
sprintf(&test_descriptor_string[i_s],
|
|
"compute method none []\n\n");
|
|
i_s=strlen(test_descriptor_string);
|
|
sprintf(&test_descriptor_string[i_s],
|
|
"destroy method none []\n\n");
|
|
i_s=strlen(test_descriptor_string);
|
|
sprintf(&test_descriptor_string[i_s],
|
|
"cutoff real*8 length []\n\n");
|
|
i_s=strlen(test_descriptor_string);
|
|
sprintf(&test_descriptor_string[i_s],
|
|
"energy real*8 energy []\n\n");
|
|
i_s=strlen(test_descriptor_string);
|
|
sprintf(&test_descriptor_string[i_s],
|
|
"forces real*8 force "
|
|
"[numberOfParticles,3]\n\n");
|
|
i_s=strlen(test_descriptor_string);
|
|
sprintf(&test_descriptor_string[i_s],
|
|
"particleEnergy real*8 energy "
|
|
"[numberOfParticles]\n\n");
|
|
//virial and virial per atom will be added here
|
|
// i_s=strlen(test_descriptor_string);
|
|
sprintf(&test_descriptor_string[i_s],
|
|
"virial real*8 energy [6] \n\n\0");
|
|
i_s=strlen(test_descriptor_string);
|
|
sprintf(&test_descriptor_string[i_s],
|
|
"process_dEdr method none [] \n\n");
|
|
i_s=strlen(test_descriptor_string);
|
|
sprintf(&test_descriptor_string[i_s],
|
|
"particleVirial real*8 energy "
|
|
"[numberOfParticles,6] \n\n\0");
|
|
|
|
// kim file created now init and maptypes
|
|
|
|
pkim = new KIM_API_model();
|
|
if (!pkim->init_str_testname(test_descriptor_string,modelname))
|
|
error->all(FLERR,"KIM initialization failed");
|
|
|
|
delete [] test_descriptor_string;
|
|
|
|
// get correct index of each variable in kim_api object
|
|
|
|
pkim->getm_index(&kimerr,33,
|
|
"coordinates", &coordinates_ind,1,
|
|
"cutoff", &cutoff_ind,1,
|
|
"particleEnergy",&particleEnergy_ind,1,
|
|
"energy", &energy_ind,1,
|
|
"forces", &forces_ind,1,
|
|
"neighObject", &neighObject_ind,1,
|
|
"numberOfParticles",&numberOfParticles_ind,1,
|
|
"get_neigh", &get_neigh_ind,1,
|
|
"particleVirial", &particleVirial_ind,1,
|
|
"virial", &virialGlobal_ind,1,
|
|
"process_dEdr",&process_dEdr_ind,1 );
|
|
this->kim_error(__LINE__,"getm_index",kimerr);
|
|
|
|
if(support_atypes){
|
|
numberParticleTypes_ind = pkim->get_index((char *) "numberParticleTypes",&kimerr);
|
|
this->kim_error(__LINE__,"numberParticleTypes",kimerr);
|
|
particleTypes_ind = pkim->get_index((char *) "particleTypes",&kimerr);
|
|
this->kim_error(__LINE__,"particleTypes",kimerr);
|
|
}
|
|
|
|
set_statics();
|
|
|
|
// setup mapping between LAMMPS and KIM atom types
|
|
|
|
atypeMapKIM = new int[2*nelements];
|
|
for(int i = 0; i < nelements; i++){
|
|
atypeMapKIM[i*2 + 0] = i;
|
|
int kimerr;
|
|
atypeMapKIM[i*2 + 1] = pkim->get_partcl_type_code(elements[i],&kimerr);
|
|
this->kim_error(__LINE__,"create_atypeMapKIM: symbol not found ",kimerr);
|
|
}
|
|
|
|
// check if Rij needed for get_neigh
|
|
|
|
char * NBC_method =(char *) pkim->get_NBC_method(&kimerr);
|
|
this->kim_error(__LINE__,"NBC method not set",kimerr);
|
|
support_Rij=false;
|
|
if (strcmp(NBC_method,"NEIGH_RVEC_F")==0) support_Rij=true;
|
|
free((void*)NBC_method);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void PairKIM::set_statics()
|
|
{
|
|
if(support_atypes)
|
|
pkim->set_data_by_index(numberParticleTypes_ind,1,(void *) &(atom->ntypes )) ;
|
|
if ( process_dEdr_ind >= 0 )
|
|
pkim->set_data((char *) "process_dEdr",1, (void*) &process_dEdr);
|
|
localnall = (int) (atom->nghost + atom->nlocal);
|
|
int kimerr;
|
|
pkim->setm_data_by_index(&kimerr,20,
|
|
energy_ind,1, (void *)&(this->eng_vdwl),1,
|
|
cutoff_ind,1, (void *)&(this->cut_global),1,
|
|
get_neigh_ind,1,(void *) &get_neigh,1,
|
|
numberOfParticles_ind,1, (void *) &localnall,1,
|
|
virialGlobal_ind,1,(void *)&(virial[0]),1);
|
|
this->kim_error(__LINE__,"setm_data_by_index",kimerr);
|
|
|
|
pkim->set_data((char *) "numberContributingParticles",1,(void *)&(atom->nlocal));
|
|
|
|
pkim->set_test_buffer( (void *)this, &kimerr);
|
|
|
|
this->kim_error(__LINE__,"set_test_buffer",kimerr);
|
|
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void PairKIM::set_volatiles()
|
|
{
|
|
localnall = (int) (atom->nghost + atom->nlocal);
|
|
bigint nall = (bigint) localnall;
|
|
|
|
pkim->set_data_by_index(coordinates_ind,nall*3,(void *) &(atom->x[0][0]) );
|
|
if (hybrid)
|
|
pkim->set_data_by_index(forces_ind,nall*3,(void *) &(fcopy[0][0]) ) ;
|
|
else
|
|
pkim->set_data_by_index(forces_ind,nall*3,(void *) &(atom->f[0][0]) ) ;
|
|
pkim->set_data_by_index(particleEnergy_ind,nall, (void *)this->eatom) ;
|
|
pkim->set_data_by_index(neighObject_ind,1, (void *)this->list) ;
|
|
|
|
if (support_atypes)
|
|
pkim->set_data_by_index(particleTypes_ind,nall, (void *) kimtype) ;
|
|
|
|
if(vflag_atom != 1) {
|
|
(*pkim)[particleVirial_ind].flag->calculate = 0;
|
|
} else {
|
|
(*pkim)[particleVirial_ind].flag->calculate = 1;
|
|
pkim->set_data_by_index(particleVirial_ind,(intptr_t)nall,
|
|
(void *)&vatom[0][0]) ;
|
|
}
|
|
if (vflag_global != 1) {
|
|
(*pkim)[virialGlobal_ind].flag->calculate = 0;
|
|
} else {
|
|
(*pkim)[virialGlobal_ind].flag->calculate = 1;
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void PairKIM::init2zero(KIM_API_model *pkim, int *kimerr)
|
|
{
|
|
// fetch pointer to this = PairKIM, so that callbacks can access class members
|
|
// if error, have no ptr to PairKIM, so let KIM generate error message
|
|
|
|
PairKIM *self = (PairKIM *) pkim->get_test_buffer(kimerr);
|
|
if (*kimerr < 1)
|
|
KIM_API_model::report_error(__LINE__,(char *) __FILE__,
|
|
(char *) "Self ptr to PairKIM is invalid",
|
|
*kimerr);
|
|
|
|
int p1_ind=-1;bool process_d1=false;
|
|
self->process_dE.virialGlobal_flag = 0;
|
|
self->process_dE.particleVirial_flag =0;
|
|
int ierGlobal,ierPerAtom;
|
|
self->process_dE.virialGlobal = (double *) pkim->get_data((char *) "virial",&ierGlobal);
|
|
self->process_dE.particleVirial = (double *) pkim->get_data((char *) "particleVirial",
|
|
&ierPerAtom);
|
|
self->process_dE.numberOfParticles = (int *) pkim->get_data((char *) "numberOfParticles",kimerr);
|
|
//halfNeighbors = !pkim->requiresFullNeighbors();
|
|
p1_ind = pkim->get_index((char *) "process_dEdr");
|
|
if (*kimerr !=KIM_STATUS_OK) return;
|
|
if (ierGlobal == KIM_STATUS_OK && self->process_dE.virialGlobal != NULL) {
|
|
self->process_dE.virialGlobal_flag = pkim->get_compute((char *) "virial");
|
|
if (self->process_dE.virialGlobal_flag==1 && pkim->virial_need2add){
|
|
self->process_dE.virialGlobal[0] =0.0; self->process_dE.virialGlobal[1] =0.0;
|
|
self->process_dE.virialGlobal[2] =0.0; self->process_dE.virialGlobal[3] =0.0;
|
|
self->process_dE.virialGlobal[4] =0.0; self->process_dE.virialGlobal[5] =0.0;
|
|
process_d1=true;
|
|
}
|
|
}
|
|
|
|
if (ierPerAtom == KIM_STATUS_OK && self->process_dE.particleVirial != NULL) {
|
|
self->process_dE.particleVirial_flag = pkim->get_compute((char *) "particleVirial");
|
|
if (self->process_dE.particleVirial_flag==1 && pkim->particleVirial_need2add) {
|
|
for (int i =0;i<(*self->process_dE.numberOfParticles)*6 ;i++) self->process_dE.particleVirial[i]=0.0;
|
|
process_d1=true;
|
|
}
|
|
}
|
|
if (p1_ind >= 0) {
|
|
if (process_d1) pkim->set_compute((char *) "process_dEdr",1,kimerr);
|
|
else pkim->set_compute((char *) "process_dEdr",0,kimerr);
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void PairKIM::process_dEdr(KIM_API_model **ppkim,
|
|
double *de,double *r,double ** pdx,
|
|
int *i,int *j,int *ier)
|
|
{
|
|
KIM_API_model *pkim = *ppkim;
|
|
PairKIM *self = (PairKIM *) pkim->get_test_buffer(ier);
|
|
|
|
*ier=KIM_STATUS_FAIL;
|
|
double vir[6],v;
|
|
double *dx = *pdx;
|
|
//v=(*de)/((*r)*(*r))/3.0;
|
|
//v=(*de)/((*r)*(*r));
|
|
|
|
v=-(*de)/(*r);
|
|
|
|
if (self->process_dE.virialGlobal_flag ==1 && pkim->virial_need2add) {
|
|
vir[0] = v * dx[0] * dx[0];
|
|
vir[1] = v * dx[1] * dx[1];
|
|
vir[2] = v * dx[2] * dx[2];
|
|
vir[3] = v * dx[1] * dx[2];
|
|
vir[4] = v * dx[0] * dx[2];
|
|
vir[5] = v * dx[0] * dx[1];
|
|
self->process_dE.virialGlobal[0] += vir[0];
|
|
self->process_dE.virialGlobal[1] += vir[1];
|
|
self->process_dE.virialGlobal[2] += vir[2];
|
|
self->process_dE.virialGlobal[3] += vir[3];
|
|
self->process_dE.virialGlobal[4] += vir[4];
|
|
self->process_dE.virialGlobal[5] += vir[5];
|
|
}
|
|
|
|
if (self->process_dE.particleVirial_flag==1 && pkim->particleVirial_need2add ){
|
|
vir[0] =0.5 * v * dx[0] * dx[0];
|
|
vir[1] =0.5 * v * dx[1] * dx[1];
|
|
vir[2] =0.5 * v * dx[2] * dx[2];
|
|
vir[3] =0.5 * v * dx[1] * dx[2];
|
|
vir[4] =0.5 * v * dx[0] * dx[2];
|
|
vir[5] =0.5 * v * dx[0] * dx[1];
|
|
self->process_dE.particleVirial[(*i)*6 + 0] += vir[0];
|
|
self->process_dE.particleVirial[(*i)*6 + 1] += vir[1];
|
|
self->process_dE.particleVirial[(*i)*6 + 2] += vir[2];
|
|
self->process_dE.particleVirial[(*i)*6 + 3] += vir[3];
|
|
self->process_dE.particleVirial[(*i)*6 + 4] += vir[4];
|
|
self->process_dE.particleVirial[(*i)*6 + 5] += vir[5];
|
|
|
|
self->process_dE.particleVirial[(*j)*6 + 0] += vir[0];
|
|
self->process_dE.particleVirial[(*j)*6 + 1] += vir[1];
|
|
self->process_dE.particleVirial[(*j)*6 + 2] += vir[2];
|
|
self->process_dE.particleVirial[(*j)*6 + 3] += vir[3];
|
|
self->process_dE.particleVirial[(*j)*6 + 4] += vir[4];
|
|
self->process_dE.particleVirial[(*j)*6 + 5] += vir[5];
|
|
}
|
|
|
|
*ier = KIM_STATUS_OK;
|
|
}
|