Page MenuHomec4science

reaxc_lookup.cpp
No OneTemporary

File Metadata

Created
Mon, Jul 1, 22:41

reaxc_lookup.cpp

/*----------------------------------------------------------------------
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:
<http://www.gnu.org/licenses/>.
----------------------------------------------------------------------*/
#include "pair_reax_c.h"
#if defined(PURE_REAX)
#include "lookup.h"
#include "nonbonded.h"
#include "tool_box.h"
#elif defined(LAMMPS_REAX)
#include "reaxc_lookup.h"
#include "reaxc_nonbonded.h"
#include "reaxc_tool_box.h"
#endif
LR_lookup_table **LR;
/* Fills solution into x. Warning: will modify c and d! */
void Tridiagonal_Solve( const real *a, const real *b,
real *c, real *d, real *x, unsigned int n){
int i;
real id;
/* Modify the coefficients. */
c[0] /= b[0]; /* Division by zero risk. */
d[0] /= b[0]; /* Division by zero would imply a singular matrix. */
for(i = 1; i < n; i++){
id = (b[i] - c[i-1] * a[i]); /* Division by zero risk. */
c[i] /= id; /* Last value calculated is redundant. */
d[i] = (d[i] - d[i-1] * a[i])/id;
}
/* Now back substitute. */
x[n - 1] = d[n - 1];
for(i = n - 2; i >= 0; i--)
x[i] = d[i] - c[i] * x[i + 1];
}
void Natural_Cubic_Spline( const real *h, const real *f,
cubic_spline_coef *coef, unsigned int n,
MPI_Comm comm )
{
int i;
real *a, *b, *c, *d, *v;
/* allocate space for the linear system */
a = (real*) smalloc( n * sizeof(real), "cubic_spline:a", comm );
b = (real*) smalloc( n * sizeof(real), "cubic_spline:a", comm );
c = (real*) smalloc( n * sizeof(real), "cubic_spline:a", comm );
d = (real*) smalloc( n * sizeof(real), "cubic_spline:a", comm );
v = (real*) smalloc( n * sizeof(real), "cubic_spline:a", comm );
/* build the linear system */
a[0] = a[1] = a[n-1] = 0;
for( i = 2; i < n-1; ++i )
a[i] = h[i-1];
b[0] = b[n-1] = 0;
for( i = 1; i < n-1; ++i )
b[i] = 2 * (h[i-1] + h[i]);
c[0] = c[n-2] = c[n-1] = 0;
for( i = 1; i < n-2; ++i )
c[i] = h[i];
d[0] = d[n-1] = 0;
for( i = 1; i < n-1; ++i )
d[i] = 6 * ((f[i+1]-f[i])/h[i] - (f[i]-f[i-1])/h[i-1]);
v[0] = 0;
v[n-1] = 0;
Tridiagonal_Solve( &(a[1]), &(b[1]), &(c[1]), &(d[1]), &(v[1]), n-2 );
for( i = 1; i < n; ++i ){
coef[i-1].d = (v[i] - v[i-1]) / (6*h[i-1]);
coef[i-1].c = v[i]/2;
coef[i-1].b = (f[i]-f[i-1])/h[i-1] + h[i-1]*(2*v[i] + v[i-1])/6;
coef[i-1].a = f[i];
}
sfree( a, "cubic_spline:a" );
sfree( b, "cubic_spline:b" );
sfree( c, "cubic_spline:c" );
sfree( d, "cubic_spline:d" );
sfree( v, "cubic_spline:v" );
}
void Complete_Cubic_Spline( const real *h, const real *f, real v0, real vlast,
cubic_spline_coef *coef, unsigned int n,
MPI_Comm comm )
{
int i;
real *a, *b, *c, *d, *v;
/* allocate space for the linear system */
a = (real*) smalloc( n * sizeof(real), "cubic_spline:a", comm );
b = (real*) smalloc( n * sizeof(real), "cubic_spline:a", comm );
c = (real*) smalloc( n * sizeof(real), "cubic_spline:a", comm );
d = (real*) smalloc( n * sizeof(real), "cubic_spline:a", comm );
v = (real*) smalloc( n * sizeof(real), "cubic_spline:a", comm );
/* build the linear system */
a[0] = 0;
for( i = 1; i < n; ++i )
a[i] = h[i-1];
b[0] = 2*h[0];
for( i = 1; i < n; ++i )
b[i] = 2 * (h[i-1] + h[i]);
c[n-1] = 0;
for( i = 0; i < n-1; ++i )
c[i] = h[i];
d[0] = 6 * (f[1]-f[0])/h[0] - 6 * v0;
d[n-1] = 6 * vlast - 6 * (f[n-1]-f[n-2]/h[n-2]);
for( i = 1; i < n-1; ++i )
d[i] = 6 * ((f[i+1]-f[i])/h[i] - (f[i]-f[i-1])/h[i-1]);
Tridiagonal_Solve( &(a[0]), &(b[0]), &(c[0]), &(d[0]), &(v[0]), n );
for( i = 1; i < n; ++i ){
coef[i-1].d = (v[i] - v[i-1]) / (6*h[i-1]);
coef[i-1].c = v[i]/2;
coef[i-1].b = (f[i]-f[i-1])/h[i-1] + h[i-1]*(2*v[i] + v[i-1])/6;
coef[i-1].a = f[i];
}
sfree( a, "cubic_spline:a" );
sfree( b, "cubic_spline:b" );
sfree( c, "cubic_spline:c" );
sfree( d, "cubic_spline:d" );
sfree( v, "cubic_spline:v" );
}
void LR_Lookup( LR_lookup_table *t, real r, LR_data *y )
{
int i;
real base, dif;
i = (int)(r * t->inv_dx);
if( i == 0 ) ++i;
base = (real)(i+1) * t->dx;
dif = r - base;
y->e_vdW = ((t->vdW[i].d*dif + t->vdW[i].c)*dif + t->vdW[i].b)*dif +
t->vdW[i].a;
y->CEvd = ((t->CEvd[i].d*dif + t->CEvd[i].c)*dif +
t->CEvd[i].b)*dif + t->CEvd[i].a;
y->e_ele = ((t->ele[i].d*dif + t->ele[i].c)*dif + t->ele[i].b)*dif +
t->ele[i].a;
y->CEclmb = ((t->CEclmb[i].d*dif + t->CEclmb[i].c)*dif + t->CEclmb[i].b)*dif +
t->CEclmb[i].a;
y->H = y->e_ele * EV_to_KCALpMOL / C_ele;
}
int Init_Lookup_Tables( reax_system *system, control_params *control,
storage *workspace, mpi_datatypes *mpi_data, char *msg )
{
int i, j, r;
int num_atom_types;
int existing_types[MAX_ATOM_TYPES], aggregated[MAX_ATOM_TYPES];
real dr;
real *h, *fh, *fvdw, *fele, *fCEvd, *fCEclmb;
real v0_vdw, v0_ele, vlast_vdw, vlast_ele;
MPI_Comm comm;
/* initializations */
v0_vdw = 0;
v0_ele = 0;
vlast_vdw = 0;
vlast_ele = 0;
comm = mpi_data->world;
num_atom_types = system->reax_param.num_atom_types;
dr = control->nonb_cut / control->tabulate;
h = (real*)
smalloc( (control->tabulate+2) * sizeof(real), "lookup:h", comm );
fh = (real*)
smalloc( (control->tabulate+2) * sizeof(real), "lookup:fh", comm );
fvdw = (real*)
smalloc( (control->tabulate+2) * sizeof(real), "lookup:fvdw", comm );
fCEvd = (real*)
smalloc( (control->tabulate+2) * sizeof(real), "lookup:fCEvd", comm );
fele = (real*)
smalloc( (control->tabulate+2) * sizeof(real), "lookup:fele", comm );
fCEclmb = (real*)
smalloc( (control->tabulate+2) * sizeof(real), "lookup:fCEclmb", comm );
/* allocate Long-Range LookUp Table space based on
number of atom types in the ffield file */
LR = (LR_lookup_table**)
scalloc( num_atom_types, sizeof(LR_lookup_table*), "lookup:LR", comm );
for( i = 0; i < num_atom_types; ++i )
LR[i] = (LR_lookup_table*)
scalloc( num_atom_types, sizeof(LR_lookup_table), "lookup:LR[i]", comm );
/* most atom types in ffield file will not exist in the current
simulation. to avoid unnecessary lookup table space, determine
the atom types that exist in the current simulation */
for( i = 0; i < MAX_ATOM_TYPES; ++i )
existing_types[i] = 0;
for( i = 0; i < system->n; ++i )
existing_types[ system->my_atoms[i].type ] = 1;
MPI_Allreduce( existing_types, aggregated, MAX_ATOM_TYPES,
MPI_INT, MPI_SUM, mpi_data->world );
/* fill in the lookup table entries for existing atom types.
only lower half should be enough. */
for( i = 0; i < num_atom_types; ++i ) {
if( aggregated[i] ) {
//for( j = 0; j < num_atom_types; ++j )
for( j = i; j < num_atom_types; ++j ) {
if( aggregated[j] ) {
LR[i][j].xmin = 0;
LR[i][j].xmax = control->nonb_cut;
LR[i][j].n = control->tabulate + 2;
LR[i][j].dx = dr;
LR[i][j].inv_dx = control->tabulate / control->nonb_cut;
LR[i][j].y = (LR_data*)
smalloc( LR[i][j].n * sizeof(LR_data), "lookup:LR[i,j].y", comm );
LR[i][j].H = (cubic_spline_coef*)
smalloc( LR[i][j].n*sizeof(cubic_spline_coef),"lookup:LR[i,j].H" ,
comm );
LR[i][j].vdW = (cubic_spline_coef*)
smalloc( LR[i][j].n*sizeof(cubic_spline_coef),"lookup:LR[i,j].vdW",
comm);
LR[i][j].CEvd = (cubic_spline_coef*)
smalloc( LR[i][j].n*sizeof(cubic_spline_coef),"lookup:LR[i,j].CEvd",
comm);
LR[i][j].ele = (cubic_spline_coef*)
smalloc( LR[i][j].n*sizeof(cubic_spline_coef),"lookup:LR[i,j].ele",
comm );
LR[i][j].CEclmb = (cubic_spline_coef*)
smalloc( LR[i][j].n*sizeof(cubic_spline_coef),
"lookup:LR[i,j].CEclmb", comm );
for( r = 1; r <= control->tabulate; ++r ) {
LR_vdW_Coulomb( system, workspace, control, i, j, r * dr, &(LR[i][j].y[r]) );
h[r] = LR[i][j].dx;
fh[r] = LR[i][j].y[r].H;
fvdw[r] = LR[i][j].y[r].e_vdW;
fCEvd[r] = LR[i][j].y[r].CEvd;
fele[r] = LR[i][j].y[r].e_ele;
fCEclmb[r] = LR[i][j].y[r].CEclmb;
}
// init the start-end points
h[r] = LR[i][j].dx;
v0_vdw = LR[i][j].y[1].CEvd;
v0_ele = LR[i][j].y[1].CEclmb;
fh[r] = fh[r-1];
fvdw[r] = fvdw[r-1];
fCEvd[r] = fCEvd[r-1];
fele[r] = fele[r-1];
fCEclmb[r] = fCEclmb[r-1];
vlast_vdw = fCEvd[r-1];
vlast_ele = fele[r-1];
Natural_Cubic_Spline( &h[1], &fh[1],
&(LR[i][j].H[1]), control->tabulate+1, comm );
Complete_Cubic_Spline( &h[1], &fvdw[1], v0_vdw, vlast_vdw,
&(LR[i][j].vdW[1]), control->tabulate+1,
comm );
Natural_Cubic_Spline( &h[1], &fCEvd[1],
&(LR[i][j].CEvd[1]), control->tabulate+1,
comm );
Complete_Cubic_Spline( &h[1], &fele[1], v0_ele, vlast_ele,
&(LR[i][j].ele[1]), control->tabulate+1,
comm );
Natural_Cubic_Spline( &h[1], &fCEclmb[1],
&(LR[i][j].CEclmb[1]), control->tabulate+1,
comm );
} else{
LR[i][j].n = 0;
}
}
}
}
free(h);
free(fh);
free(fvdw);
free(fCEvd);
free(fele);
free(fCEclmb);
return 1;
}
void Deallocate_Lookup_Tables( reax_system *system )
{
int i, j;
int ntypes;
ntypes = system->reax_param.num_atom_types;
for( i = 0; i < ntypes; ++i ) {
for( j = i; j < ntypes; ++j )
if( LR[i][j].n ) {
sfree( LR[i][j].y, "LR[i,j].y" );
sfree( LR[i][j].H, "LR[i,j].H" );
sfree( LR[i][j].vdW, "LR[i,j].vdW" );
sfree( LR[i][j].CEvd, "LR[i,j].CEvd" );
sfree( LR[i][j].ele, "LR[i,j].ele" );
sfree( LR[i][j].CEclmb, "LR[i,j].CEclmb" );
}
sfree( LR[i], "LR[i]" );
}
sfree( LR, "LR" );
}

Event Timeline