Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F90780145
pair_mgpt.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
Mon, Nov 4, 16:46
Size
80 KB
Mime Type
text/x-c
Expires
Wed, Nov 6, 16:46 (2 d)
Engine
blob
Format
Raw Data
Handle
22133531
Attached To
rLAMMPS lammps
pair_mgpt.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: Tomas Oppelstrup, LLNL (oppelstrup2@llnl.gov)
and John Moriarty, LLNL (moriarty2@llnl.gov)
Fast MGPT algorithm developed by Tomas Oppelstrup (2015) based on the
matrix MGPT v4.4 FORTRAN routine of John Moriarty (2006) as converted
to C++ for LAMMPS application by Jamie Marian and Alexander Stukowski
(2011). See LLNL copyright notice at bottom of this file.
------------------------------------------------------------------------- */
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include "pair_mgpt.h"
#include "atom.h"
#include "force.h"
#include "comm.h"
#include "memory.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
//#define TIMING_ON
#ifdef TIMING_ON
#include <sys/time.h>
#include <time.h>
//#include "rdtsc.h"
#ifdef __bgq__
#include <hwi/include/bqc/A2_inlines.h>
#endif
static double gettime(int x = 0) {
if(1) {
/*
struct timeval tv;
gettimeofday(&tv,NULL);
return tv.tv_sec + 1e-6 * tv.tv_usec;
*/
/*
const double x = 1.0 / CLOCKS_PER_SEC;
return clock() * x;
*/
//const double invfreq = 1.0 / 2394.108e6;
/*
const double invfreq = 1.0 / 700e6;
unsigned long long int x = rdtsc();
return x*invfreq;
*/
const double invfreq = 1.0 / 1.6e9;
unsigned long long int x = GetTimeBase();
return x*invfreq;
} else
return 0.0;
}
#else
static double gettime(int x = 0) { return 0.0; }
#endif
/* ---------------------------------------------------------------------- */
PairMGPT::PairMGPT(LAMMPS *lmp) : Pair(lmp)
{
single_enable = 0;
one_coeff = 1;
ghostneigh = 1;
}
PairMGPT::~PairMGPT()
{
if(allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cutghost);
}
}
/* ---------------------------------------------------------------------- */
static double t_make_b2 = 0.0,n_make_b2 = 0.0;
template<typename intype,typename outtype,int ni,int nj> void fmatconv(intype *array) {
outtype *cast = (outtype *) array;
for(int i = 0; i<ni; i++)
for(int j = 0; j<nj; j++)
cast[i*nj+j] = array[i*nj+j];
}
void PairMGPT::make_bond(const double xx[][3],int i,int j,bond_data *bptr) {
double rrij[3],rij;
int p;
double t0,t1;
/* Check that alignment requirements for SIMD code are fullfilled */
assert( (((unsigned long long int) (bptr->H.m )) & 31) == 0 );
assert( (((unsigned long long int) (bptr->Hx.m)) & 31) == 0 );
assert( (((unsigned long long int) (bptr->Hy.m)) & 31) == 0 );
assert( (((unsigned long long int) (bptr->Hz.m)) & 31) == 0 );
rij = 0.0;
for(p = 0; p<3; p++) {
rrij[p] = xx[i][p] - xx[j][p];
rij = rij + rrij[p]*rrij[p];
}
/* Zero all matrix elements */
for(i = 0; i<8; i++)
for(j = 0; j<8; j++) {
bptr->H.m[i][j] = 0.0;
bptr->Hx.m[i][j] = 0.0;
bptr->Hy.m[i][j] = 0.0;
bptr->Hz.m[i][j] = 0.0;
bptr->Hz.m[j][i] = 0.0;
}
if(rij <= rcrit*rcrit) {
t0 = gettime();
if(lang == 3) {
hamltn_5_raw(rrij[0],rrij[1],rrij[2],
bptr->H.m ,bptr->Hx.m,
bptr->Hy.m,bptr->Hz.m,&bptr->fl_deriv_sum);
} else {
hamltn_7_raw(rrij[0],rrij[1],rrij[2],
bptr->H.m ,bptr->Hx.m,
bptr->Hy.m,bptr->Hz.m,&bptr->fl_deriv_sum);
}
t1 = gettime();
t_make_b2 += t1-t0;
n_make_b2++;
} else {
bptr->fl_deriv_sum = 0.0;
}
if(linalg.single) {
fmatconv<double,float,7,8>(&(bptr->H.m[1][0]));
fmatconv<double,float,7,8>(&(bptr->Hx.m[1][0]));
fmatconv<double,float,7,8>(&(bptr->Hy.m[1][0]));
fmatconv<double,float,7,8>(&(bptr->Hz.m[1][0]));
}
}
static double t_trace = 0.0,n_trace = 0.0;
/*
static inline double mtrace(int n,double A[8][8],double B[8][8]) {
double t0,t1;
double s;
t0 = gettime();
if(n == 5) s = mtrace_5(A,B);
else if(n == 7) s = mtrace_7(A,B);
else {
s = 0.0;
for(int i = 1; i<=n; i++)
for(int j = 1; j<=n; j++)
s = s + A[i][j]*B[i][j];
}
t1 = gettime();
t_trace += t1-t0;
n_trace++;
return s;
}
*/
void PairMGPT::make_triplet(bond_data *ij_bond,bond_data *ik_bond,
triplet_data *triptr) {
if(1) {
const trmul_fun tr_mul = linalg.tr_mul;
tr_mul(&(ij_bond->H.m[1][0]), &(ik_bond->H.m[1][0]) ,&(triptr->H1H2.m[1][0]) );
tr_mul(&(ij_bond->Hx.m[1][0]),&(ik_bond->H.m[1][0]) ,&(triptr->H1xH2.m[1][0]));
tr_mul(&(ij_bond->Hy.m[1][0]),&(ik_bond->H.m[1][0]) ,&(triptr->H1yH2.m[1][0]));
tr_mul(&(ij_bond->Hz.m[1][0]),&(ik_bond->H.m[1][0]) ,&(triptr->H1zH2.m[1][0]));
tr_mul(&(ij_bond->H.m[1][0]) ,&(ik_bond->Hx.m[1][0]),&(triptr->H1H2x.m[1][0]));
tr_mul(&(ij_bond->H.m[1][0]) ,&(ik_bond->Hy.m[1][0]),&(triptr->H1H2y.m[1][0]));
tr_mul(&(ij_bond->H.m[1][0]) ,&(ik_bond->Hz.m[1][0]),&(triptr->H1H2z.m[1][0]));
} else {
transprod(ij_bond->H, ik_bond->H ,triptr->H1H2 );
transprod(ij_bond->Hx,ik_bond->H ,triptr->H1xH2);
transprod(ij_bond->Hy,ik_bond->H ,triptr->H1yH2);
transprod(ij_bond->Hz,ik_bond->H ,triptr->H1zH2);
transprod(ij_bond->H ,ik_bond->Hx,triptr->H1H2x);
transprod(ij_bond->H ,ik_bond->Hy,triptr->H1H2y);
transprod(ij_bond->H ,ik_bond->Hz,triptr->H1H2z);
}
}
static double t_make_t = 0.0,t_make_b = 0.0,n_make = 0.0;
PairMGPT::triplet_data *PairMGPT::get_triplet(const double xx[][3],int i,int j,int k,
Hash<bond_data,Doublet> *bhash,
triplet_data *twork,
double *dvir_ij_p,double *dvir_ik_p) {
const int recompute = 0;
static bond_data bij_work,bik_work;
double t0,t1;
bond_data *bij = 0,*bik = 0;
triplet_data *tptr = 0;
t0 = gettime();
if(recompute == 0) {
bij = bhash->Lookup(Doublet(i,j));
bik = bhash->Lookup(Doublet(i,k));
}
if(bij == 0) {
if(recompute == 0)
bij = bhash->Insert(Doublet(i,j));
else
bij = &bij_work;
if(i < j)
make_bond(xx,i,j,bij);
else
make_bond(xx,j,i,bij);
}
if(bik == 0) {
if(recompute == 0)
bik = bhash->Insert(Doublet(i,k));
else
bik = &bik_work;
if(i < k)
make_bond(xx,i,k,bik);
else
make_bond(xx,k,i,bik);
}
t1 = gettime();
t_make_b += t1-t0;
t0 = gettime();
if(bij != 0 && bij != 0) {
tptr = twork;
make_triplet(bij,bik,tptr);
*dvir_ij_p = bij->fl_deriv_sum;
*dvir_ik_p = bik->fl_deriv_sum;
} else {
*dvir_ij_p = 0.0;
*dvir_ik_p = 0.0;
}
t1 = gettime();
t_make_t += t1-t0;
n_make++;
return tptr;
}
double PairMGPT::numderiv3t(double xx[][3],int i,int j,int k,int p) {
static bond_data Bij,Bjk,Bki;
const double delta = 1e-5;
const double xsave = xx[i][p];
double e1,e2;
const double vc = splinepot.vc;
xx[i][p] = xsave + delta;
make_bond(xx,i,j,&Bij);
make_bond(xx,j,k,&Bjk);
make_bond(xx,k,i,&Bki);
e1 = trace(prodmat(Bij.H,Bjk.H),Bki.H) * (vc/anorm3);
xx[i][p] = xsave - delta;
make_bond(xx,i,j,&Bij);
if(0) { /* This bond doesn't change when i is perturbed */
make_bond(xx,j,k,&Bjk);
}
make_bond(xx,k,i,&Bki);
e2 = trace(prodmat(Bij.H,Bjk.H),Bki.H) * (vc/anorm3);
xx[i][p] = xsave;
return (e1 - e2)/(2.0*delta);
}
double PairMGPT::numderiv3v(double xx[][3],int i,int j,int k,int p,int ipert) {
static bond_data Bij,Bik;
const double delta = 1e-5;
const double xsave = xx[ipert][p];
double e1,e2;
const double vd = splinepot.vd;
xx[ipert][p] = xsave + delta;
make_bond(xx,i,j,&Bij);
make_bond(xx,i,k,&Bik);
e1 = trace(prodmat(Bij.H,Bij.H),prodmat(Bik.H,Bik.H)) * (vd/anorm4);
xx[ipert][p] = xsave - delta;
make_bond(xx,i,j,&Bij);
make_bond(xx,i,k,&Bik);
e2 = trace(prodmat(Bij.H,Bij.H),prodmat(Bik.H,Bik.H)) * (vd/anorm4);
xx[ipert][p] = xsave;
return (e1 - e2)/(2.0*delta);
}
double PairMGPT::numderiv4(double xx[][3],int i,int j,int k,int m,int p) {
static bond_data Bij,Bjk,Bkm,Bmi;
const double delta = 1e-5;
const double xsave = xx[i][p];
double e1,e2;
const double ve = splinepot.ve;
xx[i][p] = xsave + delta;
make_bond(xx,i,j,&Bij);
make_bond(xx,j,k,&Bjk);
make_bond(xx,k,m,&Bkm);
make_bond(xx,m,i,&Bmi);
e1 = trace(prodmat(Bij.H,Bjk.H),prodmat(Bkm.H,Bmi.H)) * (ve/anorm4);
xx[i][p] = xsave - delta;
make_bond(xx,i,j,&Bij);
if(0) { /* Only the i coordinates changed... */
make_bond(xx,j,k,&Bjk);
make_bond(xx,k,m,&Bkm);
}
make_bond(xx,m,i,&Bmi);
e2 = trace(prodmat(Bij.H,Bjk.H),prodmat(Bkm.H,Bmi.H)) * (ve/anorm4);
xx[i][p] = xsave;
return (e1 - e2)/(2.0*delta);
}
static double dtol = 1e-6;
void PairMGPT::force_debug_3t(double xx[][3],
int i0,int j0,int k0,
int i ,int j ,int k ,
double dfix,double dfiy,double dfiz,
double dfjx,double dfjy,double dfjz,
double dfkx,double dfky,double dfkz) {
double dfi[3],dfj[3],dfk[3];
dfi[0] = dfix; dfi[1] = dfiy; dfi[2] = dfiz;
dfj[0] = dfjx; dfj[1] = dfjy; dfj[2] = dfjz;
dfk[0] = dfkx; dfk[1] = dfky; dfk[2] = dfkz;
for(int p = 0; p<3; p++) {
/* Compute numerical derivatives by displacing atoms i,j,k */
double ndfi,ndfj,ndfk;
ndfi = -numderiv3t(xx,i,j,k,p);
ndfj = -numderiv3t(xx,j,k,i,p);
ndfk = -numderiv3t(xx,k,i,j,p);
if((fabs(dfi[p] - ndfi) > dtol &&
fabs(dfi[p] - ndfi) > dtol*fabs(ndfi)) ||
(fabs(dfj[p] - ndfj) > dtol &&
fabs(dfj[p] - ndfj) > dtol*fabs(ndfj)) ||
(fabs(dfk[p] - ndfk) > dtol &&
fabs(dfk[p] - ndfk) > dtol*fabs(ndfk))) {
printf("Force error in T12 & T23 & T31 :: i,j,k = %d,%d,%d\n",i0,j0,k0);
printf(" dE/d%c[i] = %20.10e %20.10e\n", 'x'+p,ndfi, dfi[p]);
printf(" dE/d%c[j] = %20.10e %20.10e\n", 'x'+p,ndfj, dfj[p]);
printf(" dE/d%c[k] = %20.10e %20.10e\n", 'x'+p,ndfk, dfk[p]);
printf("\n");
}
}
}
void PairMGPT::force_debug_3v(double xx[][3],
int i0,int j0,int k0,
int i ,int j ,int k ,
double dfix,double dfiy,double dfiz,
double dfjx,double dfjy,double dfjz,
double dfkx,double dfky,double dfkz) {
double dfi[3],dfj[3],dfk[3];
dfi[0] = dfix; dfi[1] = dfiy; dfi[2] = dfiz;
dfj[0] = dfjx; dfj[1] = dfjy; dfj[2] = dfjz;
dfk[0] = dfkx; dfk[1] = dfky; dfk[2] = dfkz;
for(int p = 0; p<3; p++) {
/* Compute numerical derivatives by displacing atoms i,j,k */
double ndfi,ndfj,ndfk;
ndfi = -numderiv3v(xx,i,j,k,p,i0);
ndfj = -numderiv3v(xx,i,j,k,p,j0);
ndfk = -numderiv3v(xx,i,j,k,p,k0);
if((fabs(dfi[p] - ndfi) > dtol &&
fabs(dfi[p] - ndfi) > dtol*fabs(ndfi)) ||
(fabs(dfj[p] - ndfj) > dtol &&
fabs(dfj[p] - ndfj) > dtol*fabs(ndfj)) ||
(fabs(dfk[p] - ndfk) > dtol &&
fabs(dfk[p] - ndfk) > dtol*fabs(ndfk))) {
printf("Force error in T12 :: i,j,k = %d,%d,%d\n",i0,j0,k0);
printf(" dE/d%c[i] = %20.10e %20.10e\n", 'x'+p,ndfi, dfi[p]);
printf(" dE/d%c[j] = %20.10e %20.10e\n", 'x'+p,ndfj, dfj[p]);
printf(" dE/d%c[k] = %20.10e %20.10e\n", 'x'+p,ndfk, dfk[p]);
printf("\n");
}
}
}
void PairMGPT::force_debug_4(double xx[][3],
int i0,int j0,int k0,int m0,
int i ,int j ,int k ,int m ,
double dfix,double dfiy,double dfiz,
double dfjx,double dfjy,double dfjz,
double dfkx,double dfky,double dfkz,
double dfmx,double dfmy,double dfmz) {
double dfi[3],dfj[3],dfk[3],dfm[3];
dfi[0] = dfix; dfi[1] = dfiy; dfi[2] = dfiz;
dfj[0] = dfjx; dfj[1] = dfjy; dfj[2] = dfjz;
dfk[0] = dfkx; dfk[1] = dfky; dfk[2] = dfkz;
dfm[0] = dfmx; dfm[1] = dfmy; dfm[2] = dfmz;
const int ii0[] = {i0,j0,k0,m0},ii[] = {i,j,k,m,i,j,k};
for(int p = 0; p<3; p++) {
/* Compute numerical derivatives by displacing atoms i,j,k,m */
double ndfi,ndfj,ndfk,ndfm;
if(1) {
double ndf[] = {0.0,0.0,0.0,0.0};
for(int s = 0; s<4; s++)
for(int t = 0; t<4; t++)
if(ii[s] == ii0[t])
ndf[t] = -numderiv4(xx,ii[s],ii[s+1],ii[s+2],ii[s+3],p);
ndfi = ndf[0]; ndfj = ndf[1];
ndfk = ndf[2]; ndfm = ndf[3];
} else {
ndfi = -numderiv4(xx,i,j,k,m,p);
ndfj = -numderiv4(xx,j,k,m,i,p);
ndfk = -numderiv4(xx,k,m,i,j,p);
ndfm = -numderiv4(xx,m,i,j,k,p);
}
if((fabs(dfi[p] - ndfi) > dtol &&
fabs(dfi[p] - ndfi) > dtol*fabs(ndfi)) ||
(fabs(dfj[p] - ndfj) > dtol &&
fabs(dfj[p] - ndfj) > dtol*fabs(ndfj)) ||
(fabs(dfk[p] - ndfk) > dtol &&
fabs(dfk[p] - ndfk) > dtol*fabs(ndfk)) ||
(fabs(dfm[p] - ndfm) > dtol &&
fabs(dfm[p] - ndfm) > dtol*fabs(ndfm))) {
printf("Force error in T31 & T64 :: i,j,k,m = %d,%d,%d,%d\n",i0,j0,k0,m0);
printf(" dE/d%c[i] = %20.10e %20.10e\n", 'x'+p,ndfi, dfi[p]);
printf(" dE/d%c[j] = %20.10e %20.10e\n", 'x'+p,ndfj, dfj[p]);
printf(" dE/d%c[k] = %20.10e %20.10e\n", 'x'+p,ndfk, dfk[p]);
printf(" dE/d%c[m] = %20.10e %20.10e\n", 'x'+p,ndfm, dfm[p]);
printf("\n");
}
}
}
/*
#define trd_update_4(T12,T45,coord) \
do { \
trd1 = transtrace(T12->H1##coord##H2,T45->H1H2 ); \
trd2 = transtrace(T12->H1H2##coord,T45->H1H2 ); \
trd3 = transtrace(T12->H1H2 ,T45->H1##coord##H2); \
trd4 = transtrace(T12->H1H2 ,T45->H1H2##coord ); \
} while(0)
*/
#define trd_update_4(T12,T45) \
do { \
tr_trace3(&(T45->H1H2.m[1][0]), \
&(T12->H1xH2.m[1][0]),&utr1x.d, \
&(T12->H1yH2.m[1][0]),&utr1y.d, \
&(T12->H1zH2.m[1][0]),&utr1z.d); \
tr_trace3(&(T45->H1H2.m[1][0]), \
&(T12->H1H2x.m[1][0]),&utr2x.d, \
&(T12->H1H2y.m[1][0]),&utr2y.d, \
&(T12->H1H2z.m[1][0]),&utr2z.d); \
tr_trace3(&(T12->H1H2.m[1][0]), \
&(T45->H1xH2.m[1][0]),&utr3x.d, \
&(T45->H1yH2.m[1][0]),&utr3y.d, \
&(T45->H1zH2.m[1][0]),&utr3z.d); \
tr_trace3(&(T12->H1H2.m[1][0]), \
&(T45->H1H2x.m[1][0]),&utr4x.d, \
&(T45->H1H2y.m[1][0]),&utr4y.d, \
&(T45->H1H2z.m[1][0]),&utr4z.d); \
if(linalg.single) { \
trd1x = utr1x.f; trd2x = utr2x.f; trd3x = utr3x.f; trd4x = utr4x.f; \
trd1y = utr1y.f; trd2y = utr2y.f; trd3y = utr3y.f; trd4y = utr4y.f; \
trd1z = utr1z.f; trd2z = utr2z.f; trd3z = utr3z.f; trd4z = utr4z.f; \
} else { \
trd1x = utr1x.d; trd2x = utr2x.d; trd3x = utr3x.d; trd4x = utr4x.d; \
trd1y = utr1y.d; trd2y = utr2y.d; trd3y = utr3y.d; trd4y = utr4y.d; \
trd1z = utr1z.d; trd2z = utr2z.d; trd3z = utr3z.d; trd4z = utr4z.d; \
} \
} while(0)
#define dfix_update_4a(coord) \
do { \
dfi##coord = ( (-sij)*trd1##coord + (-sim)*trd3##coord ) * (ve / anorm4); \
dfj##coord = ( ( sij)*trd1##coord + (-sjk)*trd2##coord ) * (ve / anorm4); \
dfk##coord = ( ( sjk)*trd2##coord + (-skm)*trd4##coord ) * (ve / anorm4); \
dfm##coord = ( ( sim)*trd3##coord + ( skm)*trd4##coord ) * (ve / anorm4); \
} while(0)
#define dfix_update_4b(coord) \
do { \
dfi##coord = ( ( ski)*trd1##coord + (-sim)*trd3##coord ) * (ve / anorm4); \
dfj##coord = ( (-sjk)*trd2##coord + (-sjm)*trd4##coord ) * (ve / anorm4); \
dfk##coord = ( (-ski)*trd1##coord + ( sjk)*trd2##coord ) * (ve / anorm4); \
dfm##coord = ( ( sim)*trd3##coord + ( sjm)*trd4##coord ) * (ve / anorm4); \
} while(0);
#define dfix_update_4c(coord) \
do { \
dfi##coord = ( (-sij)*trd1##coord + ( ski)*trd2##coord ) * (ve / anorm4); \
dfj##coord = ( ( sij)*trd1##coord + (-sjm)*trd3##coord ) * (ve / anorm4); \
dfk##coord = ( (-ski)*trd2##coord + (-skm)*trd4##coord ) * (ve / anorm4); \
dfm##coord = ( ( sjm)*trd3##coord + ( skm)*trd4##coord ) * (ve / anorm4); \
} while(0);
#define accumulate_forces_2(w) \
do { \
fix = fix + dfix*(w); \
fiy = fiy + dfiy*(w); \
fiz = fiz + dfiz*(w); \
\
fjx = fjx + dfjx*(w); \
fjy = fjy + dfjy*(w); \
fjz = fjz + dfjz*(w); \
} while(0)
#define accumulate_forces_3(w) \
do { \
accumulate_forces_2(w); \
fkx = fkx + dfkx*(w); \
fky = fky + dfky*(w); \
fkz = fkz + dfkz*(w); \
} while(0)
#define accumulate_forces_4(w) \
do { \
accumulate_forces_3(w); \
fmx = fmx + dfmx*(w); \
fmy = fmy + dfmy*(w); \
fmz = fmz + dfmz*(w); \
} while(0)
#define restrict __restrict__
#ifdef __bg__
#define const
#endif
static int ntr_calls = 0;
static trtrace3_fun tr_internal;
static void tr_count(const double * restrict A,
const double * restrict B1,double * restrict t1,
const double * restrict B2,double * restrict t2,
const double * restrict B3,double * restrict t3) {
tr_internal(A,B1,t1,B2,t2,B3,t3);
ntr_calls++;
}
#ifdef __bg__
#undef const
#endif
#undef restrict
int PairMGPT::Matrix::sz;
void PairMGPT::compute_x(const int *nnei,const int * const *nlist,
double *e_s,double *e_p,double *e_t,double *e_q,
int evflag,int newton_pair) {
Hash<bond_data,Doublet> bond_hash(100000);
int i,j,k,m,ix,jx,kx,mx,itag,jtag,p;
double e_single,e_pair,e_triplet,e_triplet_c,e_quad;
double volvir2;
double nbc = 0.0,tbl = 0.0,tbm = 0.0;
const int lmax_local = lmax;
//if(evflag) printf("##### ev flag is set... wasting cycles...\n");
*e_s = -99.0;
*e_p = -99.0;
*e_t = -99.0;
*e_q = -99.0;
double t0,t1;
t0 = gettime(1);
e_single = e_pair = e_triplet = e_triplet_c = e_quad = 0.0;
volvir2 = 0.0;
t_make_t = t_make_b = t_make_b2 = t_trace = 0.0;
n_make = n_make_b2 = n_trace = 0.0;
double tx0,tx1,tsort = 0.0,tpair = 0.0,tlookup = 0.0;
double ttriplet = 0.0,tquad = 0.0,tmem = 0.0;
double ntsort = 0.0,ntpair = 0.0,ntlookup = 0.0;
double nttriplet = 0.0,ntquad = 0.0,ntmem = 0.0,ntquaditer = 0.0;
double mcount = 0.0,mcount2 = 0.0, qcount = 0.0;
double fix,fjx,fkx,fmx,dfix,dfjx,dfkx,dfmx;
double fiy,fjy,fky,fmy,dfiy,dfjy,dfky,dfmy;
double fiz,fjz,fkz,fmz,dfiz,dfjz,dfkz,dfmz;
double fsave[4][3] = { {0.0} } /* {{0.0}} is to get rid of uninitialized use warning */;
//const int numerical_pair_forces = (nbody_flag/16)%2;
const int pair_forces = (nbody_flag/2)%2,three_body_forces = (nbody_flag/4)%2,four_body_forces = (nbody_flag/8)%2;
const int pair_energies = (nbody_flag/2)%2,three_body_energies = (nbody_flag/4)%2,four_body_energies = (nbody_flag/8)%2;
const int single_energies = nbody_flag%2;
const int triplet_debug = 0,quad_debug = 0;
/* Energy and force scale factor for unit conversion. */
const double e_scale = 0.5;
#ifdef NEIGHMASK
#define NIDX(x) (x)
#else
#define NIDX(x) ((x) & NEIGHMASK)
#endif
int nneitot,*first,*nlist_short;
double w2,w3,w4;
triplet_data T12work,T23work,T31work,T45work,T56work,T64work;
triplet_data *T12,*T23,*T31,*T45,*T56,*T64;
int c_ij,c_jk,c_ki,c_im,c_jm,c_km;
int mi,mj,mk;
double tr0,tr1,tr2,tr3;
double v33,v43;
double rcut2_pair = rmax*rmax,rcut2_bond = rcrit*rcrit,rij2;
int ntot,nloc;
double dvir_ij,dvir_jk,dvir_ki,dvir_im,dvir_jm,dvir_km;
double vir3t = 0.0,vir3v = 0.0,vir4 = 0.0;
double (*xx)[3],(*ff)[3],(*ss)[3];
#ifdef TIMING_ON
tr_internal = linalg.tr_trace; ntr_calls = 0;
const trtrace3_fun tr_trace3 = tr_count;
#else
const trtrace3_fun tr_trace3 = linalg.tr_trace;
#endif
union {
double d;
float f;
} utr1x,utr2x,utr3x,utr4x,utr1y,utr2y,utr3y,utr4y,utr1z,utr2z,utr3z,utr4z;
double trd1x,trd2x,trd3x,trd4x;
double trd1y,trd2y,trd3y,trd4y;
double trd1z,trd2z,trd3z,trd4z;
tx0 = gettime();
double rhoinv;
{
double vtot = 1.0;
double ntot = atom->natoms;
for(i = 0; i<3; i++)
vtot = vtot * (domain->boxhi[i] - domain->boxlo[i]);
rhoinv = vtot / ntot;
}
/* Make sure triplet data work area is aligned and zeroed out. */ {
assert(T12work.align_check() == 0);
assert(T23work.align_check() == 0);
assert(T31work.align_check() == 0);
assert(T45work.align_check() == 0);
assert(T56work.align_check() == 0);
assert(T64work.align_check() == 0);
T12work.zero(); T23work.zero(); T31work.zero();
T45work.zero(); T56work.zero(); T64work.zero();
}
ntot = atom->nlocal + atom->nghost;
nloc = atom->nlocal;
//printf("[%3d] Allocating local array, size is %d atoms...\n",comm->me,j);
xx = (double (*)[3]) memory->smalloc(sizeof(double [3]) * ntot,"mgpt: local position vector.");
ff = (double (*)[3]) memory->smalloc(sizeof(double [3]) * ntot,"mgpt: local force vector.");
//printf("[%3d] Initializing arrays...\n",comm->me);
const int triclinic = domain->triclinic;
double alpha[3] = {0.0,0.0,0.0};
if(triclinic) {
double E[3][3],EX[3][3];
int cyc[] = {0,1,2,0,1};
ss = (double (*)[3]) memory->smalloc(sizeof(double [3]) * ntot,
"mgpt: local reduced coordinate vector.");
for(i = 0; i<3; i++) {
for(j = 0; j<3; j++)
E[i][j] = 0.0;
E[i][i] = domain->subhi_lamda[i] - domain->sublo_lamda[i];
domain->lamda2x(E[i],EX[i]);
}
for(i = 0; i<3; i++) {
int i1 = cyc[i+1],i2 = cyc[i+2];
double dot = 0.0,ns2 = 0.0;
for(j = 0; j<3; j++) {
int j1 = cyc[j+1],j2 = cyc[j+2];
double cj = EX[i1][j1]*EX[i2][j2] - EX[i1][j2]*EX[i2][j1];
ns2 = ns2 + cj*cj;
dot = dot + EX[i][j]*cj;
}
alpha[i] = E[i][i] / (dot/sqrt(ns2));
if(comm->me == 0) {
static int count = 0;
if(count < 3)
printf("@@@ alpha(%d) = %15.5e\n",i+1,alpha[i]);
count++;
}
if(alpha[i] < 0.0) alpha[i] = -alpha[i];
}
} else
ss = xx;
nneitot = 0;
for(ix = 0; ix<ntot; ix++) {
for(p = 0; p<3; p++) {
xx[ix][p] = atom->x[ix][p];
ff[ix][p] = 0.0;
}
if(triclinic)
domain->x2lamda(xx[ix],ss[ix]);
nneitot = nneitot + nnei[ix];
}
first = (int *) memory->smalloc(sizeof(int) * (ntot+1),"mgpt: first");
nlist_short = (int *) memory->smalloc(sizeof(int) * nneitot,"mgpt: nlist_short");
tx1 = gettime();
tmem += tx1-tx0;
ntmem++;
//printf("[%3d] Starting calculation...\n",comm->me);
fix = fjx = fkx = fmx = 0.0;
fiy = fjy = fky = fmy = 0.0;
fiz = fjz = fkz = fmz = 0.0;
int c_p = 0, c_t = 0, c_q = 0;
if(0)
if(domain->triclinic) {
if(comm->me == 0)
printf("Can not handle triclinic box yet\n");
error->all(__FILE__,__LINE__,"Can not handle triclinic cell with mgpt yet.");
}
/*
for(i = 0; i<nloc; i++) {
printf("Atom %3d:: %10.3f %10.3f %10.3f\n",
i,xx[i][0],xx[i][1],xx[i][2]);
}
*/
first[0] = 0;
for(i = 0; i<ntot; i++) {
fix = fiy = fiz = 0.0;
first[i+1] = first[i];
const int c1 = c1_outside(ss[i],triclinic,alpha);
tx0 = gettime();
for(jx = 0; jx<nnei[i]; jx++) {
fjx = fjy = fjz = 0.0;
j = NIDX( nlist[i][jx] );
rij2 = 0.0;
for(p = 0; p<3; p++) {
double t = xx[i][p] - xx[j][p];
rij2 = rij2 + t*t;
}
if(c1 == 0 && rij2 < rcut2_pair) {
if(j < i) {
w2 = get_weight(triclinic,ss[i],ss[j]);
if(w2 > 0.0) {
/*
Compute pair energy/force
*/
double de_pair,df,rij = sqrt(rij2);
splinepot.eval_pot(rij,&de_pair,&df);
de_pair = de_pair * e_scale * w2;
df = df / rij * w2;
if(pair_energies == 0) de_pair = 0.0;
e_pair = e_pair + de_pair;
c_p++;
if(pair_forces == 0) df = 0.0;
if(volpres_flag && pair_energies) {
double dvir;
splinepot.eval_vir(rij,&dvir);
volvir2 = volvir2 - dvir * w2;
/* Per-atom virial contribution of volumetric energy term */
if(vflag_atom)
for(int pp = 0; pp<3; pp++) {
//virial[i] = virial[i] + rhoinv*e_scale*volvir2;
vatom[i][pp] -= 0.5 * rhoinv*e_scale*dvir*w2;
vatom[j][pp] -= 0.5 * rhoinv*e_scale*dvir*w2;
}
}
double drijx = xx[j][0] - xx[i][0];
double drijy = xx[j][1] - xx[i][1];
double drijz = xx[j][2] - xx[i][2];
fix = fix + df*drijx;
fjx = fjx - df*drijx;
fiy = fiy + df*drijy;
fjy = fjy - df*drijy;
fiz = fiz + df*drijz;
fjz = fjz - df*drijz;
if(evflag) {
//ev_tally(i,j,nloc,newton_pair,de_pair,0.0,df,-drijx,-drijy,-drijz);
/* To fix stress-per-atom scaling, and sign */
ev_tally(i,j,nloc,newton_pair,de_pair,0.0,-df * e_scale,-drijx,-drijy,-drijz);
}
ff[j][0] += fjx * e_scale;
ff[j][1] += fjy * e_scale;
ff[j][2] += fjz * e_scale;
}
}
}
if(rij2 < rcut2_bond && c2_outside(ss[i],ss[j],triclinic,alpha) == 0) {
/*
Add j to short neighbor list for i.
Insert j to keep list sorted.
*/
p = first[i+1]-1;
while(p >= first[i] && nlist_short[p] > j) {
nlist_short[p+1] = nlist_short[p];
p = p - 1;
}
nlist_short[p+1] = j;
first[i+1] = first[i+1] + 1;
if(first[i+1] > nneitot) {
printf("nneitot = %d, short list full. i=%d\n",
nneitot,i);
error->one(__FILE__,__LINE__,"Shit! Short list full\n");
}
}
}
ff[i][0] += fix * e_scale;
ff[i][1] += fiy * e_scale;
ff[i][2] += fiz * e_scale;
tx1 = gettime();
tpair += tx1-tx0;
ntpair += nnei[i];
}
for(i = 0; i<ntot; i++) {
fix = fiy = fiz = 0.0;
/*
Use short lists for triplets and quadruplets.
For open (2-bonded) triplets, can only use k<j, but not k<i.
For closed (3-bonded) triplets, we can assume k<j<i.
Quadruplets:
Always use k<j<i, and require m<i.
If 5-bonded with im bond, ignore the quadruplet.
If 6-bonded, require m<k.
For 4-bonded quadruplets, we can still use k<j, but also
assume max(m,j)<i
*/
if(three_body_energies || three_body_forces ||
four_body_energies || four_body_forces)
for(jx = first[i]; jx<first[i+1]; jx++) {
fjx = fjy = fjz = 0.0;
j = nlist_short[jx];
for(kx = first[i]; kx<jx; kx++) {
fkx = fky = fkz = 0.0;
k = nlist_short[kx];
/*
Search lists of j and k, and see if
1) j is in k-list (closed triplet)
2) j and k have a common neighbor (closed quadruplet)
*/
c_ij = c_ki = 1;
const int sij = (i < j) ? 1 : -1;
const int sjk = (j < k) ? 1 : -1;
const int ski = (k < i) ? 1 : -1;
T12 = T23 = T31 = 0;
mj = first[j];
/*
Since i is in the j-list, and i > k and the list
is sorted, the loop below terminates:-)
*/
while(mj < first[j+1] && nlist_short[mj] < k) mj = mj + 1;
if(mj < first[j+1] && nlist_short[mj] == k) {
/* Closed triplet */
c_jk = 1;
if(j > i) continue; /* Require k<j<i for closed triplets */
} else {
/* Open triplet */
c_jk = 0;
}
tx0 = gettime();
w3 = get_weight(triclinic,ss[i],ss[j],ss[k]);
int triplet_defer;
if(w3 > 0.0) {
triplet_defer = 0;
dvir_ij = dvir_jk = dvir_ki = 0.0;
if(c_ij && c_jk)
T12 = get_triplet(xx,j,i,k,&bond_hash,&T12work,&dvir_ij,&dvir_jk);
if(c_ki && c_jk)
T23 = get_triplet(xx,k,i,j,&bond_hash,&T23work,&dvir_ki,&dvir_jk);
if(c_ij && c_ki)
T31 = get_triplet(xx,i,j,k,&bond_hash,&T31work,&dvir_ij,&dvir_ki);
if(evflag) {
fsave[0][0] = fix; fsave[0][1] = fiy; fsave[0][2] = fiz;
fsave[1][0] = fjx; fsave[1][1] = fjy; fsave[1][2] = fjz;
fsave[2][0] = fkx; fsave[2][1] = fky; fsave[2][2] = fkz;
fix = fiy = fiz = 0.0;
fjx = fjy = fjz = 0.0;
fkx = fky = fkz = 0.0;
}
tr0 = tr1 = tr2 = tr3 = 0.0;
double xvir3t,xvir3v;
xvir3t = xvir3v = 0.0;
if(T12 && T23) {
bond_data *bki = bond_hash.Lookup(Doublet(k,i));
if(three_body_energies && evflag) {
tr0 = transtrace(T12->H1H2,bki->H);
double dvir = ((dvir_ij + dvir_jk + bki->fl_deriv_sum)*splinepot.vc +
splinepot.dvc)*tr0*w3/anorm3;
vir3t = vir3t + dvir;
xvir3t = xvir3t + dvir;
}
mcount2++;
{
const double vc = splinepot.vc;
tr_trace3(&(bki->H.m[1][0]),
&(T12->H1xH2.m[1][0]),&utr1x.d,
&(T12->H1yH2.m[1][0]),&utr1y.d,
&(T12->H1zH2.m[1][0]),&utr1z.d);
tr_trace3(&(bki->H.m[1][0]),
&(T12->H1H2x.m[1][0]),&utr2x.d,
&(T12->H1H2y.m[1][0]),&utr2y.d,
&(T12->H1H2z.m[1][0]),&utr2z.d);
tr_trace3(&(T12->H1H2.m[1][0]),
&(bki->Hx.m[1][0]),&utr3x.d,
&(bki->Hy.m[1][0]),&utr3y.d,
&(bki->Hz.m[1][0]),&utr3z.d);
if(linalg.single) {
trd1x = utr1x.f; trd2x = utr2x.f; trd3x = utr3x.f;
trd1y = utr1y.f; trd2y = utr2y.f; trd3y = utr3y.f;
trd1z = utr1z.f; trd2z = utr2z.f; trd3z = utr3z.f;
} else {
trd1x = utr1x.d; trd2x = utr2x.d; trd3x = utr3x.d;
trd1y = utr1y.d; trd2y = utr2y.d; trd3y = utr3y.d;
trd1z = utr1z.d; trd2z = utr2z.d; trd3z = utr3z.d;
}
dfix = ( (-sij)*trd1x + ( ski)*trd3x ) * (vc / anorm3);
dfjx = ( ( sij)*trd1x + (-sjk)*trd2x ) * (vc / anorm3);
dfkx = ( ( sjk)*trd2x + (-ski)*trd3x ) * (vc / anorm3);
dfiy = ( (-sij)*trd1y + ( ski)*trd3y ) * (vc / anorm3);
dfjy = ( ( sij)*trd1y + (-sjk)*trd2y ) * (vc / anorm3);
dfky = ( ( sjk)*trd2y + (-ski)*trd3y ) * (vc / anorm3);
dfiz = ( (-sij)*trd1z + ( ski)*trd3z ) * (vc / anorm3);
dfjz = ( ( sij)*trd1z + (-sjk)*trd2z ) * (vc / anorm3);
dfkz = ( ( sjk)*trd2z + (-ski)*trd3z ) * (vc / anorm3);
}
if(triplet_debug)
force_debug_3t(xx,i,j,k, i,j,k,
dfix,dfiy,dfiz,
dfjx,dfjy,dfjz,
dfkx,dfky,dfkz);
if(three_body_forces)
accumulate_forces_3(w3);
}
if(T12 != 0) {
//printf("T12 i,j,k = %d,%d,%d\n",i,j,k);
mcount++;
if(three_body_energies && evflag) {
tr1 = transtrace(T12->H1H2,T12->H1H2);
double dvir = (2.0*(dvir_ij + dvir_jk)*splinepot.vd +
splinepot.dvd)*tr1*w3/anorm4;
vir3v = vir3v + dvir;
xvir3v = xvir3v + dvir;
}
{
const double vd = splinepot.vd;
tr_trace3(&(T12->H1H2.m[1][0]),
&(T12->H1xH2.m[1][0]),&utr1x.d,
&(T12->H1yH2.m[1][0]),&utr1y.d,
&(T12->H1zH2.m[1][0]),&utr1z.d);
tr_trace3(&(T12->H1H2.m[1][0]),
&(T12->H1H2x.m[1][0]),&utr2x.d,
&(T12->H1H2y.m[1][0]),&utr2y.d,
&(T12->H1H2z.m[1][0]),&utr2z.d);
if(linalg.single) {
trd1x = utr1x.f; trd2x = utr2x.f;
trd1y = utr1y.f; trd2y = utr2y.f;
trd1z = utr1z.f; trd2z = utr2z.f;
} else {
trd1x = utr1x.d; trd2x = utr2x.d;
trd1y = utr1y.d; trd2y = utr2y.d;
trd1z = utr1z.d; trd2z = utr2z.d;
}
dfix = 2.0*(-sij)*trd1x * (vd / anorm4);
dfkx = 2.0*( sjk)*trd2x * (vd / anorm4);
dfjx = -(dfix + dfkx);
dfiy = 2.0*(-sij)*trd1y * (vd / anorm4);
dfky = 2.0*( sjk)*trd2y * (vd / anorm4);
dfjy = -(dfiy + dfky);
dfiz = 2.0*(-sij)*trd1z * (vd / anorm4);
dfkz = 2.0*( sjk)*trd2z * (vd / anorm4);
dfjz = -(dfiz + dfkz);
}
if(triplet_debug) /* Compare forces to numerical derivatives */
force_debug_3v(xx,i,j,k, j,i,k,
dfix,dfiy,dfiz,
dfjx,dfjy,dfjz,
dfkx,dfky,dfkz);
if(three_body_forces)
accumulate_forces_3(w3);
}
if(T23 != 0) {
//printf("T23 i,j,k = %d,%d,%d\n",i,j,k);
mcount++;
if(three_body_energies && evflag) {
tr2 = transtrace(T23->H1H2,T23->H1H2);
double dvir = (2.0*(dvir_jk + dvir_ki)*splinepot.vd +
splinepot.dvd)*tr2*w3/anorm4;
vir3v = vir3v + dvir;
xvir3v = xvir3v + dvir;
}
{
const double vd = splinepot.vd;
tr_trace3(&(T23->H1H2.m[1][0]),
&(T23->H1xH2.m[1][0]),&utr1x.d,
&(T23->H1yH2.m[1][0]),&utr1y.d,
&(T23->H1zH2.m[1][0]),&utr1z.d);
tr_trace3(&(T23->H1H2.m[1][0]),
&(T23->H1H2x.m[1][0]),&utr2x.d,
&(T23->H1H2y.m[1][0]),&utr2y.d,
&(T23->H1H2z.m[1][0]),&utr2z.d);
if(linalg.single) {
trd1x = utr1x.f; trd2x = utr2x.f;
trd1y = utr1y.f; trd2y = utr2y.f;
trd1z = utr1z.f; trd2z = utr2z.f;
} else {
trd1x = utr1x.d; trd2x = utr2x.d;
trd1y = utr1y.d; trd2y = utr2y.d;
trd1z = utr1z.d; trd2z = utr2z.d;
}
dfix = 2.0*( ski)*trd1x * (vd / anorm4);
dfjx = 2.0*(-sjk)*trd2x * (vd / anorm4);
dfkx = -(dfix + dfjx);
dfiy = 2.0*( ski)*trd1y * (vd / anorm4);
dfjy = 2.0*(-sjk)*trd2y * (vd / anorm4);
dfky = -(dfiy + dfjy);
dfiz = 2.0*( ski)*trd1z * (vd / anorm4);
dfjz = 2.0*(-sjk)*trd2z * (vd / anorm4);
dfkz = -(dfiz + dfjz);
}
if(triplet_debug) /* Compare forces to numerical derivatives */
force_debug_3v(xx,i,j,k, k,i,j,
dfix,dfiy,dfiz,
dfjx,dfjy,dfjz,
dfkx,dfky,dfkz);
if(three_body_forces)
accumulate_forces_3(w3);
}
if(T31 != 0) {
//printf("T31 i,j,k = %d,%d,%d\n",i,j,k);
mcount++;
if(three_body_energies && evflag) {
tr3 = transtrace(T31->H1H2,T31->H1H2);
double dvir = (2.0*(dvir_ki + dvir_ij)*splinepot.vd +
splinepot.dvd)*tr3*w3/anorm4;
vir3v = vir3v + dvir;
xvir3v = xvir3v + dvir;
}
{
const double vd = splinepot.vd;
tr_trace3(&(T31->H1H2.m[1][0]),
&(T31->H1xH2.m[1][0]),&utr1x.d,
&(T31->H1yH2.m[1][0]),&utr1y.d,
&(T31->H1zH2.m[1][0]),&utr1z.d);
tr_trace3(&(T31->H1H2.m[1][0]),
&(T31->H1H2x.m[1][0]),&utr2x.d,
&(T31->H1H2y.m[1][0]),&utr2y.d,
&(T31->H1H2z.m[1][0]),&utr2z.d);
if(linalg.single) {
trd1x = utr1x.f; trd2x = utr2x.f;
trd1y = utr1y.f; trd2y = utr2y.f;
trd1z = utr1z.f; trd2z = utr2z.f;
} else {
trd1x = utr1x.d; trd2x = utr2x.d;
trd1y = utr1y.d; trd2y = utr2y.d;
trd1z = utr1z.d; trd2z = utr2z.d;
}
dfjx = 2.0*( sij)*trd1x * (vd / anorm4);
dfkx = 2.0*(-ski)*trd2x * (vd / anorm4);
dfix = -(dfjx + dfkx);
dfjy = 2.0*( sij)*trd1y * (vd / anorm4);
dfky = 2.0*(-ski)*trd2y * (vd / anorm4);
dfiy = -(dfjy + dfky);
dfjz = 2.0*( sij)*trd1z * (vd / anorm4);
dfkz = 2.0*(-ski)*trd2z * (vd / anorm4);
dfiz = -(dfjz + dfkz);
}
if(triplet_debug) /* Compare forces to numerical derivatives */
force_debug_3v(xx,i,j,k, i,j,k,
dfix,dfiy,dfiz,
dfjx,dfjy,dfjz,
dfkx,dfky,dfkz);
if(three_body_forces)
accumulate_forces_3(w3);
}
v33 = tr0 / anorm3;
v43 = (tr1 + tr2 + tr3) / anorm4;
double de_triplet = (splinepot.vc*v33 + splinepot.vd*v43) * e_scale * w3;
e_triplet = e_triplet + de_triplet;
e_triplet_c = e_triplet_c + splinepot.vc*v33 * e_scale * w3;
c_t++;
//printf("xxxx %6d %6d %6d :: %20.10e\n",1,2,3,de_triplet);
if(evflag) {
double drji[3],drki[3];
double fj[3] = {fjx,fjy,fjz},fk[3] = {fkx,fky,fkz};
for(int p = 0; p<3; p++) {
drji[p] = xx[j][p] - xx[i][p];
drki[p] = xx[k][p] - xx[i][p];
/* To fix stress-per-atom scaling. */
fj[p] *= e_scale;
fk[p] *= e_scale;
}
ev_tally3(i,j,k,de_triplet,0.0,fj,fk,drji,drki);
if(volpres_flag && vflag_atom) {
//virial[i] = virial[i] - (vir3v + vir3t) * rhoinv*e_scale;
double dvir = -(xvir3v + xvir3t) * rhoinv*e_scale * (1.0/3.0);
for(int pp = 0; pp<3; pp++) {
vatom[i][pp] += dvir;
vatom[j][pp] += dvir;
vatom[k][pp] += dvir;
}
}
fix = fix+fsave[0][0]; fiy = fiy+fsave[0][1]; fiz = fiz+fsave[0][2];
fjx = fjx+fsave[1][0]; fjy = fjy+fsave[1][1]; fjz = fjz+fsave[1][2];
fkx = fkx+fsave[2][0]; fky = fky+fsave[2][1]; fkz = fkz+fsave[2][2];
}
tx1 = gettime();
ttriplet += tx1 - tx0;
nttriplet++;
} else {
triplet_defer = 1;
}
if(four_body_energies || four_body_forces)
if(j < i) { /* Search for quadruplet */
tx0 = gettime();
mj = first[j];
mk = first[k];
/*
i is in both the j-list and the k-list, and i > k,
and lists are sorted, so the loop terminates.
*/
while(nlist_short[mj] < i && nlist_short[mk] < i) {
if(mj >= first[j+1] || mk >= first[k+1]) {
printf("Illegal quad...\n"
" j=%d first[j]=%d first[j+1]=%d mj=%d\n"
" k=%d first[k]=%d first[k+1]=%d mk=%d\n",
j,first[j],first[j+1],mj,
k,first[k],first[k+1],mk);
error->one(__FILE__,__LINE__,"Shit, brkoen quad loop");
}
if(nlist_short[mj] == nlist_short[mk]) {
/* Closed quadruplet */
m = nlist_short[mj];
c_jm = c_km = 1;
const int sim = (i < m) ? 1 : -1;
const int sjm = (j < m) ? 1 : -1;
const int skm = (k < m) ? 1 : -1;
w4 = get_weight(triclinic,ss[i],ss[j],ss[k],ss[m]);
if(w4 > 0.0) {
/* Alrady know ij,jk,ki,jm,km bonds. Look for im bond. */
mi = first[i];
while(mi < first[i+1] && nlist_short[mi] < m) mi = mi + 1;
if(mi < first[i+1] && nlist_short[mi] == m)
c_im = 1;
else
c_im = 0;
if(c_im == 0 || c_jk == 0 || (c_jk && c_im && m < k)) {
if(triplet_defer) {
dvir_ij = dvir_jk = dvir_ki = 0.0;
if(c_ij && c_jk)
T12 = get_triplet(xx,j,i,k,&bond_hash,&T12work,&dvir_ij,&dvir_jk);
if(c_ki && c_jk)
T23 = get_triplet(xx,k,i,j,&bond_hash,&T23work,&dvir_ki,&dvir_jk);
if(c_ij && c_ki)
T31 = get_triplet(xx,i,j,k,&bond_hash,&T31work,&dvir_ij,&dvir_ki);
triplet_defer = 0;
}
fmx = fmy = fmz = 0.0;
double xvir4 = 0.0;
if(evflag) {
fsave[0][0] = fix; fsave[0][1] = fiy; fsave[0][2] = fiz;
fsave[1][0] = fjx; fsave[1][1] = fjy; fsave[1][2] = fjz;
fsave[2][0] = fkx; fsave[2][1] = fky; fsave[2][2] = fkz;
fsave[3][0] = fmx; fsave[3][1] = fmy; fsave[3][2] = fmz;
fix = fiy = fiz = 0.0;
fjx = fjy = fjz = 0.0;
fkx = fky = fkz = 0.0;
fmx = fmy = fmz = 0.0;
}
tr1 = tr2 = tr3 = 0.0;
dvir_im = dvir_jm = dvir_km = 0.0;
T45 = T56 = T64 = 0;
if(T12 != 0 && c_km && c_im)
T45 = get_triplet(xx,m,i,k,&bond_hash,&T45work,&dvir_im,&dvir_km);
if(T23 != 0 && c_im && c_jm)
T56 = get_triplet(xx,m,i,j,&bond_hash,&T56work,&dvir_im,&dvir_jm);
if(T31 != 0 && c_jm && c_km)
T64 = get_triplet(xx,m,j,k,&bond_hash,&T64work,&dvir_jm,&dvir_km);
if(T12 != 0 && T45 != 0) {
if(four_body_energies && evflag) {
tr1 = transtrace(T12->H1H2,T45->H1H2);
double dvir = ( (dvir_ij + dvir_jk + dvir_im + dvir_km)*splinepot.ve +
splinepot.dve )*tr1*w4/anorm4;
vir4 = vir4 + dvir;
xvir4 = xvir4 + dvir;
}
qcount++;
{
const double ve = splinepot.ve;
trd_update_4(T12,T45);
dfix_update_4a(x);
dfix_update_4a(y);
dfix_update_4a(z);
}
if(quad_debug) /* Compare forces to numerical derivatives */
force_debug_4(xx,i,j,k,m, i,j,k,m,
dfix,dfiy,dfiz , dfjx,dfjy,dfjz,
dfkx,dfky,dfkz , dfmx,dfmy,dfmz);
if(four_body_forces)
accumulate_forces_4(w4);
}
if(T23 != 0 && T56 != 0) {
if(four_body_energies && evflag) {
tr2 = transtrace(T23->H1H2,T56->H1H2);
double dvir = ( (dvir_ki + dvir_jk + dvir_im + dvir_jm)*splinepot.ve +
splinepot.dve )*tr2*w4/anorm4;
vir4 = vir4 + dvir;
xvir4 = xvir4 + dvir;
}
qcount++;
{
const double ve = splinepot.ve;
trd_update_4(T23,T56);
dfix_update_4b(x);
dfix_update_4b(y);
dfix_update_4b(z);
}
if(quad_debug) /* Compare forces to numerical derivatives */
force_debug_4(xx,i,j,k,m, i,m,j,k,
dfix,dfiy,dfiz , dfjx,dfjy,dfjz,
dfkx,dfky,dfkz , dfmx,dfmy,dfmz);
if(four_body_forces)
accumulate_forces_4(w4);
}
if(T31 != 0 && T64 != 0) {
if(four_body_energies && evflag) {
tr3 = transtrace(T31->H1H2,T64->H1H2);
double dvir = ( (dvir_ki + dvir_ij + dvir_jm + dvir_km)*splinepot.ve +
splinepot.dve )*tr3*w4/anorm4;
vir4 = vir4 + dvir;
xvir4 = xvir4 + dvir;
}
qcount++;
{
const double ve = splinepot.ve;
/* X */
trd_update_4(T31,T64);
dfix_update_4c(x);
dfix_update_4c(y);
dfix_update_4c(z);
}
if(quad_debug) /* Compare forces to numerical derivatives */
force_debug_4(xx,i,j,k,m, i,j,m,k,
dfix,dfiy,dfiz , dfjx,dfjy,dfjz,
dfkx,dfky,dfkz , dfmx,dfmy,dfmz);
if(four_body_forces)
accumulate_forces_4(w4);
}
double de_quad = splinepot.ve*(tr1 + tr2 + tr3)/anorm4 * e_scale * w4;
e_quad = e_quad + de_quad;
if((T12 && T45) ||
(T23 && T56) ||
(T31 && T64)) {
c_q++;
}
if(evflag) {
double drim[3],drjm[3],drkm[3];
double fi[3] = {fix,fiy,fiz};
double fj[3] = {fjx,fjy,fjz};
double fk[3] = {fkx,fky,fkz};
for(int p = 0; p<3; p++) {
drim[p] = xx[i][p] - xx[m][p];
drjm[p] = xx[j][p] - xx[m][p];
drkm[p] = xx[k][p] - xx[m][p];
fi[p] *= e_scale;
fj[p] *= e_scale;
fk[p] *= e_scale;
}
ev_tally4(i,j,k,m,de_quad,fi,fj,fk,drim,drjm,drkm);
if(volpres_flag && vflag_atom) {
//virial[i] = virial[i] - vir4 * rhoinv*e_scale;
double dvir = -xvir4 * rhoinv*e_scale * (1.0/4.0);
for(int pp = 0; pp<3; pp++) {
vatom[i][pp] += dvir;
vatom[j][pp] += dvir;
vatom[k][pp] += dvir;
vatom[m][pp] += dvir;
}
}
fix = fix+fsave[0][0]; fiy = fiy+fsave[0][1]; fiz = fiz+fsave[0][2];
fjx = fjx+fsave[1][0]; fjy = fjy+fsave[1][1]; fjz = fjz+fsave[1][2];
fkx = fkx+fsave[2][0]; fky = fky+fsave[2][1]; fkz = fkz+fsave[2][2];
fmx = fmx+fsave[3][0]; fmy = fmy+fsave[3][1]; fmz = fmz+fsave[3][2];
}
ff[m][0] += fmx * e_scale;
ff[m][1] += fmy * e_scale;
ff[m][2] += fmz * e_scale;
}
}
mj = mj + 1;
mk = mk + 1;
} else if(nlist_short[mj] < nlist_short[mk]) {
mj = mj + 1;
} else {
mk = mk + 1;
}
}
tx1 = gettime();
tquad += tx1 - tx0;
ntquad++;
ntquaditer++;
}
ff[k][0] += fkx * e_scale;
ff[k][1] += fky * e_scale;
ff[k][2] += fkz * e_scale;
}
#undef transtrace
ff[j][0] += fjx * e_scale;
ff[j][1] += fjy * e_scale;
ff[j][2] += fjz * e_scale;
}
ff[i][0] += fix * e_scale;
ff[i][1] += fiy * e_scale;
ff[i][2] += fiz * e_scale;
if(single_energies == 1 && i < nloc) {
const double evol0 = splinepot.evol0;
if(eflag_global) {
e_single = e_single + evol0 * e_scale;
eng_vdwl = eng_vdwl + evol0 * e_scale;
}
if(eflag_atom) eatom[i] = eatom[i] + evol0 * e_scale;
if(volpres_flag && vflag_atom) {
for(int pp = 0; pp<3; pp++)
vatom[i][pp] = vatom[i][pp] - rhoinv*splinepot.devol0*e_scale;
}
}
}
tx0 = gettime();
for(i = 0; i<ntot; i++)
for(p = 0; p<3; p++)
atom->f[i][p] = atom->f[i][p] + ff[i][p];
memory->sfree(nlist_short);
memory->sfree(first);
if(ss != xx) memory->sfree(ss);
memory->sfree(ff);
memory->sfree(xx);
tx1 = gettime();
tmem += tx1-tx0;
ntmem++;
t1 = gettime(1);
//printf("compute_x: c_p = %d c_t = %d c_q = %d\n",c_p,c_t,c_q);
#ifdef TIMING_ON
if(comm->me == 0) {
double tsum = (tmem+tsort+tpair+tlookup+ttriplet+tquad);
double nsum = (ntmem+ntsort+ntpair+ntlookup+nttriplet+ntquad);
//double adj = ((t1-t0)-tsum)/nsum;
/* Use adj = 6ns for RDTSC, and 58ns for gettimeofday,
on monkfish.llnl.gov, 2.4GHz Intel
Use adj = 35.945ns for RDTSC on uBGL (assumed rate set to 700MHz)
*/
double adj = 35.945e-9;
double
memadj = tmem - adj*ntmem ,
sortadj = tsort - adj*ntsort ,
pairadj = tpair - adj*ntpair ,
lookupadj = tlookup - adj*ntlookup ,
tripletadj = ttriplet - adj*nttriplet,
quadadj = tquad - adj*ntquad ,
make_b_adj = t_make_b - adj*n_make,
make_t_adj = t_make_t - adj*n_make,
make_b2_adj = t_make_b2 - adj*n_make_b2,
trace_adj = t_trace - adj*n_trace;
printf("mgpt engy = %10.3fms\n",(t1-t0)*1e3);
printf(" mem = %10.3fms n = %8.0f adj = %10.3fms one = %10.3fns\n",
tmem*1e3,ntmem,memadj*1e3,memadj/ntmem*1e9);
printf(" sort = %10.3fms n = %8.0f adj = %10.3fms one = %10.3fns\n",
tsort*1e3,ntsort,sortadj*1e3,sortadj/ntsort*1e9);
printf(" pair = %10.3fms n = %8.0f adj = %10.3fms one = %10.3fns\n",
tpair*1e3,ntpair,pairadj*1e3,pairadj/ntpair*1e9);
printf(" lookup = %10.3fms n = %8.0f adj = %10.3fms one = %10.3fns\n",
tlookup*1e3,ntlookup,lookupadj*1e3,lookupadj/ntlookup*1e9);
printf(" triplet = %10.3fms n = %8.0f adj = %10.3fms one = %10.3fns\n",
ttriplet*1e3,nttriplet,tripletadj*1e3,tripletadj/nttriplet*1e9);
printf(" quad = %10.3fms n = %8.0f adj = %10.3fms one = %10.3fns\n",
tquad*1e3,ntquaditer,quadadj*1e3,quadadj/ntquaditer*1e9);
printf(" sum = %10.3fms adj = %10.3fms\n",
tsum*1e3,(tsum - adj*nsum)*1e3);
printf("\n make_b = %10.3fms n = %8.0f adj = %10.3fms one = %10.3fns\n",
t_make_b*1e3,n_make,make_b_adj*1e3,make_b_adj/n_make*1e9);
printf(" make_b2 = %10.3fms n = %8.0f adj = %10.3fms one = %10.3fns\n",
t_make_b2*1e3,n_make_b2,make_b2_adj*1e3,make_b2_adj/n_make_b2*1e9);
printf(" make_t = %10.3fms n = %8.0f adj = %10.3fms one = %10.3fns\n\n",
t_make_t*1e3,n_make,make_t_adj*1e3,make_t_adj/n_make*1e9);
printf(" trace = %10.3fms n = %8.0f adj = %10.3fms one = %10.3fns\n\n",
t_trace*1e3,n_trace,trace_adj*1e3,trace_adj/n_trace*1e9);
printf("mcount (transpose + trace for triplet) = %.0f , %.0f qcount = %.0f lmax = %d\n",
mcount,mcount2,qcount,lmax);
printf("nbc=%.0f tbl=%.3fms tbm=%.3fms one tbl=%.3fns one tbm=%.3fns\n",
nbc,(tbl-adj*nbc)*1e3,(tbm-adj*nbc)*1e3,(tbl/nbc-adj)*1e9,
(tbm/nbc-adj)*1e9);
printf("\n\nForces:\n");
printf("fix = %.3f fiy=%.3f fiz=%.3f\n",fix,fiy,fiz);
printf("fjx = %.3f fjy=%.3f fjz=%.3f\n",fjx,fjy,fjz);
printf("fkx = %.3f fky=%.3f fkz=%.3f\n",fkx,fky,fkz);
printf("\n");
printf("Bonds : nsearch=%d maxlen=%d avg.len=%.3f\n",
bond_hash.NSearch(),bond_hash.MaxLength(),
bond_hash.NStep()/(double) bond_hash.NSearch());
printf("compute_x: c_p = %d c_t = %d c_q = %d\n",c_p,c_t,c_q);
printf("@@ Total number of trace3 calls is %d, total number of make_triplet is %.1f\n",
ntr_calls,n_make);
{
Hash<bond_data,Doublet>::Iterator iter = bond_hash.begin();
int nitem = 0,nhit = 0;
while(iter != bond_hash.end()) {
nitem++;
nhit += iter.link()->hits;
iter.next();
}
printf("bond_hash hits: nitems=%d nhits=%d hits/item = %.3f\n",
nitem,nhit,nhit/(double) nitem);
}
}
#endif
if(volpres_flag) {
/*
Include contributions to the pressure due to derivatines
of the energy with respect to the potential input volume.
*/
/* The following lines have moved to beginning of functions,
since they are used in calculating per-atom virial contributions */
/*
double vtot = 1.0;
double ntot = atom->natoms;
for(i = 0; i<3; i++)
vtot = vtot * (domain->boxhi[i] - domain->boxlo[i]);
double rhoinv = vtot / ntot;
*/
if(single_energies) // Virial correction for self energy
for(i = 0; i<3; i++) {
//virial[i] = virial[i] + nloc*pot_input_vol*pvol0*e_scale;
virial[i] = virial[i] - nloc*rhoinv*splinepot.devol0*e_scale;
}
if(pair_energies) // Virial correction for pair energy
for(i = 0; i<3; i++)
virial[i] = virial[i] + rhoinv*e_scale*volvir2;
if(three_body_energies) // Virial correction for three body enegries
for(i = 0; i<3; i++) {
//virial[i] = virial[i] - pot_input_vol*(e_triplet_c*pc + (e_triplet-e_triplet_c)*pd);
virial[i] = virial[i] - (vir3v + vir3t) * rhoinv*e_scale;
}
if(four_body_energies) // Virial correction for four body enegries
for(i = 0; i<3; i++) {
//virial[i] = virial[i] - pot_input_vol*e_quad*pe;
virial[i] = virial[i] - vir4 * rhoinv*e_scale;
}
}
*e_s = e_single;
*e_p = e_pair;
*e_t = e_triplet;
*e_q = e_quad;
}
void PairMGPT::compute(int eflag, int vflag)
{
if(eflag || vflag) ev_setup(eflag, vflag);
else evflag = vflag_fdotr = eflag_global = vflag_global = eflag_atom = vflag_atom = 0;
int newton_pair = force->newton_pair;
double e_s,e_p,e_t,e_q;
//printf("newton_pair = %d, newton = %d, tag_enable = %d\n",force->newton_pair,force->newton,atom->tag_enable);
if(newton_pair == 0) {
printf("This is a problem. MGPT requires newton_pair flag to be on. Exiting...\n");
exit(1);
}
if(atom->tag_enable == 0) {
printf("This is a problem. MGPT requires tag_enable flag to be on. Exiting...\n");
exit(1);
}
compute_x(listfull->numneigh,listfull->firstneigh,&e_s,&e_p,&e_t,&e_q,evflag,newton_pair);
if(0) { // Stupid force calculation / verification
int ii,nmax=-1;
for(ii = 0; ii<listfull->inum + listfull->gnum; ii++) {
int i = listfull->ilist[ii];
if(i > nmax) nmax = i;
}
nmax++;
double *ffwork = new double[3*nmax];
double *ffloc = new double[3*listfull->inum];
double *ffloc2 = new double[3*listfull->inum];
double **ffptr = new double *[nmax];
for(ii = 0; ii<listfull->inum + listfull->gnum; ii++)
ffptr[ii] = &ffwork[3*ii];
printf("Computing boundary forces\n");
for(ii = 0; ii<listfull->inum; ii++) {
ffloc2[3*ii] = 0.0;
ffloc2[3*ii+1] = 0.0;
ffloc2[3*ii+2] = 0.0;
int i = listfull->ilist[ii];
for(int jj = 0; jj<listfull->inum+listfull->gnum; jj++) {
int j = listfull->ilist[jj];
if(atom->tag[i] == atom->tag[j])
for(int p = 0; p<3; p++)
ffloc2[3*ii+p] += atom->f[j][p];
}
}
printf("Starting main displacement force calculation\n");
for(ii = 0; ii<listfull->inum; ii++) {
int i = listfull->ilist[ii];
double **atom_f_save = atom->f;
atom->f = ffptr;
for(int p = 0; p<3; p++) {
double xsave = atom->x[i][p];
const double delta = 1e-3;
atom->x[i][p] = xsave + delta;
for(int jj = 0; jj<3*nmax; jj++) ffwork[jj] = 0.0;
compute_x(listfull->numneigh,
listfull->firstneigh,
&e_s,&e_p,&e_t,&e_q,evflag,newton_pair);
double e1 = e_s + e_p + e_t + e_q;
atom->x[i][p] = xsave - delta;
for(int jj = 0; jj<3*nmax; jj++) ffwork[jj] = 0.0;
compute_x(listfull->numneigh,
listfull->firstneigh,
&e_s,&e_p,&e_t,&e_q,evflag,newton_pair);
double e2 = e_s + e_p + e_t + e_q;
ffloc[3*ii+p] = -(e1-e2)/(2*delta);
atom->x[i][p] = xsave;
}
atom->f = atom_f_save;
printf("Force on i=%4d:\n",i);
printf(" Position %20.10e %20.10e %20.10e\n",
atom->x[i][0],atom->x[i][1],atom->x[i][2]);
printf(" Exact %20.10e %20.10e %20.10e\n",
atom->f[i][0],atom->f[i][1],atom->f[i][2]);
printf(" Numerical %20.10e %20.10e %20.10e\n",
ffloc[3*ii+0],ffloc[3*ii+1],ffloc[3*ii+2]);
printf(" Boundary %20.10e %20.10e %20.10e\n",
ffloc2[3*ii+0],ffloc2[3*ii+1],ffloc2[3*ii+2]);
}
delete[] ffloc2;
delete[] ffloc;
delete[] ffptr;
delete[] ffwork;
}
if(0) {
printf("\nForces MGPT:\n");
const int iimax = (listfull->inum < 10) ? listfull->inum : 10;
for(int ii = 0; ii<iimax; ii++) {
int i = listfull->ilist[ii];
printf("%4d = %20.10e %20.10e %20.10e\n",
i,atom->f[i][0],atom->f[i][1],atom->f[i][2]);
}
printf("\n\n");
}
if(vflag_fdotr) {
//printf("##### Using virial_compute!!!\n");
virial_fdotr_compute();
}
}
void PairMGPT::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for(int i = 0; i <= n; i++)
for(int j = 0; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cutghost,n+1,n+1,"pair:cutsq");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairMGPT::settings(int narg, char **arg)
{
if(narg != 0) error->all(__FILE__,__LINE__,"Illegal pair_style command");
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairMGPT::coeff(int narg, char **arg)
{
int single_precision = 0;
if(narg < 5)
error->all(__FILE__,__LINE__,
"Not enough arguments for mgpt (MGPT) pair coefficients.");
if(!allocated) allocate();
// Make sure I,J args are * *
if(strcmp(arg[0],"*") != 0 || strcmp(arg[1],"*") != 0)
error->all(__FILE__,__LINE__,"Incorrect args for pair coefficients");
double vol;
if(sscanf(arg[4], "%lg", &vol) != 1 || vol <= 0.0)
error->all(__FILE__,__LINE__,"Invalid volume in mgpt (MGPT) pair coefficients.");
volpres_flag = 1;
single_precision = 0;
/* Parse arguments */ {
int volpres_tag = 0,precision_tag = 0,nbody_tag = 0;
int iarg = 5;
while (iarg < narg) {
if(strcmp(arg[iarg],"volpress") == 0) { /* Volumetric pressure flag */
if (iarg+2 > narg)
error->all(FLERR,"Incorrect args for pair coefficients");
if(strcmp(arg[iarg+1],"yes") == 0) volpres_flag = 1;
else if(strcmp(arg[iarg+1],"no") == 0) volpres_flag = 0;
else {
char line[1024];
sprintf(line,"(In %s:%d) Invalid value for volumetric pressure argument.\n"
"It should be \"volpress yes\" or \"volpress no\".\n"
"The value is \"%s\".\n",__FILE__,__LINE__,arg[iarg+1]);
error->all(__FILE__,__LINE__,line);
}
volpres_tag = 1;
iarg += 2;
if(comm->me == 0) printf("* volpress: volpres_flag = %d [%s %s]\n",volpres_flag,arg[iarg-2],arg[iarg-1]);
} else if(strcmp(arg[iarg],"nbody") == 0) {
if (iarg+2 > narg)
error->all(FLERR,"Incorrect args for pair coefficients");
if(strspn(arg[iarg+1],"1234") == strlen(arg[iarg+1])) {
nbody_flag = 0;
for(int i = 0; i<4; i++)
if(strchr(arg[iarg+1],'1'+i) != NULL) {
nbody_flag = nbody_flag + (1<<i);
if(comm->me == 0) printf("Explicitly adding %d-tuple forces.\n",i+1);
}
} else {
char line[1024];
sprintf(line,"(In %s:%d) Invalid value for nbody flag.\n"
"It should be e.g. \"nbody=1234\" (for single, pair, triple, and quad forces/energiers)\n"
"For e.g. only pair and triple forces/energies, use \"nbody=23\".\n"
"The default is \"nbody=1234\".\n"
"The current value is \"%s\".\n",__FILE__,__LINE__,arg[iarg+1]);
error->all(__FILE__,__LINE__,line);
}
nbody_tag = 1;
iarg += 2;
} else if(strcmp(arg[iarg],"precision") == 0) {
if (iarg+2 > narg)
error->all(FLERR,"Incorrect args for pair coefficients");
if(strcmp(arg[iarg+1],"single") == 0) single_precision = 1;
else if(strcmp(arg[iarg+1],"double") == 0) single_precision = 0;
else {
char line[1024];
sprintf(line,"(In %s:%d) Invalid value for precision argument.\n"
"It should be \"precision single\" or \"precision double\".\n"
"The value is \"%s\".\n",__FILE__,__LINE__,arg[iarg+1]);
error->all(__FILE__,__LINE__,line);
}
precision_tag = 1;
iarg += 2;
if(comm->me == 0) printf("* precision: single_flag = %d [%s %s]\n",single_precision,arg[iarg-2],arg[iarg-1]);
} else {
char line[1024];
sprintf(line,"(In %s:%d) Invalid argument. Allowed arguments are:\n"
" volpress {yes|no} , default = yes\n"
" precision {single|double} , default = double\n"
" nbody {[1234,]*} , default = whichever terms potential require\n"
"The invalid argument is \"%s\".\n",__FILE__,__LINE__,arg[iarg]);
error->all(__FILE__,__LINE__,line);
}
}
if(comm->me == 0)
printf("Volumetric pressure is %s.\n",volpres_flag ? "on" : "off");
if(comm->me == 0) {
FILE *parmin_fp = force->open_potential(arg[2]);
FILE *potin_fp = force->open_potential(arg[3]);
if (parmin_fp == NULL || potin_fp == NULL) {
char str[128];
sprintf(str,"Cannot open MGPT potential files %s %s",arg[2],arg[3]);
error->one(FLERR,str);
}
fclose(parmin_fp);
fclose(potin_fp);
splinepot.readpot(arg[2],arg[3],vol);
printf("evol0 = %.10e\n",splinepot.evol0);
/* Set up default and requested nbody forces to include */ {
int nbody_default = (1<<0) + (1<<1) + (1<<2) + (1<<3);
if(splinepot.vd == 0.0 && splinepot.dvd == 0.0)
nbody_default -= (1<<2); // No 3-body contributions
if(splinepot.ve == 0.0 && splinepot.dve == 0.0)
nbody_default -= (1<<3); // No 4-body contributions
if(nbody_tag == 0) nbody_flag = nbody_default;
if(nbody_flag != nbody_default) {
printf("Warning: nbody=%d (suggested=%d) set to disregard multibody-forces in potential.\n",
nbody_flag,nbody_default);
}
}
}
}
MPI_Bcast(&nbody_flag,sizeof(nbody_flag),MPI_BYTE,0,world);
/*
Broadcast structure to all processes. In receiving
processes, pointes will be screwed up. We allocate
memory, and then broadcast contents of arrays.
*/
MPI_Bcast(&splinepot,sizeof(splinepot),MPI_BYTE,0,world);
if(comm->me != 0) {
splinepot.vpair_spline = new double[splinepot.nr-1][4];
splinepot.dvpair_spline = new double[splinepot.nr-1][4];
}
MPI_Bcast(splinepot.vpair_spline,4*(splinepot.nr-1),MPI_DOUBLE,0,world);
MPI_Bcast(splinepot.dvpair_spline,4*(splinepot.nr-1),MPI_DOUBLE,0,world);
anorm3 = splinepot.anorm3;
anorm4 = splinepot.anorm4;
lmax = splinepot.lmax;
lang = splinepot.lang;
//ipot = splinepot.ipot;
for(int i = 0; i<(int) (sizeof(ddl)/sizeof(double)); i++)
ddl[i] = splinepot.ddl[i];
for(int i = 0; i<lmax; i++) {
for(int j = 0; j<lmax; j++)
del0.m[i+1][j+1] = 0.0;
del0.m[i+1][i+1] = 1.0;
}
/* Set matrix param, cutoff, LAMMPS param */
Matrix::sz = lmax;
rcrit = splinepot.rcrit;
rmax = splinepot.rmax;
cutoff = rmax;
if(rcrit > rmax) cutoff = rcrit;
// Set LAMMPS pair interaction flags.
for(int i = 1; i <= atom->ntypes; i++) {
for(int j = 1; j <= atom->ntypes; j++) {
setflag[i][j] = 1;
cutsq[i][j] = cutoff;
cutghost[i][j] = cutoff;
}
}
// Set atomic mass.
for(int i = 1; i <= atom->ntypes; i++)
atom->set_mass(FLERR,i, splinepot.mass);
// Initialize linear algebra routines.
linalg = mgpt_linalg(lmax,single_precision);
if(comm->me == 0)
printf("%s",linalg.msg);
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairMGPT::init_style()
{
if(force->newton_pair == 0)
error->all(__FILE__,__LINE__,"Pair style mgpt requires newton pair on.");
// Need full neighbor list.
int irequest_full = neighbor->request(this);
neighbor->requests[irequest_full]->id = 1;
neighbor->requests[irequest_full]->half = 0;
neighbor->requests[irequest_full]->full = 1;
neighbor->requests[irequest_full]->ghost = 1;
// Also need half neighbor list.
int irequest_half = neighbor->request(this);
neighbor->requests[irequest_half]->id = 2;
neighbor->requests[irequest_half]->half = 0;
neighbor->requests[irequest_half]->half_from_full = 1;
neighbor->requests[irequest_half]->otherlist = irequest_full;
}
/* ----------------------------------------------------------------------
neighbor callback to inform pair style of neighbor list to use
half or full
------------------------------------------------------------------------- */
void PairMGPT::init_list(int id, NeighList *ptr)
{
if(id == 1) listfull = ptr;
else if(id == 2) listhalf = ptr;
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairMGPT::init_one(int i, int j)
{
return cutoff;
}
/************************************************************************
**** REIMPLEMENTATION OF FL AND HAMLTN WITH ANALYTICAL DERIVATIVES ****
************************************************************************/
/*
Reimplementation of bond length potential, including
derivatives with respect to x,y, and z.
*/
void PairMGPT::fl_deriv_new(double r,double ri,double xhat,double yhat,double zhat,
double &fl_0,double &fl_x,double &fl_y,double &fl_z,
double &fl_rp,double &fl_p1,double &fl_r0,double &fl_al) {
const double rp = splinepot.rp,p1 = splinepot.p1,r0 = splinepot.r00,al = splinepot.al;
const int mode = splinepot.mode;
const double pn = splinepot.pn;
double t,tx,ty,tz,t_rp_ti,t_p1_ti;
double s;
/*
// Original code
double term;
double pn=1.0;
if (mode <= 4)
term = pow(rp/r, p1);
else
term = exp(-p1*(pow(r/rp, pn) - 1.0)/pn);
*/
double rpi = 1.0/rp;
if(mode <= 4) {
t = pow(rp*ri,p1);
s = -p1 * t * ri;
t_rp_ti = p1*rpi;
t_p1_ti = log(rp*ri);
} else {
if(pn == 1.0) {
double p1_rpi = -p1*rpi;
t = exp(p1 + r*p1_rpi);
s = p1_rpi * t;
t_rp_ti = -r*p1_rpi*rpi;
t_p1_ti = 1.0 - r*rpi;
} else {
double pni = 1.0/pn;
double rprpn = pow(r*rpi,pn);
t = exp(-p1*pni*(rprpn - 1.0));
s = -p1*rprpn*ri * t;
t_rp_ti = p1*rprpn*rpi;
t_p1_ti = pni - pni*rprpn;// -pni*(rprpn - 1.0);
}
}
tx = s * xhat;
ty = s * yhat;
tz = s * zhat;
fl_rp = t_rp_ti;
fl_p1 = t_p1_ti;
if (r <= r0) {
fl_0 = t;
fl_x = tx;
fl_y = ty;
fl_z = tz;
fl_r0 = 0.0;
fl_al = 0.0;
} else {
double q,qx,qy,qz,exp_q,q_r0,q_al;
double r0i,u;
r0i = 1.0/r0;
u = r*r0i - 1.0;
q = al*u*u;
s = 2*al*u*r0i;
qx = s * xhat;
qy = s * yhat;
qz = s * zhat;
q_r0 = -2.0*al*u*r*r0i*r0i;
q_al = u*u;
exp_q = exp(-q);
if(mode <= 2) {
fl_0 = exp_q * t;
fl_x = exp_q*(tx - t*qx);
fl_y = exp_q*(ty - t*qy);
fl_z = exp_q*(tz - t*qz);
fl_r0 = -q_r0;
fl_al = -q_al;
} else {
fl_0 = exp_q * (1.0 + q) * t;
fl_x = exp_q * (tx + q*(tx - t*qx));
fl_y = exp_q * (ty + q*(ty - t*qy));
fl_z = exp_q * (tz + q*(tz - t*qz));
fl_r0 = -q_r0 * q/(1.0 + q);
fl_al = -q_al * q/(1.0 + q);
}
}
}
/*
Macros to build elements of the bond matrix, and also
its derivatives with repsect to x,y, and z.
*/
#define MAKE_ELEMENT_5(i,j) \
do { \
const double dl0 = del0.m[i][j]; \
const double dl4 = gsl_##i * gsl_##j; \
const double dl4x = gsl_##i##x * gsl_##j + gsl_##i * gsl_##j##x; \
const double dl4y = gsl_##i##y * gsl_##j + gsl_##i * gsl_##j##y; \
const double dl4z = gsl_##i##z * gsl_##j + gsl_##i * gsl_##j##z; \
\
const double tmp = w4*dl4 + w2*dl2 + w0*dl0; \
const double tmpx = w4*dl4x + w2*dl2x; \
const double tmpy = w4*dl4y + w2*dl2y; \
const double tmpz = w4*dl4z + w2*dl2z; \
const double tmpsum = tmpx*x + tmpy*y + tmpz*z; \
M [j][i] = M[i][j] = fl *tmp; \
Mx[j][i] = Mx[i][j] = fl_x*tmp + fl_ri*(tmpx - x*tmpsum); \
My[j][i] = My[i][j] = fl_y*tmp + fl_ri*(tmpy - y*tmpsum); \
Mz[j][i] = Mz[i][j] = fl_z*tmp + fl_ri*(tmpz - z*tmpsum); \
} while(0)
#define MAKE_ELEMENT_7(i,j) \
do { \
const double dl0 = del0.m[i][j]; \
const double dl6 = gsl_##i * gsl_##j; \
const double dl6x = gsl_##i##x * gsl_##j + gsl_##i * gsl_##j##x; \
const double dl6y = gsl_##i##y * gsl_##j + gsl_##i * gsl_##j##y; \
const double dl6z = gsl_##i##z * gsl_##j + gsl_##i * gsl_##j##z; \
\
const double tmp = w6*dl6 + w4*dl4 + w2*dl2 + w0*dl0; \
const double tmpx = w6*dl6x + w4*dl4x + w2*dl2x; \
const double tmpy = w6*dl6y + w4*dl4y + w2*dl2y; \
const double tmpz = w6*dl6z + w4*dl4z + w2*dl2z; \
const double tmpsum = tmpx*x + tmpy*y + tmpz*z; \
M [j][i] = M[i][j] = fl *tmp; \
Mx[j][i] = Mx[i][j] = fl_x*tmp + fl_ri*(tmpx - x*tmpsum); \
My[j][i] = My[i][j] = fl_y*tmp + fl_ri*(tmpy - y*tmpsum); \
Mz[j][i] = Mz[i][j] = fl_z*tmp + fl_ri*(tmpz - z*tmpsum); \
} while(0)
/* End of bond matrix macros */
/*
Construction of bond matrix, and its derivatives
with respect to the coordinates
*/
void PairMGPT::hamltn_5_raw(const double xin,const double yin,const double zin,
double M [8][8],double Mx[8][8],
double My[8][8],double Mz[8][8],
double *fl_deriv_sum_p) {
const double r = sqrt(xin*xin + yin*yin + zin*zin),ri = 1.0/r;
const double x = xin*ri,y = yin*ri,z = zin*ri;
// d-d
// call delndd(x,y,z)
const double x2 = x*x,y2 = y*y,z2 = z*z;
const double xy = x*y,xz = x*z,yz = y*z;
const double sr3 = sqrt(3.0),sr3i = 1.0/sr3;
const double frac_1_3 = 1.0/3.0,frac_2_3 = 2.0/3.0,frac_4_3 = 4.0/3.0;
const double ddl_1 = ddl[1],ddl_2 = ddl[2],ddl_3 = ddl[3];
const double w4 = ddl_1 - frac_4_3*ddl_2 + frac_1_3*ddl_3;
const double w2 = ddl_2 - ddl_3;
const double w0 = ddl_2;
//del4
double gsl_1 ,gsl_2 ,gsl_3 ,gsl_4 ,gsl_5;
double gsl_1x,gsl_2x,gsl_3x,gsl_4x,gsl_5x;
double gsl_1y,gsl_2y,gsl_3y,gsl_4y,gsl_5y;
double gsl_1z,gsl_2z,gsl_3z,gsl_4z,gsl_5z;
double dl2,dl2x,dl2y,dl2z;
double fl,fl_x,fl_y,fl_z,fl_ri;
double fl_rp,fl_p1,fl_r0,fl_al;
gsl_1 = 0.5*(3.0*z2 - 1.0);
gsl_1x = 0.0;
gsl_1y = 0.0;
gsl_1z = 3.0*z;
gsl_2 = sr3*xz;
gsl_2x = sr3*z;
gsl_2y = 0.0;
gsl_2z = sr3*x;
gsl_3 = sr3*yz;
gsl_3x = 0.0;
gsl_3y = sr3*z;
gsl_3z = sr3*y;
gsl_4 = sr3*(x2 - y2)*0.5;
gsl_4x = sr3*x;
gsl_4y = -sr3*y;
gsl_4z = 0.0;
gsl_5 = sr3*xy;
gsl_5x = sr3*y;
gsl_5y = sr3*x;
gsl_5z = 0.0;
// Compute bond length potential
fl_deriv_new(r,ri,x,y,z,fl,fl_x,fl_y,fl_z , fl_rp,fl_p1,fl_r0,fl_al);
fl_ri = fl*ri;
*fl_deriv_sum_p =
fl_rp*splinepot.drp + fl_p1*splinepot.dp1 +
fl_r0*splinepot.dr00 + fl_al*splinepot.dal;
// del2
//del2.m[1][1] = z2 - 2.0/3.0;
dl2 = z2 - frac_2_3;
dl2x = 0.0;
dl2y = 0.0;
dl2z = 2*z;
MAKE_ELEMENT_5(1,1);
//del2.m[1][2] = xz/sr3;
dl2 = xz*sr3i;
dl2x = z*sr3i;
dl2y = 0.0;
dl2z = x*sr3i;
MAKE_ELEMENT_5(1,2);
//del2.m[1][3] = yz/sr3;
dl2 = yz*sr3i;
dl2x = 0.0;
dl2y = z*sr3i;
dl2z = y*sr3i;
MAKE_ELEMENT_5(1,3);
//del2.m[1][4] = -(x2 - y2)*sr3i;
dl2 = -(x2 - y2)*sr3i;
dl2x = -2.0*sr3i*x;
dl2y = 2.0*sr3i*y;
dl2z = 0.0;
MAKE_ELEMENT_5(1,4);
//del2.m[1][5] = -2.0*xy*sr3i;
dl2 = -2.0*xy*sr3i;
dl2x = -2.0*y*sr3i;
dl2y = -2.0*x*sr3i;
dl2z = 0.0;
MAKE_ELEMENT_5(1,5);
//del2.m[2][2] = -y2;
dl2 = -y2;
dl2x = 0.0;
dl2y = -2.0*y;
dl2z = 0.0;
MAKE_ELEMENT_5(2,2);
//del2.m[2][3] = xy;
dl2 = xy;
dl2x = y;
dl2y = x;
dl2z = 0.0;
MAKE_ELEMENT_5(2,3);
//del2.m[2][4] = xz;
dl2 = xz;
dl2x = z;
dl2y = 0.0;
dl2z = x;
MAKE_ELEMENT_5(2,4);
//del2.m[2][5] = yz;
dl2 = yz;
dl2x = 0.0;
dl2y = z;
dl2z = y;
MAKE_ELEMENT_5(2,5);
//del2.m[3][3] = -x2;
dl2 = -x2;
dl2x = -2.0*x;
dl2y = 0.0;
dl2z = 0.0;
MAKE_ELEMENT_5(3,3);
//del2.m[3][4] = -yz;
dl2 = -yz;
dl2x = 0.0;
dl2y = -z;
dl2z = -y;
MAKE_ELEMENT_5(3,4);
//del2.m[3][5] = xz;
dl2 = xz;
dl2x = z;
dl2y = 0.0;
dl2z = x;
MAKE_ELEMENT_5(3,5);
//del2.m[4][4] = -z2;
dl2 = -z2;
dl2x = 0.0;
dl2y = 0.0;
dl2z = -2.0*z;
MAKE_ELEMENT_5(4,4);
//del2.m[4][5] = 0.0;
dl2 = 0.0;
dl2x = 0.0;
dl2y = 0.0;
dl2z = 0.0;
MAKE_ELEMENT_5(4,5);
//del2.m[5][5] = -z2;
dl2 = -z2;
dl2x = 0.0;
dl2y = 0.0;
dl2z = -2.0*z;
MAKE_ELEMENT_5(5,5);
}
void PairMGPT::hamltn_7_raw(const double xin,const double yin,const double zin,
double M [8][8],double Mx[8][8],
double My[8][8],double Mz[8][8],
double *fl_deriv_sum_p) {
const double r = sqrt(xin*xin + yin*yin + zin*zin),ri = 1.0/r;
const double x = xin*ri,y = yin*ri,z = zin*ri;
// d-d
// call delndd(x,y,z)
const double x2 = x*x,y2 = y*y,z2 = z*z;
const double xy = x*y,xz = x*z,yz = y*z;
const double x4 = x2*x2,y4 = y2*y2;
//const double sr3 = sqrt(3.0);//,sr3i = 1.0/sr3;
//const double frac_1_3 = 1.0/3.0,frac_2_3 = 2.0/3.0,frac_4_3 = 4.0/3.0;
const double sr01 = sqrt(0.1);
const double sr015 = sqrt(0.15);
const double sr024 = sqrt(0.24);
const double sr0375 = sqrt(0.375);
const double sr06 = sqrt(0.6);
const double sr0625 = sqrt(0.625);
const double sr09 = sqrt(0.9);
const double sr15 = sqrt(1.5);
const double sr24 = sqrt(2.4);
const double sr36 = sqrt(3.6);
const double sr375 = sqrt(3.75);
const double sr96 = sqrt(9.6);
const double sr150 = sqrt(15.0);
const double ddl_1 = ddl[1],ddl_2 = ddl[2],ddl_3 = ddl[3],ddl_4 = ddl[4];
const double w6 = ddl_1 - 1.5*ddl_2 + 0.6*ddl_3 - 0.1*ddl_4;
const double w4 = 0.625*ddl_2 - ddl_3 + 0.375*ddl_4;
const double w2 = 0.625*(ddl_2 - ddl_4);
const double w0 = 0.625*ddl_2 + 0.375*ddl_4;
//del6
double gsl_1 ,gsl_2 ,gsl_3 ,gsl_4 ,gsl_5 ,gsl_6, gsl_7;
double gsl_1x,gsl_2x,gsl_3x,gsl_4x,gsl_5x,gsl_6x,gsl_7x;
double gsl_1y,gsl_2y,gsl_3y,gsl_4y,gsl_5y,gsl_6y,gsl_7y;
double gsl_1z,gsl_2z,gsl_3z,gsl_4z,gsl_5z,gsl_6z,gsl_7z;
double dl2,dl2x,dl2y,dl2z;
double dl4,dl4x,dl4y,dl4z;
double t1;
double fl,fl_x,fl_y,fl_z,fl_ri;
double fl_rp,fl_p1,fl_r0,fl_al;
//gslf[1] = 0.5*(5.0*n2 - 3.0)*n;
gsl_1 = 0.5*(5.0*z2 - 3.0)*z;
gsl_1x = 0.0;
gsl_1y = 0.0;
gsl_1z = 7.5*z2 - 1.5;
//gslf[2] = sr0375*(5.0*n2 - 1.0)*l;
gsl_2 = sr0375*(5.0*z2 - 1.0)*x;
gsl_2x = sr0375*(5.0*z2 - 1.0);
gsl_2y = 0.0;
gsl_2z = sr0375*10.0*xz;
//gslf[3] = sr0375*(5.0*n2 - 1.0)*m;
gsl_3 = sr0375*(5.0*z2 - 1.0)*y;
gsl_3x = 0.0;
gsl_3y = sr0375*(5.0*z2 - 1.0);
gsl_3z = sr0375*10.0*yz;
//gslf[4] = sr375*(l2 - m2)*n;
gsl_4 = sr375*(x2 - y2)*z;
gsl_4x = 2.0*sr375*xz;
gsl_4y = -2.0*sr375*yz;
gsl_4z = sr375*(x2 - y2);
//gslf[5] = sr150*lm*n;
gsl_5 = sr150*xy*z;
gsl_5x = sr150*yz;
gsl_5y = sr150*xz;
gsl_5z = sr150*xy;
//gslf[6] = sr0625*(l2 - 3.0*m2)*l;
gsl_6 = sr0625*(x2 - 3.0*y2)*x;
gsl_6x = 3.0*sr0625*(x2 - y2);
gsl_6y = -6.0*sr0625*xy;
gsl_6z = 0.0;
//gslf[7] = sr0625*(3.0*l2 - m2)*m;
gsl_7 = sr0625*(3.0*x2 - y2)*y;
gsl_7x = 6.0*sr0625*xy;
gsl_7y = 3.0*sr0625*(x2 - y2);
gsl_7z = 0.0;
// Compute bond length potential
fl_deriv_new(r,ri,x,y,z,fl,fl_x,fl_y,fl_z , fl_rp,fl_p1,fl_r0,fl_al);
fl_ri = fl*ri;
*fl_deriv_sum_p =
fl_rp*splinepot.drp + fl_p1*splinepot.dp1 +
fl_r0*splinepot.dr00 + fl_al*splinepot.dal;
// del2f
//del2f.m[1][1] = 0.4*(3.0*n2 - 1.0);
dl2 = 0.4*(3.0*z2 - 1.0);
dl2x = 0.0;
dl2y = 0.0;
dl2z = 2.4*z;
//del4f.m[1][1] = 0.60*(5.0*n2 - 4.0)*n2;
dl4 = 0.60*(5.0*z2 - 4.0)*z2;
dl4x = 0.0;
dl4y = 0.0;
dl4z = 0.60*(20.0*z2 - 8.0)*z;
MAKE_ELEMENT_7(1,1);
//del2f.m[1][2] = sr024*ln;
dl2 = sr024*xz;
dl2x = sr024*z;
dl2y = 0.0;
dl2z = sr024*x;
//del4f.m[1][2] = sr024*(5.0*n2 - 2.0)*ln;
dl4 = sr024*(5.0*z2 - 2.0)*xz;
dl4x = sr024*(5.0*z2 - 2.0)*z;
dl4y = 0.0;
dl4z = sr024*(15.0*z2 - 2.0)*x;
MAKE_ELEMENT_7(1,2);
//del2f.m[1][3] = sr024*mn;
dl2 = sr024*yz;
dl2x = 0.0;
dl2y = sr024*z;
dl2z = sr024*y;
//del4f.m[1][3] = sr024*(5.0*n2 - 2.0)*mn;
dl4 = sr024*(5.0*z2 - 2.0)*yz;
dl4x = 0.0;
dl4y = sr024*(5.0*z2 - 2.0)*z;
dl4z = sr024*(15.0*z2 - 2.0)*y;
MAKE_ELEMENT_7(1,3);
//del2f.m[1][4] = -sr06*(l2 - m2);
dl2 = -sr06*(x2 - y2);
dl2x = -2.0*sr06*x;
dl2y = 2.0*sr06*y;
dl2z = 0.0;
//del4f.m[1][4] = -sr06*(l2 - m2)*n2;
dl4 = -sr06*(x2 - y2)*z2;
dl4x = -2.0*sr06*x*z2;
dl4y = 2.0*sr06*y*z2;
dl4z = -2.0*sr06*(x2 - y2)*z;
MAKE_ELEMENT_7(1,4);
//del2f.m[1][5] = -sr24*lm;
dl2 = -sr24*xy;
dl2x = -sr24*y;
dl2y = -sr24*x;
dl2z = 0.0;
//del4f.m[1][5] = -sr24*lm*n2;
dl4 = -sr24*xy*z2;
dl4x = -sr24*y*z2;
dl4y = -sr24*x*z2;
dl4z = -2.0*sr24*xy*z;
MAKE_ELEMENT_7(1,5);
//del2f.m[1][6] = 0.0;
dl2 = 0.0;
dl2x = 0.0;
dl2y = 0.0;
dl2z = 0.0;
//del4f.m[1][6] = sr36*(3.0*m2 - l2)*ln;
dl4 = sr36*(3.0*y2 - x2)*xz;
dl4x = 3.0*sr36*(y2 - x2)*z;
dl4y = 6.0*sr36*y*xz;
dl4z = sr36*(3.0*y2 - x2)*x;
MAKE_ELEMENT_7(1,6);
//del2f.m[1][7] = 0.0;
dl2 = 0.0;
dl2x = 0.0;
dl2y = 0.0;
dl2z = 0.0;
//del4f.m[1][7] = -sr36*(3.0*l2 - m2)*mn;
dl4 = -sr36*(3.0*x2 - y2)*yz;
dl4x = -6.0*sr36*x*yz;
dl4y = -3.0*sr36*(x2 - y2)*z;
dl4z = -sr36*(3.0*x2 - y2)*y;
MAKE_ELEMENT_7(1,7);
//del2f.m[2][2] = 0.3*(1.0 - 4.0*m2 + n2);
dl2 = 0.3 - 1.2*y2 + 0.3*z2;
dl2x = 0.0;
dl2y = -2.4*y;
dl2z = 0.6*z;
//del4f.m[2][2] = -0.4*l*l - 2.5*(m2 - 0.6*l2)*n2;
dl4 = -0.4*x2 - 2.5*(y2 - 0.6*x2)*z2;
dl4x = -0.8*x + 3.0*x*z2;
dl4y = -5.0*y*z2;
dl4z = -5.0*(y2 - 0.6*x2)*z;
MAKE_ELEMENT_7(2,2);
//del2f.m[2][3] = 1.2*lm;
dl2 = 1.2*xy;
dl2x = 1.2*y;
dl2y = 1.2*x;
dl2z = 0.0;
//del4f.m[2][3] = 0.4*(10.0*n2 - 1.0)*lm;
dl4 = (4.0*z2 - 0.4)*xy;
dl4x = (4.0*z2 - 0.4)*y;
dl4y = (4.0*z2 - 0.4)*x;
dl4z = 8.0*z*xy;
MAKE_ELEMENT_7(2,3);
//del2f.m[2][4] = sr09*ln;
dl2 = sr09*xz;
dl2x = sr09*z;
dl2y = 0.0;
dl2z = sr09*x;
//del4f.m[2][4] = sr01*(6.0*n2 - 8.0*m2 - 1.0)*ln;
dl4 = sr01*(6.0*z2 - 8.0*y2 - 1.0)*xz;
dl4x = sr01*(6.0*z2 - 8.0*y2 - 1.0)*z;
dl4y = -16.0*sr01*y*xz;
dl4z = sr01*(18.0*z2 - 8.0*y2 - 1.0)*x;
MAKE_ELEMENT_7(2,4);
//del2f.m[2][5] = sr09*mn;
dl2 = sr09*yz;
dl2x = 0.0;
dl2y = sr09*z;
dl2z = sr09*y;
//del4f.m[2][5] = sr01*(2.0*n2 - 8.0*m2 + 3.0)*mn;
dl4 = sr01*(2.0*z2 - 8.0*y2 + 3.0)*yz;
dl4x = 0.0;
dl4y = sr01*(2.0*z2 - 24.0*y2 + 3.0)*z;
dl4z = sr01*(6.0*z2 - 8.0*y2 + 3.0)*y;
MAKE_ELEMENT_7(2,5);
//del2f.m[2][6] = -sr015*(l2 - m2);
dl2 = -sr015*(x2 - y2);
dl2x = -2.0*sr015*x;
dl2y = 2.0*sr015*y;
dl2z = 0.0;
//del4f.m[2][6] = sr375*(l2 - m2 - 1.4*l4 + 1.2*l2*m2 + m4);
dl4 = sr375*(x2 - y2 - 1.4*x4 + 1.2*x2*y2 + y4);
dl4x = sr375*(2.0 - 5.6*x2 + 2.4*y2)*x;
dl4y = sr375*(-2.0 + 2.4*x2 + 4.0*y2)*y;
dl4z = 0.0;
MAKE_ELEMENT_7(2,6);
//del2f.m[2][7] = -sr06*lm;
dl2 = -sr06*xy;
dl2x = -sr06*y;
dl2y = -sr06*x;
dl2z = 0.0;
//del4f.m[2][7] = sr96*(n2 - l2 + 0.25)*lm;
dl4 = sr96*(z2 - x2 + 0.25)*xy;
dl4x = sr96*(z2 - 3.0*x2 + 0.25)*y;
dl4y = sr96*(z2 - x2 + 0.25)*x;
dl4z = 2.0*sr96*z*xy;
MAKE_ELEMENT_7(2,7);
//del2f.m[3][3] = 0.30*(1.0 - 4.0*l2 + n2);
dl2 = 0.3 - 1.2*x2 + 0.3*z2;
dl2x = -2.4*x;
dl2y = 0.0;
dl2z = 0.6*z;
//del4f.m[3][3] = -0.4*m2 - 2.5*(l2 - 0.6*m2)*n2;
dl4 = -0.4*y2 - 2.5*(x2 - 0.6*y2)*z2;
dl4x = -5.0*x*z2;
dl4y = y*(3.0*z2 - 0.8);
dl4z = -5.0*(x2 - 0.6*y2)*z;
MAKE_ELEMENT_7(3,3);
//del2f.m[3][4] = -sr09*mn;
dl2 = -sr09*yz;
dl2x = 0.0;
dl2y = -sr09*z;
dl2z = -sr09*y;
//del4f.m[3][4] = -sr01*(6.0*n2 - 8.0*l2 - 1.0)*mn;
dl4 = -sr01*(6.0*z2 - 8.0*x2 - 1.0)*yz;
dl4x = 16.0*sr01*x*yz;
dl4y = -sr01*(6.0*z2 - 8.0*x2 - 1.0)*z;
dl4z = -sr01*(18.0*z2 - 8.0*x2 - 1.0)*y;
MAKE_ELEMENT_7(3,4);
//del2f.m[3][5] = sr09*ln;
dl2 = sr09*xz;
dl2x = sr09*z;
dl2y = 0.0;
dl2z = sr09*x;
//del4f.m[3][5] = sr01*(2.0*n2 - 8.0*l2 + 3.0)*ln;
dl4 = sr01*(2.0*z2 - 8.0*x2 + 3.0)*xz;
dl4x = sr01*(2.0*z2 - 24.0*x2 + 3.0)*z;
dl4y = 0.0;
dl4z = sr01*(6.0*z2 - 8.0*x2 + 3.0)*x;
MAKE_ELEMENT_7(3,5);
//del2f.m[3][6] = sr06*lm;
dl2 = sr06*xy;
dl2x = sr06*y;
dl2y = sr06*x;
dl2z = 0.0;
//del4f.m[3][6] = sr96*(m2 - n2 - 0.25)*lm;
dl4 = sr96*(y2 - z2 - 0.25)*xy;
dl4x = sr96*(y2 - z2 - 0.25)*y;
dl4y = sr96*(3.0*y2 - z2 - 0.25)*x;
dl4z = -2.0*sr96*z*xy;
MAKE_ELEMENT_7(3,6);
//del2f.m[3][7] = -sr015*(l2 - m2);
dl2 = -sr015*(x2 - y2);
dl2x = -2.0*sr015*x;
dl2y = 2.0*sr015*y;
dl2z = 0.0;
//del4f.m[3][7] = sr375*(l2 - m2 + 1.4*m4 - 1.2*l2*m2 - l4);
dl4 = sr375*(x2 - y2 + 1.4*y4 - 1.2*x2*y2 - x4);
dl4x = sr375*(2.0 - 2.4*y2 - 4.0*x2)*x;
dl4y = sr375*(-2.0 + 5.6*y2 - 2.4*x2)*y;
dl4z = 0.0;
MAKE_ELEMENT_7(3,7);
//del2f.m[4][4] = 0.0;
dl2 = 0.0;
dl2x = 0.0;
dl2y = 0.0;
dl2z = 0.0;
//del4f.m[4][4] = (2.0 - 3.0*n2)*n2 - 4.0*l2*m2;
dl4 = (2.0 - 3.0*z2)*z2 - 4.0*x2*y2;
dl4x = -8.0*x*y2;
dl4y = -8.0*x2*y;
dl4z = (4.0 - 12.0*z2)*z;
MAKE_ELEMENT_7(4,4);
//del2f.m[4][5] = 0.0;
dl2 = 0.0;
dl2x = 0.0;
dl2y = 0.0;
dl2z = 0.0;
//del4f.m[4][5] = 2.0*(l2 - m2)*lm;
dl4 = 2.0*(x2 - y2)*xy;
dl4x = 2.0*(3.0*x2 - y2)*y;
dl4y = 2.0*(x2 - 3.0*y2)*x;
dl4z = 0.0;
MAKE_ELEMENT_7(4,5);
//del2f.m[4][6] = sr15*ln;
dl2 = sr15*xz;
dl2x = sr15*z;
dl2y = 0.0;
dl2z = sr15*x;
//del4f.m[4][6] = -sr15*(2.0*n2 - 1.0)*ln;
dl4 = -sr15*(2.0*z2 - 1.0)*xz;
dl4x = -sr15*(2.0*z2 - 1.0)*z;
dl4y = 0.0;
dl4z = -sr15*(6.0*z2 - 1.0)*x;
MAKE_ELEMENT_7(4,6);
//del2f.m[4][7] = sr15*mn;
dl2 = sr15*yz;
dl2x = 0.0;
dl2y = sr15*z;
dl2z = sr15*y;
//del4f.m[4][7] = -sr15*(2.0*n2 - 1.0)*mn;
dl4 = -sr15*(2.0*z2 - 1.0)*yz;
dl4x = 0.0;
dl4y = -sr15*(2.0*z2 - 1.0)*z;
dl4z = -sr15*(6.0*z2 - 1.0)*y;
MAKE_ELEMENT_7(4,7);
//del2f.m[5][5] = 0.0;
dl2 = 0.0;
dl2x = 0.0;
dl2y = 0.0;
dl2z = 0.0;
//del4f.m[5][5] = -pow((2.0*n2 - 1.0),2) + 4.0*l2*m2;
t1 = 2.0*z2 - 1.0;
dl4 = -t1*t1 + 4.0*x2*y2;
dl4x = 8.0*x*y2;
dl4y = 8.0*x2*y;
dl4z = -8.0*t1*z;
MAKE_ELEMENT_7(5,5);
//del2f.m[5][6] = -sr15*mn;
dl2 = -sr15*yz;
dl2x = 0.0;
dl2y = -sr15*z;
dl2z = -sr15*y;
//del4f.m[5][6] = sr15*(2.0*n2 - 1.0)*mn;
dl4 = sr15*(2.0*z2 - 1.0)*yz;
dl4x = 0.0;
dl4y = sr15*(2.0*z2 - 1.0)*z;
dl4z = sr15*(6.0*z2 - 1.0)*y;
MAKE_ELEMENT_7(5,6);
//del2f.m[5][7] = sr15*ln;
dl2 = sr15*xz;
dl2x = sr15*z;
dl2y = 0.0;
dl2z = sr15*x;
//del4f.m[5][7] = -sr15*(2.0*n2 - 1.0)*ln;
dl4 = -sr15*(2.0*z2 - 1.0)*xz;
dl4x = -sr15*(2.0*z2 - 1.0)*z;
dl4y = 0.0;
dl4z = -sr15*(6.0*z2 - 1.0)*x;
MAKE_ELEMENT_7(5,7);
//del2f.m[6][6] = -(3.0*n2 - 1.0)/2.0;
dl2 = 0.5 - 1.5*z2;
dl2x = 0.0;
dl2y = 0.0;
dl2z = -3.0*z;
//del4f.m[6][6] = 1.5*(n2 - 1.0)*n2;
dl4 = (1.5*z2 - 1.5)*z2;
dl4x = 0.0;
dl4y = 0.0;
dl4z = (6.0*z2 - 3.0)*z;
MAKE_ELEMENT_7(6,6);
//del2f.m[6][7] = 0.0;
dl2 = 0.0;
dl2x = 0.0;
dl2y = 0.0;
dl2z = 0.0;
//del4f.m[6][7] = 0.0;
dl4 = 0.0;
dl4x = 0.0;
dl4y = 0.0;
dl4z = 0.0;
MAKE_ELEMENT_7(6,7);
//del2f.m[7][7] = -(3.0*n2 - 1.0)/2.0;
dl2 = 0.5 - 1.5*z2;
dl2x = 0.0;
dl2y = 0.0;
dl2z = -3.0*z;
//del4f.m[7][7] = 1.5*(n2 - 1.0)*n2;
dl4 = (1.5*z2 - 1.5)*z2;
dl4x = 0.0;
dl4y = 0.0;
dl4z = (6.0*z2 - 3.0)*z;
MAKE_ELEMENT_7(7,7);
}
/************************************************************************/
/* ----------------------------------------------------------------------
* Fast Model Generalized Pseudopotential Theory (MGPT) interatomic
* potential routine.
*
* Copyright (2015) Lawrence Livermore National Security, LLC.
* Produced at the Lawrence Livermore National Laboratory.
* Written by Tomas Oppelstrup (oppelstrup2@llnl.gov) and John Moriarty
* (moriarty2@llnl.gov)
* LLNL-CODE-674031 All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (as published by the
* Free Software Foundation) version 2, dated June 1991.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the terms and conditions of the
* GNU General Public License for more details.
*
* LLNL Preamble Notice
* A. This notice is required to be provided under our contract with the
* U.S. Department of Energy (DOE). This work was performed under the auspices
* of the DOE by Lawrence Livermore National Laboratory under Contract No.
* DE-AC52-07NA27344.
*
* B. Neither the United States Government nor Lawrence Livermore National
* Security, LLC nor any of their employees, makes any warranty, express or
* implied, or assumes any liability or responsibility for the accuracy,
* completeness, or usefulness of any information, apparatus, product, or
* process disclosed, or represents that its use would not infringe
* privately-owned rights.
*
* C. Also, reference herein to any specific commercial products, process,
* or services by trade name, trademark, manufacturer or otherwise does not
* necessarily constitute or imply its endorsement, recommendation, or
* favoring by the United States Government or Lawrence Livermore National
* Security, LLC. The views and opinions of authors expressed herein do not
* necessarily state or reflect those of the United States Government or
* Lawrence Livermore National Security, LLC, and shall not be used for
* advertising or product endorsement purposes.
------------------------------------------------------------------------- */
Event Timeline
Log In to Comment