git-svn-id: svn://svn.icms.temple.edu/lammps-ro/trunk@7858 f3b2605a-c512-4ea7-a41b-209d697bcdaa

This commit is contained in:
sjplimp
2012-02-28 19:52:12 +00:00
parent 00944a2b95
commit 6a544be9cf
7 changed files with 1159 additions and 813 deletions

View File

@ -60,7 +60,7 @@ PPPM::PPPM(LAMMPS *lmp, int narg, char **arg) : KSpace(lmp, narg, arg)
{
if (narg < 1) error->all(FLERR,"Illegal kspace_style pppm command");
precision = atof(arg[0]);
accuracy_relative = atof(arg[0]);
nfactors = 3;
factors = new int[nfactors];
@ -222,6 +222,11 @@ void PPPM::init()
error->warning(FLERR,str);
}
// set accuracy (force units) from accuracy_relative or accuracy_absolute
if (accuracy_absolute >= 0.0) accuracy = accuracy_absolute;
else accuracy = accuracy_relative * two_charge_force;
// setup FFT grid resolution and g_ewald
// normally one iteration thru while loop is all that is required
// if grid stencil extends beyond neighbor proc, reduce order and try again
@ -229,7 +234,6 @@ void PPPM::init()
int iteration = 0;
while (order > 0) {
if (iteration && me == 0)
error->warning(FLERR,"Reducing PPPM order b/c stencil extends "
"beyond neighbor processor");
@ -970,9 +974,7 @@ void PPPM::set_grid()
acons[7][5] = 1755948832039.0 / 36229939200000.0;
acons[7][6] = 4887769399.0 / 37838389248.0;
//double q2 = qsqsum * force->qqrd2e / force->dielectric;
double q2 = qsqsum / force->dielectric;
bigint natoms = atom->natoms;
double q2 = qsqsum * force->qqrd2e / force->dielectric;
// use xprd,yprd,zprd even if triclinic so grid size is the same
// adjust z dimension for 2d slab PPPM
@ -984,20 +986,21 @@ void PPPM::set_grid()
double zprd_slab = zprd*slab_volfactor;
// make initial g_ewald estimate
// based on desired error and real space cutoff
// based on desired accuracy and real space cutoff
// fluid-occupied volume used to estimate real-space error
// zprd used rather than zprd_slab
double h_x,h_y,h_z;
bigint natoms = atom->natoms;
if (!gewaldflag)
g_ewald = sqrt(-log(precision*sqrt(natoms*cutoff*xprd*yprd*zprd) /
g_ewald = sqrt(-log(accuracy*sqrt(natoms*cutoff*xprd*yprd*zprd) /
(2.0*q2))) / cutoff;
// set optimal nx_pppm,ny_pppm,nz_pppm based on order and precision
// set optimal nx_pppm,ny_pppm,nz_pppm based on order and accuracy
// nz_pppm uses extended zprd_slab instead of zprd
// h = 1/g_ewald is upper bound on h such that h*g_ewald <= 1
// reduce it until precision target is met
// reduce it until accuracy target is met
if (!gridflag) {
double err;
@ -1008,21 +1011,21 @@ void PPPM::set_grid()
nz_pppm = static_cast<int> (zprd_slab/h_z + 1);
err = rms(h_x,xprd,natoms,q2,acons);
while (err > precision) {
while (err > accuracy) {
err = rms(h_x,xprd,natoms,q2,acons);
nx_pppm++;
h_x = xprd/nx_pppm;
}
err = rms(h_y,yprd,natoms,q2,acons);
while (err > precision) {
while (err > accuracy) {
err = rms(h_y,yprd,natoms,q2,acons);
ny_pppm++;
h_y = yprd/ny_pppm;
}
err = rms(h_z,zprd_slab,natoms,q2,acons);
while (err > precision) {
while (err > accuracy) {
err = rms(h_z,zprd_slab,natoms,q2,acons);
nz_pppm++;
h_z = zprd_slab/nz_pppm;
@ -1067,7 +1070,7 @@ void PPPM::set_grid()
}
}
// final RMS precision
// final RMS accuracy
double lprx = rms(h_x,xprd,natoms,q2,acons);
double lpry = rms(h_y,yprd,natoms,q2,acons);
@ -1092,14 +1095,18 @@ void PPPM::set_grid()
fprintf(screen," G vector (1/distance)= %g\n",g_ewald);
fprintf(screen," grid = %d %d %d\n",nx_pppm,ny_pppm,nz_pppm);
fprintf(screen," stencil order = %d\n",order);
fprintf(screen," RMS precision = %g\n",MAX(lpr,spr));
fprintf(screen," absolute RMS force accuracy = %g\n",MAX(lpr,spr));
fprintf(screen," relative force accuracy = %g\n",
MAX(lpr,spr)/two_charge_force);
fprintf(screen," using %s precision FFTs\n",fft_prec);
}
if (logfile) {
fprintf(logfile," G vector (1/distance) = %g\n",g_ewald);
fprintf(logfile," grid = %d %d %d\n",nx_pppm,ny_pppm,nz_pppm);
fprintf(logfile," stencil order = %d\n",order);
fprintf(logfile," RMS precision = %g\n",MAX(lpr,spr));
fprintf(logfile," absolute RMS force accuracy = %g\n",MAX(lpr,spr));
fprintf(logfile," relative force accuracy = %g\n",
MAX(lpr,spr)/two_charge_force);
fprintf(logfile," using %s precision FFTs\n",fft_prec);
}
}
@ -1128,7 +1135,7 @@ int PPPM::factorable(int n)
}
/* ----------------------------------------------------------------------
compute RMS precision for a dimension
compute RMS accuracy for a dimension
------------------------------------------------------------------------- */
double PPPM::rms(double h, double prd, bigint natoms,
@ -1143,7 +1150,7 @@ double PPPM::rms(double h, double prd, bigint natoms,
}
/* ----------------------------------------------------------------------
compute difference in real-space and kspace RMS precision
compute difference in real-space and KSpace RMS accuracy
------------------------------------------------------------------------- */
double PPPM::diffpr(double h_x, double h_y, double h_z, double q2,

View File

@ -47,7 +47,6 @@ class PPPM : public KSpace {
protected:
int me,nprocs;
double precision;
int nfactors;
int *factors;
double qsum,qsqsum;
@ -221,7 +220,7 @@ E: PPPM grid is too large
The global PPPM grid is larger than OFFSET in one or more dimensions.
OFFSET is currently set to 4096. You likely need to decrease the
requested precision.
requested accuracy.
E: PPPM order has been reduced to 0

View File

@ -56,11 +56,14 @@ EwaldN::EwaldN(LAMMPS *lmp, int narg, char **arg) : KSpace(lmp, narg, arg)
kvec = NULL;
B = NULL;
first_output = 0;
energy_self_peratom = NULL;
virial_self_peratom = NULL;
}
EwaldN::~EwaldN()
{
deallocate();
deallocate_peratom();
delete [] ekr_local;
delete [] B;
}
@ -132,6 +135,9 @@ void EwaldN::init()
if (screen) fprintf(screen, " G vector = %g\n", g_ewald);
if (logfile) fprintf(logfile, " G vector = %g\n", g_ewald);
}
deallocate_peratom();
peratom_allocate_flag = 0;
}
@ -231,6 +237,12 @@ void EwaldN::reallocate() // allocate memory
void EwaldN::reallocate_atoms()
{
if (eflag_atom || vflag_atom)
if (atom->nlocal > atom->nmax) {
deallocate_peratom();
allocate_peratom();
}
if ((nevec = atom->nmax*(2*nbox+1))<=nevec_max) return;
delete [] ekr_local;
ekr_local = new cvector[nevec];
@ -238,6 +250,19 @@ void EwaldN::reallocate_atoms()
nevec_max = nevec;
}
void EwaldN::allocate_peratom()
{
memory->create(energy_self_peratom,atom->nmax,EWALD_NFUNCS,"ewald/n:energy_self_peratom");
memory->create(virial_self_peratom,atom->nmax,EWALD_NFUNCS,"ewald/n:virial_self_peratom");
}
void EwaldN::deallocate_peratom() // free memory
{
memory->destroy(energy_self_peratom);
memory->destroy(virial_self_peratom);
}
void EwaldN::deallocate() // free memory
{
@ -392,6 +417,56 @@ void EwaldN::init_self()
}
}
void EwaldN::init_self_peratom()
{
if (!(vflag_atom || eflag_atom)) return;
double g1 = g_ewald, g2 = g1*g1, g3 = g1*g2;
const double qscale = force->qqrd2e * scale;
int nlocal = atom->nlocal;
for (int k = 0; k < 3; k++)
for (int i = 0; i < nlocal; i++) {
energy_self_peratom[i][k] = 0;
virial_self_peratom[i][k] = 0;
}
if (function[0]) { // 1/r
double *q = atom->q;
for (int i = 0; i < nlocal; i++) {
virial_self_peratom[i][0] = -0.5*MY_PI*qscale/(g2*volume)*q[i]*sum[0].x;
energy_self_peratom[i][0] = q[i]*q[i]*qscale*g1/sqrt(MY_PI)-virial_self_peratom[i][0];
}
}
if (function[1]) { // geometric 1/r^6
int *type = atom->type;
for (int i = 0; i < nlocal; i++) {
virial_self_peratom[i][1] = MY_PI*sqrt(MY_PI)*g3/(6.0*volume)*B[type[i]]*sum[1].x;
energy_self_peratom[i][1] = -B[type[i]]*B[type[i]]*g3*g3/12.0+virial_self_peratom[i][1];
}
}
if (function[2]) { // arithmetic 1/r^6
double *bi;
int *type = atom->type;
for (int i = 0; i < nlocal; i++) {
bi = B+7*type[i]+7;
for (int k=2; k<9; ++k) {
virial_self_peratom[i][2] += 0.5*MY_PI*sqrt(MY_PI)*g3/(48.0*volume)*sum[k].x*(--bi)[0];
}
energy_self_peratom[i][2] = -bi[0]*bi[6]*g3*g3/3.0+virial_self_peratom[i][2];
}
}
if (function[3]) { // dipole
double **mu = atom->mu;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
virial_self_peratom[i][3] = 0; // in surface
energy_self_peratom[i][3] = mu[i][3]*mu[i][3]*mumurd2e*2.0*g3/3.0/sqrt(MY_PI)-virial_self_peratom[i][3];
}
}
}
/* ----------------------------------------------------------------------
compute the EwaldN long-range force, energy, virial
------------------------------------------------------------------------- */
@ -399,12 +474,28 @@ void EwaldN::init_self()
void EwaldN::compute(int eflag, int vflag)
{
if (!nbox) return;
// set energy/virial flags
// invoke allocate_peratom() if needed for first time
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = eflag_global = vflag_global = eflag_atom = vflag_atom = 0;
if (!peratom_allocate_flag && (eflag_atom || vflag_atom)) {
allocate_peratom();
peratom_allocate_flag = 1;
}
reallocate_atoms();
init_self_peratom();
compute_ek();
compute_force();
compute_surface();
compute_energy(eflag);
compute_virial(vflag);
compute_surface_peratom();
compute_energy();
compute_energy_peratom();
compute_virial();
compute_virial_peratom();
}
@ -588,10 +679,40 @@ void EwaldN::compute_surface()
energy_self[3] -= virial_self[3];
}
void EwaldN::compute_energy(int eflag)
void EwaldN::compute_surface_peratom()
{
if (!(vflag_atom || eflag_atom)) return;
if (!function[3]) return;
vector sum_local = VECTOR_NULL, sum_total;
double **mu = atom->mu;
int nlocal = atom->nlocal;
for (int i=0; i < nlocal; i++) {
register double di = mu[i][3];
sum_local[0] += di*mu[i][0];
sum_local[1] += di*mu[i][1];
sum_local[2] += di*mu[i][2];
}
MPI_Allreduce(sum_local, sum_total, 3, MPI_DOUBLE, MPI_SUM, world);
for (int i = 0; i < nlocal; i++) {
energy_self_peratom[i][3] += virial_self_peratom[i][3];
register double di = mu[i][3];
virial_self_peratom[i][3] =
mumurd2e*(2.0*MY_PI*(di*mu[i][0]*sum_total[0] + di*mu[i][1]*sum_total[1] +
di*mu[i][2]*sum_total[2])/(2.0*dielectric+1)/volume);
energy_self_peratom[i][3] -= virial_self_peratom[i][3];
}
}
void EwaldN::compute_energy()
{
energy = 0.0;
if (!eflag) return;
if (!eflag_global) return;
complex *cek = cek_global;
double *ke = kenergy;
@ -621,16 +742,94 @@ void EwaldN::compute_energy(int eflag)
sum[3] += *(ke++)*(cek->re*cek->re+cek->im*cek->im); ++cek; }
}
for (int k=0; k<EWALD_NFUNCS; ++k) energy += c[k]*sum[k]-energy_self[k];
if (slabflag) compute_slabcorr(eflag);
if (slabflag) compute_slabcorr();
}
void EwaldN::compute_energy_peratom()
{
if (!eflag_atom) return;
kvector *k;
hvector *h, *nh;
cvector *z = ekr_local;
vector mui;
double sum[EWALD_MAX_NSUMS];
complex *cek, zc, zx, zxy;
double *q = atom->q;
double *mu = atom->mu ? atom->mu[0] : NULL;
const double qscale = force->qqrd2e * scale;
double *ke = kenergy;
double c[EWALD_NFUNCS] = {
4.0*MY_PI*qscale/volume, 2.0*MY_PI*sqrt(MY_PI)/(24.0*volume),
2.0*MY_PI*sqrt(MY_PI)/(192.0*volume), 4.0*MY_PI*mumurd2e/volume};
int i, kx, ky, lbytes = (2*nbox+1)*sizeof(cvector), *type = atom->type;
int func[EWALD_NFUNCS];
memcpy(func, function, EWALD_NFUNCS*sizeof(int));
for (int j = 0; j < atom->nlocal; j++) {
k = kvec;
kx = ky = -1;
ke = kenergy;
cek = cek_global;
memset(sum, 0, EWALD_MAX_NSUMS*sizeof(double));
if (func[3]) {
register double di = mu[3] * c[3];
mui[0] = di*(mu++)[0]; mui[1] = di*(mu++)[1]; mui[2] = di*(mu++)[2];
mu++;
}
for (nh = (h = hvec)+nkvec; h<nh; ++h, ++k) {
if (ky!=k->y) { // based on order in
if (kx!=k->x) zx = z[kx = k->x].x; // reallocate
C_RMULT(zxy, z[ky = k->y].y, zx);
}
C_CRMULT(zc, z[k->z].z, zxy);
if (func[0]) { // 1/r
sum[0] += *(ke++)*(cek->re*zc.re - cek->im*zc.im); ++cek; }
if (func[1]) { // geometric 1/r^6
sum[1] += *(ke++)*(cek->re*zc.re - cek->im*zc.im); ++cek; }
if (func[2]) { // arithmetic 1/r^6
register double im, c = *(ke++);
for (i=2; i<9; ++i) {
im = c*(cek->re*zc.re - cek->im*zc.im); ++cek;
sum[i] += im;
}
}
if (func[3]) { // dipole
sum[9] += *(ke++)*(cek->re*zc.re -
cek->im*zc.im)*(mui[0]*h->x+mui[1]*h->y+mui[2]*h->z); ++cek;
}
}
if (func[0]) { // 1/r
register double qj = *(q++)*c[0];
eatom[j] += sum[0]*qj - energy_self_peratom[j][0];
}
if (func[1]) { // geometric 1/r^6
register double bj = B[*type]*c[1];
eatom[j] += sum[1]*bj - energy_self_peratom[j][1];
}
if (func[2]) { // arithmetic 1/r^6
register double *bj = B+7*type[0]+7;
for (i=2; i<9; ++i) {
register double c2 = (--bj)[0]*c[2];
eatom[j] += 0.5*sum[i]*c2;
}
eatom[j] -= energy_self_peratom[j][2];
}
if (func[3]) { // dipole
eatom[j] += sum[9] - energy_self_peratom[j][3];
}
z = (cvector *) ((char *) z+lbytes);
++type;
}
}
#define swap(a, b) { register double t = a; a= b; b = t; }
void EwaldN::compute_virial(int vflag)
void EwaldN::compute_virial()
{
memset(virial, 0, sizeof(shape));
if (!vflag) return;
if (!vflag_global) return;
complex *cek = cek_global;
double *kv = kvirial;
@ -678,6 +877,105 @@ void EwaldN::compute_virial(int vflag)
}
}
void EwaldN::compute_virial_peratom()
{
if (!vflag_atom) return;
kvector *k;
hvector *h, *nh;
cvector *z = ekr_local;
vector mui;
complex *cek, zc, zx, zxy;
double *kv;
double *q = atom->q;
double *mu = atom->mu ? atom->mu[0] : NULL;
const double qscale = force->qqrd2e * scale;
double c[EWALD_NFUNCS] = {
4.0*MY_PI*qscale/volume, 2.0*MY_PI*sqrt(MY_PI)/(24.0*volume),
2.0*MY_PI*sqrt(MY_PI)/(192.0*volume), 4.0*MY_PI*mumurd2e/volume};
shape sum[EWALD_MAX_NSUMS];
int func[EWALD_NFUNCS];
memcpy(func, function, EWALD_NFUNCS*sizeof(int));
int i, kx, ky, lbytes = (2*nbox+1)*sizeof(cvector), *type = atom->type;
for (int j = 0; j < atom->nlocal; j++) {
k = kvec;
kx = ky = -1;
kv = kvirial;
cek = cek_global;
memset(sum, 0, EWALD_MAX_NSUMS*sizeof(shape));
if (func[3]) {
register double di = mu[3] * c[3];
mui[0] = di*(mu++)[0]; mui[1] = di*(mu++)[1]; mui[2] = di*(mu++)[2];
mu++;
}
for (nh = (h = hvec)+nkvec; h<nh; ++h, ++k) {
if (ky!=k->y) { // based on order in
if (kx!=k->x) zx = z[kx = k->x].x; // reallocate
C_RMULT(zxy, z[ky = k->y].y, zx);
}
C_CRMULT(zc, z[k->z].z, zxy);
if (func[0]) { // 1/r
register double r = cek->re*zc.re - cek->im*zc.im; ++cek;
sum[0][0] += *(kv++)*r; sum[0][1] += *(kv++)*r; sum[0][2] += *(kv++)*r;
sum[0][3] += *(kv++)*r; sum[0][4] += *(kv++)*r; sum[0][5] += *(kv++)*r;
}
if (func[1]) { // geometric 1/r^6
register double r = cek->re*zc.re - cek->im*zc.im; ++cek;
sum[1][0] += *(kv++)*r; sum[1][1] += *(kv++)*r; sum[1][2] += *(kv++)*r;
sum[1][3] += *(kv++)*r; sum[1][4] += *(kv++)*r; sum[1][5] += *(kv++)*r;
}
if (func[2]) { // arithmetic 1/r^6
register double r;
for (i=2; i<9; ++i) {
r = cek->re*zc.re - cek->im*zc.im; ++cek;
sum[i][0] += *(kv++)*r; sum[i][1] += *(kv++)*r; sum[i][2] += *(kv++)*r;
sum[i][3] += *(kv++)*r; sum[i][4] += *(kv++)*r; sum[i][5] += *(kv++)*r;
kv -= 6;
}
kv += 6;
}
if (func[3]) { // dipole
register double r = (cek->re*zc.re -
cek->im*zc.im)*(mui[0]*h->x+mui[1]*h->y+mui[2]*h->z); ++cek;
sum[9][0] += *(kv++)*r; sum[9][1] += *(kv++)*r; sum[9][2] += *(kv++)*r;
sum[9][3] += *(kv++)*r; sum[9][4] += *(kv++)*r; sum[9][5] += *(kv++)*r;
}
}
if (func[0]) { // 1/r
register double qi = *(q++)*c[0];
for (int n = 0; n < 6; n++) vatom[j][n] += sum[0][n]*qi;
}
if (func[1]) { // geometric 1/r^6
register double bi = B[*type]*c[1];
for (int n = 0; n < 6; n++) vatom[j][n] += sum[1][n]*bi;
double dum = sum[1][2];
}
if (func[2]) { // arithmetic 1/r^6
register double *bj = B+7*type[0]+7;
for (i=2; i<9; ++i) {
register double c2 = (--bj)[0]*c[2];
for (int n = 0; n < 6; n++) {
vatom[j][n] += 0.5*sum[i][n]*c2;
}
}
}
if (func[3]) { // dipole
for (int n = 0; n < 6; n++) vatom[j][n] += sum[9][n];
}
for (int k=0; k<EWALD_NFUNCS; ++k) {
if (func[k]) {
for (int n = 0; n < 3; n++) vatom[j][n] -= virial_self_peratom[j][k];
}
}
z = (cvector *) ((char *) z+lbytes);
++type;
}
}
/* ----------------------------------------------------------------------
Slab-geometry correction term to dampen inter-slab interactions between
periodically repeating slabs. Yields good approximation to 2-D EwaldN if
@ -685,26 +983,41 @@ void EwaldN::compute_virial(int vflag)
111, 3155). Slabs defined here to be parallel to the xy plane.
------------------------------------------------------------------------- */
void EwaldN::compute_slabcorr(int eflag)
void EwaldN::compute_slabcorr()
{
// compute local contribution to global dipole moment
double *q = atom->q;
double *x = atom->x[0]-1, *xn = x+3*atom->nlocal-1;
double dipole = 0.0, dipole_all;
double **x = atom->x;
int nlocal = atom->nlocal;
while ((x+=3)<xn) dipole += *x * *(q++);
MPI_Allreduce(&dipole, &dipole_all, 1, MPI_DOUBLE, MPI_SUM, world);
double dipole = 0.0;
for (int i = 0; i < nlocal; i++) dipole += q[i]*x[i][2];
// sum local contributions to get global dipole moment
double dipole_all;
MPI_Allreduce(&dipole,&dipole_all,1,MPI_DOUBLE,MPI_SUM,world);
// compute corrections
const double e_slabcorr = 2.0*MY_PI*dipole_all*dipole_all/volume;
const double qscale = force->qqrd2e * scale;
double ffact = -4.0*MY_PI*qscale*dipole_all/volume;
double *f = atom->f[0]-1, *fn = f+3*atom->nlocal-3;
if (eflag_global) energy += qscale * e_slabcorr;
q = atom->q;
while ((f+=3)<fn) *f += ffact* *(q++);
// per-atom energy
if (eflag) // energy correction
energy += qscale*(2.0*MY_PI*dipole_all*dipole_all/volume);
if (eflag_atom) {
double efact = 2.0*MY_PI*dipole_all/volume;
for (int i = 0; i < nlocal; i++) eatom[i] += qscale * q[i]*x[i][2]*efact;
}
// add on force corrections
double ffact = -4.0*MY_PI*dipole_all/volume;
double **f = atom->f;
for (int i = 0; i < nlocal; i++) f[i][2] += qscale * q[i]*ffact;
}

View File

@ -49,10 +49,13 @@ class EwaldN : public KSpace {
int nkvec, nkvec_max, nevec, nevec_max,
nbox, nfunctions, nsums, sums;
int peratom_allocate_flag;
double bytes;
double precision, g2_max;
double *kenergy, energy_self[EWALD_NFUNCS];
double *kvirial, virial_self[EWALD_NFUNCS];
double **energy_self_peratom;
double **virial_self_peratom;
cvector *ekr_local;
hvector *hvec;
kvector *kvec;
@ -62,18 +65,24 @@ class EwaldN : public KSpace {
complex *cek_local, *cek_global;
void reallocate();
void allocate_peratom();
void reallocate_atoms();
void deallocate();
void deallocate_peratom();
void coefficients();
void init_coeffs();
void init_coeff_sums();
void init_self();
void init_self_peratom();
void compute_ek();
void compute_force();
void compute_surface();
void compute_energy(int);
void compute_virial(int);
void compute_slabcorr(int);
void compute_surface_peratom();
void compute_energy();
void compute_energy_peratom();
void compute_virial();
void compute_virial_peratom();
void compute_slabcorr();
};
}

View File

@ -324,7 +324,8 @@ void FixBoxRelax::init()
temperature = modify->compute[icompute];
icompute = modify->find_compute(id_press);
if (icompute < 0) error->all(FLERR,"Pressure ID for fix box/relax does not exist");
if (icompute < 0)
error->all(FLERR,"Pressure ID for fix box/relax does not exist");
pressure = modify->compute[icompute];
pv2e = 1.0 / force->nktv2p;

View File

@ -16,6 +16,7 @@
#include "kspace.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "memory.h"
#include "error.h"
@ -32,6 +33,11 @@ KSpace::KSpace(LAMMPS *lmp, int narg, char **arg) : Pointers(lmp)
slabflag = 0;
slab_volfactor = 1;
accuracy_absolute = -1.0;
two_charge_force = force->qqr2e *
(force->qelectron * force->qelectron) /
(force->angstrom * force->angstrom);
maxeatom = maxvatom = 0;
eatom = NULL;
vatom = NULL;
@ -121,6 +127,10 @@ void KSpace::modify_params(int narg, char **arg)
if (iarg+2 > narg) error->all(FLERR,"Illegal kspace_modify command");
order = atoi(arg[iarg+1]);
iarg += 2;
} else if (strcmp(arg[iarg],"force") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal kspace_modify command");
accuracy_absolute = atof(arg[iarg+1]);
iarg += 2;
} else if (strcmp(arg[iarg],"gewald") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal kspace_modify command");
g_ewald = atof(arg[iarg+1]);

View File

@ -46,6 +46,13 @@ class KSpace : protected Pointers {
double scale;
double slab_volfactor;
double accuracy; // accuracy of KSpace solver (force units)
double accuracy_absolute; // user-specifed accuracy in force units
double accuracy_relative; // user-specified dimensionless accuracy
// accurary = acc_rel * two_charge_force
double two_charge_force; // force in user units of two point
// charges separated by 1 Angstrom
int evflag,evflag_atom;
int eflag_either,eflag_global,eflag_atom;
int vflag_either,vflag_global,vflag_atom;