// clang-format off
/*----------------------------------------------------------------------
PuReMD - Purdue ReaxFF Molecular Dynamics Program
Copyright (2010) Purdue University
Hasan Metin Aktulga, hmaktulga@lbl.gov
Joseph Fogarty, jcfogart@mail.usf.edu
Sagar Pandit, pandit@usf.edu
Ananth Y Grama, ayg@cs.purdue.edu
Please cite the related publication:
H. M. Aktulga, J. C. Fogarty, S. A. Pandit, A. Y. Grama,
"Parallel Reactive Molecular Dynamics: Numerical Methods and
Algorithmic Techniques", Parallel Computing, in press.
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; either version 2 of
the License, or (at your option) any later version.
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 GNU General Public License for more details:
.
----------------------------------------------------------------------*/
#include "reaxff_api.h"
#include "fix_efield.h" //..nina
#include "pair.h"
#include
using namespace LAMMPS_NS; //..nina
/*double ex_mtn = system->efield.ex; //..nina
double ey_mtn = system->efield.ey; //..nina
double ez_mtn = system->efield.ez; //..nina */
namespace ReaxFF {
void Compute_Polarization_Energy(reax_system *system, simulation_data *data, storage *workspace)
{
int i, type_i;
double x,y,z; //..nina
double q, en_tmp;
double ex_mtn = system->efield->ex; //..nina
double ey_mtn = system->efield->ey; //..nina
double ez_mtn = system->efield->ez; //..nina
data->my_en.e_pol = 0.0;
for (i = 0; i < system->n; i++) {
type_i = system->my_atoms[i].type;
if (type_i < 0) continue;
q = system->my_atoms[i].q;
x = system->my_atoms[i].x[0]; //..nina
y = system->my_atoms[i].x[1]; //..nina
z = system->my_atoms[i].x[2]; //..nina
en_tmp = KCALpMOL_to_EV * ((system->reax_param.sbp[type_i].chi * q +
(system->reax_param.sbp[type_i].eta / 2.) * SQR(q))-q*(x*ex_mtn+y*ey_mtn+z*ez_mtn)); //..nina
if (system->acks2_flag) {
/* energy due to coupling with kinetic energy potential */
en_tmp += KCALpMOL_to_EV * q * workspace->s[ system->N + i ];
}
data->my_en.e_pol += en_tmp;
/* tally energy into global or per-atom energy accumulators */
if (system->pair_ptr->eflag_either)
system->pair_ptr->ev_tally(i,i,system->n,1,0.0,en_tmp,0.0,0.0,0.0,0.0);
}
}
void vdW_Coulomb_Energy(reax_system *system, control_params *control,
simulation_data *data, storage *workspace,
reax_list **lists)
{
int i, j, pj, natoms;
int start_i, end_i, flag;
rc_tagint orig_i, orig_j;
double p_vdW1, p_vdW1i;
double powr_vdW1, powgi_vdW1;
double tmp, r_ij, fn13, exp1, exp2;
double Tap, dTap, dfn13, CEvd, CEclmb, de_core;
double dr3gamij_1, dr3gamij_3;
double e_ele, e_vdW, e_core, SMALL = 0.0001;
double e_lg, de_lg, r_ij5, r_ij6, re6;
double bond_softness, d_bond_softness, d, effpot_diff;
two_body_parameters *twbp;
far_neighbor_data *nbr_pj;
reax_list *far_nbrs;
// Tallying variables:
double pe_vdw, f_tmp, delij[3];
natoms = system->n;
far_nbrs = (*lists) + FAR_NBRS;
p_vdW1 = system->reax_param.gp.l[28];
p_vdW1i = 1.0 / p_vdW1;
e_core = 0;
e_vdW = 0;
e_lg = de_lg = 0.0;
for (i = 0; i < natoms; ++i) {
if (system->my_atoms[i].type < 0) continue;
start_i = Start_Index(i, far_nbrs);
end_i = End_Index(i, far_nbrs);
orig_i = system->my_atoms[i].orig_id;
for (pj = start_i; pj < end_i; ++pj) {
nbr_pj = &(far_nbrs->select.far_nbr_list[pj]);
j = nbr_pj->nbr;
if (system->my_atoms[j].type < 0) continue;
orig_j = system->my_atoms[j].orig_id;
flag = 0;
if (nbr_pj->d <= control->nonb_cut) {
if (j < natoms) flag = 1;
else if (orig_i < orig_j) flag = 1;
else if (orig_i == orig_j) {
if (nbr_pj->dvec[2] > SMALL) flag = 1;
else if (fabs(nbr_pj->dvec[2]) < SMALL) {
if (nbr_pj->dvec[1] > SMALL) flag = 1;
else if (fabs(nbr_pj->dvec[1]) < SMALL && nbr_pj->dvec[0] > SMALL)
flag = 1;
}
}
}
if (flag) {
r_ij = nbr_pj->d;
twbp = &(system->reax_param.tbp[system->my_atoms[i].type]
[system->my_atoms[j].type]);
Tap = workspace->Tap[7] * r_ij + workspace->Tap[6];
Tap = Tap * r_ij + workspace->Tap[5];
Tap = Tap * r_ij + workspace->Tap[4];
Tap = Tap * r_ij + workspace->Tap[3];
Tap = Tap * r_ij + workspace->Tap[2];
Tap = Tap * r_ij + workspace->Tap[1];
Tap = Tap * r_ij + workspace->Tap[0];
dTap = 7*workspace->Tap[7] * r_ij + 6*workspace->Tap[6];
dTap = dTap * r_ij + 5*workspace->Tap[5];
dTap = dTap * r_ij + 4*workspace->Tap[4];
dTap = dTap * r_ij + 3*workspace->Tap[3];
dTap = dTap * r_ij + 2*workspace->Tap[2];
dTap += workspace->Tap[1]/r_ij;
/*vdWaals Calculations*/
if (system->reax_param.gp.vdw_type==1 || system->reax_param.gp.vdw_type==3)
{ // shielding
powr_vdW1 = pow(r_ij, p_vdW1);
powgi_vdW1 = pow(1.0 / twbp->gamma_w, p_vdW1);
fn13 = pow(powr_vdW1 + powgi_vdW1, p_vdW1i);
exp1 = exp(twbp->alpha * (1.0 - fn13 / twbp->r_vdW));
exp2 = exp(0.5 * twbp->alpha * (1.0 - fn13 / twbp->r_vdW));
e_vdW = twbp->D * (exp1 - 2.0 * exp2);
data->my_en.e_vdW += Tap * e_vdW;
dfn13 = pow(powr_vdW1 + powgi_vdW1, p_vdW1i - 1.0) *
pow(r_ij, p_vdW1 - 2.0);
CEvd = dTap * e_vdW -
Tap * twbp->D * (twbp->alpha / twbp->r_vdW) * (exp1 - exp2) * dfn13;
} else { // no shielding
exp1 = exp(twbp->alpha * (1.0 - r_ij / twbp->r_vdW));
exp2 = exp(0.5 * twbp->alpha * (1.0 - r_ij / twbp->r_vdW));
e_vdW = twbp->D * (exp1 - 2.0 * exp2);
data->my_en.e_vdW += Tap * e_vdW;
CEvd = dTap * e_vdW -
Tap * twbp->D * (twbp->alpha / twbp->r_vdW) * (exp1 - exp2) / r_ij;
}
if (system->reax_param.gp.vdw_type==2 || system->reax_param.gp.vdw_type==3)
{ // inner wall
e_core = twbp->ecore * exp(twbp->acore * (1.0-(r_ij/twbp->rcore)));
data->my_en.e_vdW += Tap * e_core;
de_core = -(twbp->acore/twbp->rcore) * e_core;
CEvd += dTap * e_core + Tap * de_core / r_ij;
// lg correction, only if lgvdw is yes
if (control->lgflag) {
r_ij5 = pow(r_ij, 5.0);
r_ij6 = pow(r_ij, 6.0);
re6 = pow(twbp->lgre, 6.0);
e_lg = -(twbp->lgcij/(r_ij6 + re6));
data->my_en.e_vdW += Tap * e_lg;
de_lg = -6.0 * e_lg * r_ij5 / (r_ij6 + re6) ;
CEvd += dTap * e_lg + Tap * de_lg / r_ij;
}
}
/*Coulomb Calculations*/
dr3gamij_1 = (r_ij * r_ij * r_ij + twbp->gamma);
dr3gamij_3 = pow(dr3gamij_1 , 0.33333333333333);
tmp = Tap / dr3gamij_3;
data->my_en.e_ele += e_ele =
C_ele * system->my_atoms[i].q * system->my_atoms[j].q * tmp;
CEclmb = C_ele * system->my_atoms[i].q * system->my_atoms[j].q *
(dTap - Tap * r_ij / dr3gamij_1) / dr3gamij_3;
/* tally into per-atom energy */
if (system->pair_ptr->evflag) {
pe_vdw = Tap * (e_vdW + e_core + e_lg);
rvec_ScaledSum(delij, 1., system->my_atoms[i].x,
-1., system->my_atoms[j].x);
f_tmp = -(CEvd + CEclmb);
system->pair_ptr->ev_tally(i,j,natoms,1,pe_vdw,e_ele,
f_tmp,delij[0],delij[1],delij[2]);
}
rvec_ScaledAdd(workspace->f[i], -(CEvd + CEclmb), nbr_pj->dvec);
rvec_ScaledAdd(workspace->f[j], +(CEvd + CEclmb), nbr_pj->dvec);
}
}
}
/* contribution to energy and gradients (atoms and cell)
* due to geometry-dependent terms in the ACKS2
* kinetic energy */
if (system->acks2_flag)
for( i = 0; i < natoms; ++i ) {
if (system->my_atoms[i].type < 0) continue;
start_i = Start_Index(i, far_nbrs);
end_i = End_Index(i, far_nbrs);
orig_i = system->my_atoms[i].orig_id;
for( pj = start_i; pj < end_i; ++pj ) {
nbr_pj = &(far_nbrs->select.far_nbr_list[pj]);
j = nbr_pj->nbr;
if (system->my_atoms[j].type < 0) continue;
orig_j = system->my_atoms[j].orig_id;
flag = 0;
/* kinetic energy terms */
double xcut = 0.5 * (system->reax_param.sbp[system->my_atoms[i].type].bcut_acks2
+ system->reax_param.sbp[system->my_atoms[j].type].bcut_acks2);
if(nbr_pj->d <= xcut) {
if (j < natoms) flag = 1;
else if (orig_i < orig_j) flag = 1;
else if (orig_i == orig_j) {
if (nbr_pj->dvec[2] > SMALL) flag = 1;
else if (fabs(nbr_pj->dvec[2]) < SMALL) {
if (nbr_pj->dvec[1] > SMALL) flag = 1;
else if (fabs(nbr_pj->dvec[1]) < SMALL && nbr_pj->dvec[0] > SMALL)
flag = 1;
}
}
}
if (flag) {
d = nbr_pj->d / xcut;
bond_softness = system->reax_param.gp.l[34] * pow( d, 3.0 )
* pow( 1.0 - d, 6.0 );
if ( bond_softness > 0.0 )
{
/* Coulombic energy contribution */
effpot_diff = workspace->s[system->N + i]
- workspace->s[system->N + j];
e_ele = -0.5 * KCALpMOL_to_EV * bond_softness
* SQR( effpot_diff );
data->my_en.e_ele += e_ele;
/* forces contribution */
d_bond_softness = system->reax_param.gp.l[34]
* 3.0 / xcut * pow( d, 2.0 )
* pow( 1.0 - d, 5.0 ) * (1.0 - 3.0 * d);
d_bond_softness = -0.5 * d_bond_softness
* SQR( effpot_diff );
d_bond_softness = KCALpMOL_to_EV * d_bond_softness
/ nbr_pj->d;
/* tally into per-atom energy */
if (system->pair_ptr->evflag || system->pair_ptr->vflag_atom) {
rvec_ScaledSum( delij, 1., system->my_atoms[i].x,
-1., system->my_atoms[j].x );
f_tmp = -d_bond_softness;
system->pair_ptr->ev_tally(i,j,natoms,1,0.0,e_ele,
f_tmp,delij[0],delij[1],delij[2]);
}
rvec_ScaledAdd( workspace->f[i], -d_bond_softness, nbr_pj->dvec );
rvec_ScaledAdd( workspace->f[j], d_bond_softness, nbr_pj->dvec );
}
}
}
}
Compute_Polarization_Energy( system, data, workspace );
}
void Tabulated_vdW_Coulomb_Energy(reax_system *system, control_params *control,
simulation_data *data, storage *workspace,
reax_list **lists)
{
int i, j, pj, r, natoms;
int type_i, type_j, tmin, tmax;
int start_i, end_i, flag;
rc_tagint orig_i, orig_j;
double r_ij, base, dif;
double e_vdW, e_ele;
double CEvd, CEclmb, SMALL = 0.0001;
double f_tmp, delij[3];
double bond_softness, d_bond_softness, d, effpot_diff;
far_neighbor_data *nbr_pj;
reax_list *far_nbrs;
LR_lookup_table *t;
LR_lookup_table ** & LR = system->LR;
natoms = system->n;
far_nbrs = (*lists) + FAR_NBRS;
e_ele = e_vdW = 0;
for (i = 0; i < natoms; ++i) {
type_i = system->my_atoms[i].type;
if (type_i < 0) continue;
start_i = Start_Index(i,far_nbrs);
end_i = End_Index(i,far_nbrs);
orig_i = system->my_atoms[i].orig_id;
for (pj = start_i; pj < end_i; ++pj) {
nbr_pj = &(far_nbrs->select.far_nbr_list[pj]);
j = nbr_pj->nbr;
type_j = system->my_atoms[j].type;
if (type_j < 0) continue;
orig_j = system->my_atoms[j].orig_id;
flag = 0;
if (nbr_pj->d <= control->nonb_cut) {
if (j < natoms) flag = 1;
else if (orig_i < orig_j) flag = 1;
else if (orig_i == orig_j) {
if (nbr_pj->dvec[2] > SMALL) flag = 1;
else if (fabs(nbr_pj->dvec[2]) < SMALL) {
if (nbr_pj->dvec[1] > SMALL) flag = 1;
else if (fabs(nbr_pj->dvec[1]) < SMALL && nbr_pj->dvec[0] > SMALL)
flag = 1;
}
}
}
if (flag) {
r_ij = nbr_pj->d;
tmin = MIN(type_i, type_j);
tmax = MAX(type_i, type_j);
t = &(LR[tmin][tmax]);
/* Cubic Spline Interpolation */
r = (int)(r_ij * t->inv_dx);
if (r == 0) ++r;
base = (double)(r+1) * t->dx;
dif = r_ij - base;
e_vdW = ((t->vdW[r].d*dif + t->vdW[r].c)*dif + t->vdW[r].b)*dif +
t->vdW[r].a;
e_ele = ((t->ele[r].d*dif + t->ele[r].c)*dif + t->ele[r].b)*dif +
t->ele[r].a;
e_ele *= system->my_atoms[i].q * system->my_atoms[j].q;
data->my_en.e_vdW += e_vdW;
data->my_en.e_ele += e_ele;
CEvd = ((t->CEvd[r].d*dif + t->CEvd[r].c)*dif + t->CEvd[r].b)*dif +
t->CEvd[r].a;
CEclmb = ((t->CEclmb[r].d*dif+t->CEclmb[r].c)*dif+t->CEclmb[r].b)*dif +
t->CEclmb[r].a;
CEclmb *= system->my_atoms[i].q * system->my_atoms[j].q;
/* tally into per-atom energy */
if (system->pair_ptr->evflag) {
rvec_ScaledSum(delij, 1., system->my_atoms[i].x,
-1., system->my_atoms[j].x);
f_tmp = -(CEvd + CEclmb);
system->pair_ptr->ev_tally(i,j,natoms,1,e_vdW,e_ele,
f_tmp,delij[0],delij[1],delij[2]);
}
rvec_ScaledAdd(workspace->f[i], -(CEvd + CEclmb), nbr_pj->dvec);
rvec_ScaledAdd(workspace->f[j], +(CEvd + CEclmb), nbr_pj->dvec);
}
}
}
/* contribution to energy and gradients (atoms and cell)
* due to geometry-dependent terms in the ACKS2
* kinetic energy */
if (system->acks2_flag)
for( i = 0; i < natoms; ++i ) {
if (system->my_atoms[i].type < 0) continue;
start_i = Start_Index(i, far_nbrs);
end_i = End_Index(i, far_nbrs);
orig_i = system->my_atoms[i].orig_id;
for( pj = start_i; pj < end_i; ++pj ) {
nbr_pj = &(far_nbrs->select.far_nbr_list[pj]);
j = nbr_pj->nbr;
if (system->my_atoms[j].type < 0) continue;
orig_j = system->my_atoms[j].orig_id;
flag = 0;
/* kinetic energy terms */
double xcut = 0.5 * (system->reax_param.sbp[ system->my_atoms[i].type ].bcut_acks2
+ system->reax_param.sbp[ system->my_atoms[j].type ].bcut_acks2);
if(nbr_pj->d <= xcut) {
if (j < natoms) flag = 1;
else if (orig_i < orig_j) flag = 1;
else if (orig_i == orig_j) {
if (nbr_pj->dvec[2] > SMALL) flag = 1;
else if (fabs(nbr_pj->dvec[2]) < SMALL) {
if (nbr_pj->dvec[1] > SMALL) flag = 1;
else if (fabs(nbr_pj->dvec[1]) < SMALL && nbr_pj->dvec[0] > SMALL)
flag = 1;
}
}
}
if (flag) {
d = nbr_pj->d / xcut;
bond_softness = system->reax_param.gp.l[34] * pow( d, 3.0 )
* pow( 1.0 - d, 6.0 );
if ( bond_softness > 0.0 )
{
/* Coulombic energy contribution */
effpot_diff = workspace->s[system->N + i]
- workspace->s[system->N + j];
e_ele = -0.5 * KCALpMOL_to_EV * bond_softness
* SQR( effpot_diff );
data->my_en.e_ele += e_ele;
/* forces contribution */
d_bond_softness = system->reax_param.gp.l[34]
* 3.0 / xcut * pow( d, 2.0 )
* pow( 1.0 - d, 5.0 ) * (1.0 - 3.0 * d);
d_bond_softness = -0.5 * d_bond_softness
* SQR( effpot_diff );
d_bond_softness = KCALpMOL_to_EV * d_bond_softness
/ nbr_pj->d;
/* tally into per-atom energy */
if (system->pair_ptr->evflag || system->pair_ptr->vflag_atom) {
rvec_ScaledSum( delij, 1., system->my_atoms[i].x,
-1., system->my_atoms[j].x );
f_tmp = -d_bond_softness;
system->pair_ptr->ev_tally(i,j,natoms,1,0.0,e_ele,
f_tmp,delij[0],delij[1],delij[2]);
}
rvec_ScaledAdd( workspace->f[i], -d_bond_softness, nbr_pj->dvec );
rvec_ScaledAdd( workspace->f[j], d_bond_softness, nbr_pj->dvec );
}
}
}
}
Compute_Polarization_Energy(system, data, workspace);
}
void LR_vdW_Coulomb(reax_system *system, storage *workspace,
control_params *control, int i, int j,
double r_ij, LR_data *lr)
{
double p_vdW1 = system->reax_param.gp.l[28];
double p_vdW1i = 1.0 / p_vdW1;
double powr_vdW1, powgi_vdW1;
double tmp, fn13, exp1, exp2;
double Tap, dTap, dfn13;
double dr3gamij_1, dr3gamij_3;
double e_core, de_core;
double e_lg, de_lg, r_ij5, r_ij6, re6;
two_body_parameters *twbp;
twbp = &(system->reax_param.tbp[i][j]);
e_core = 0;
de_core = 0;
e_lg = de_lg = 0.0;
/* calculate taper and its derivative */
Tap = workspace->Tap[7] * r_ij + workspace->Tap[6];
Tap = Tap * r_ij + workspace->Tap[5];
Tap = Tap * r_ij + workspace->Tap[4];
Tap = Tap * r_ij + workspace->Tap[3];
Tap = Tap * r_ij + workspace->Tap[2];
Tap = Tap * r_ij + workspace->Tap[1];
Tap = Tap * r_ij + workspace->Tap[0];
dTap = 7*workspace->Tap[7] * r_ij + 6*workspace->Tap[6];
dTap = dTap * r_ij + 5*workspace->Tap[5];
dTap = dTap * r_ij + 4*workspace->Tap[4];
dTap = dTap * r_ij + 3*workspace->Tap[3];
dTap = dTap * r_ij + 2*workspace->Tap[2];
dTap += workspace->Tap[1]/r_ij;
/*vdWaals Calculations*/
if (system->reax_param.gp.vdw_type==1 || system->reax_param.gp.vdw_type==3)
{ // shielding
powr_vdW1 = pow(r_ij, p_vdW1);
powgi_vdW1 = pow(1.0 / twbp->gamma_w, p_vdW1);
fn13 = pow(powr_vdW1 + powgi_vdW1, p_vdW1i);
exp1 = exp(twbp->alpha * (1.0 - fn13 / twbp->r_vdW));
exp2 = exp(0.5 * twbp->alpha * (1.0 - fn13 / twbp->r_vdW));
lr->e_vdW = Tap * twbp->D * (exp1 - 2.0 * exp2);
dfn13 = pow(powr_vdW1 + powgi_vdW1, p_vdW1i-1.0) * pow(r_ij, p_vdW1-2.0);
lr->CEvd = dTap * twbp->D * (exp1 - 2.0 * exp2) -
Tap * twbp->D * (twbp->alpha / twbp->r_vdW) * (exp1 - exp2) * dfn13;
}
else { // no shielding
exp1 = exp(twbp->alpha * (1.0 - r_ij / twbp->r_vdW));
exp2 = exp(0.5 * twbp->alpha * (1.0 - r_ij / twbp->r_vdW));
lr->e_vdW = Tap * twbp->D * (exp1 - 2.0 * exp2);
lr->CEvd = dTap * twbp->D * (exp1 - 2.0 * exp2) -
Tap * twbp->D * (twbp->alpha / twbp->r_vdW) * (exp1 - exp2) / r_ij;
}
if (system->reax_param.gp.vdw_type==2 || system->reax_param.gp.vdw_type==3)
{ // inner wall
e_core = twbp->ecore * exp(twbp->acore * (1.0-(r_ij/twbp->rcore)));
lr->e_vdW += Tap * e_core;
de_core = -(twbp->acore/twbp->rcore) * e_core;
lr->CEvd += dTap * e_core + Tap * de_core / r_ij;
// lg correction, only if lgvdw is yes
if (control->lgflag) {
r_ij5 = pow(r_ij, 5.0);
r_ij6 = pow(r_ij, 6.0);
re6 = pow(twbp->lgre, 6.0);
e_lg = -(twbp->lgcij/(r_ij6 + re6));
lr->e_vdW += Tap * e_lg;
de_lg = -6.0 * e_lg * r_ij5 / (r_ij6 + re6) ;
lr->CEvd += dTap * e_lg + Tap * de_lg/r_ij;
}
}
/* Coulomb calculations */
dr3gamij_1 = (r_ij * r_ij * r_ij + twbp->gamma);
dr3gamij_3 = pow(dr3gamij_1 , 0.33333333333333);
tmp = Tap / dr3gamij_3;
lr->H = EV_to_KCALpMOL * tmp;
lr->e_ele = C_ele * tmp;
lr->CEclmb = C_ele * (dTap - Tap * r_ij / dr3gamij_1) / dr3gamij_3;
}
}