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

This commit is contained in:
sjplimp 2007-11-30 21:38:34 +00:00
parent bf7903653b
commit 5d0e722080
2 changed files with 77 additions and 82 deletions
src/KSPACE

View File

@ -795,7 +795,7 @@ void PPPM::deallocate()
void PPPM::set_grid() void PPPM::set_grid()
{ {
// see JCP 109, pg. 7698 for derivation of coefficients // see JCP 109, pg 7698 for derivation of coefficients
// higher order coefficients may be computed if needed // higher order coefficients may be computed if needed
double **acons = memory->create_2d_double_array(8,7,"pppm:acons"); double **acons = memory->create_2d_double_array(8,7,"pppm:acons");
@ -846,119 +846,91 @@ void PPPM::set_grid()
// fluid-occupied volume used to estimate real-space error // fluid-occupied volume used to estimate real-space error
// zprd used rather than zprd_slab // zprd used rather than zprd_slab
double hx,hy,hz;
if (!gewaldflag) if (!gewaldflag)
g_ewald = sqrt(-log(precision*sqrt(natoms*cutoff*xprd*yprd*zprd) / g_ewald = sqrt(-log(precision*sqrt(natoms*cutoff*xprd*yprd*zprd) /
(2.0*q2))) / cutoff; (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 precision
// nz_pppm uses extended zprd_slab instead of zprd // nz_pppm uses extended zprd_slab instead of zprd
// h = 1/g_ewald is upper bound on h such that h*g_ewald <= 1
double h,h1,h2,err,er1,er2,lpr; // reduce it until precision target is met
int ncount;
if (!gridflag) { if (!gridflag) {
h = 1.0; double err;
h1 = 2.0; hx = hy = hz = 1/g_ewald;
ncount = 0; nx_pppm = static_cast<int> (xprd/hx + 1);
err = LARGE; ny_pppm = static_cast<int> (yprd/hy + 1);
er1 = 0.0; nz_pppm = static_cast<int> (zprd_slab/hz + 1);
while (fabs(err) > SMALL) {
lpr = rms(h,xprd,natoms,q2,acons); err = rms(hx,xprd,natoms,q2,acons);
err = log(lpr) - log(precision); while (err > precision) {
er2 = er1; err = rms(hx,xprd,natoms,q2,acons);
er1 = err; nx_pppm++;
h2 = h1; hx = xprd/nx_pppm;
h1 = h;
if ((er1 - er2) == 0.0) h = h1 + er1;
else h = h1 + er1*(h2 - h1)/(er1 - er2);
ncount++;
if (ncount > LARGE) error->all("Cannot compute PPPM X grid spacing");
} }
nx_pppm = static_cast<int> (xprd/h + 1);
ncount = 0; err = rms(hy,yprd,natoms,q2,acons);
err = LARGE; while (err > precision) {
er1 = 0.0; err = rms(hy,yprd,natoms,q2,acons);
while (fabs(err) > SMALL) { ny_pppm++;
lpr = rms(h,yprd,natoms,q2,acons); hy = yprd/ny_pppm;
err = log(lpr) - log(precision);
er2 = er1;
er1 = err;
h2 = h1;
h1 = h;
if ((er1 - er2) == 0.0) h = h1 + er1;
else h = h1 + er1*(h2 - h1)/(er1 - er2);
ncount++;
if (ncount > LARGE) error->all("Cannot compute PPPM Y grid spacing");
} }
ny_pppm = static_cast<int> (yprd/h + 1);
ncount = 0; err = rms(hz,zprd_slab,natoms,q2,acons);
err = LARGE; while (err > precision) {
er1 = 0.0; err = rms(hz,zprd_slab,natoms,q2,acons);
while (fabs(err) > SMALL) { nz_pppm++;
lpr = rms(h,zprd_slab,natoms,q2,acons); hz = zprd_slab/nz_pppm;
err = log(lpr) - log(precision);
er2 = er1;
er1 = err;
h2 = h1;
h1 = h;
if ((er1 - er2) == 0.0) h = h1 + er1;
else h = h1 + er1*(h2 - h1)/(er1 - er2);
ncount++;
if (ncount > LARGE) error->all("Cannot compute PPPM Z grid spacing");
} }
nz_pppm = static_cast<int> (zprd_slab/h + 1);
} }
// convert grid into sizes that are factorable // boost grid size until it is factorable
while (!factorable(nx_pppm)) nx_pppm++; while (!factorable(nx_pppm)) nx_pppm++;
while (!factorable(ny_pppm)) ny_pppm++; while (!factorable(ny_pppm)) ny_pppm++;
while (!factorable(nz_pppm)) nz_pppm++; while (!factorable(nz_pppm)) nz_pppm++;
// adjust g_ewald for new grid // adjust g_ewald for new grid size
double dx = xprd/nx_pppm; hx = xprd/nx_pppm;
double dy = yprd/ny_pppm; hy = yprd/ny_pppm;
double dz = zprd_slab/nz_pppm; hz = zprd_slab/nz_pppm;
if (!gewaldflag) { if (!gewaldflag) {
double gew1,gew2,lprx,lpry,lprz,spr; double gew1,gew2,dgew,f,fmid,hmin,rtb;
int ncount;
gew1 = g_ewald + 0.01; gew1 = 0.0;
g_ewald = gew1;
f = diffpr(hx,hy,hz,q2,acons);
hmin = MIN(hx,MIN(hy,hz));
gew2 = 10/hmin;
g_ewald = gew2;
fmid = diffpr(hx,hy,hz,q2,acons);
if (f*fmid >= 0.0) error->all("Cannot compute PPPM G");
rtb = f < 0.0 ? (dgew=gew2-gew1,gew1) : (dgew=gew1-gew2,gew2);
ncount = 0; ncount = 0;
err = LARGE; while (fabs(dgew) > SMALL && fmid != 0.0) {
er1 = 0.0; dgew *= 0.5;
g_ewald = rtb + dgew;
while (fabs(err) > SMALL) { fmid = diffpr(hx,hy,hz,q2,acons);
lprx = rms(dx,xprd,natoms,q2,acons); if (fmid <= 0.0) rtb = g_ewald;
lpry = rms(dy,yprd,natoms,q2,acons);
lprz = rms(dz,zprd_slab,natoms,q2,acons);
lpr = sqrt(lprx*lprx + lpry*lpry + lprz*lprz) / sqrt(3.0);
spr = 2.0*q2 * exp(-g_ewald*g_ewald*cutoff*cutoff) /
sqrt(natoms*cutoff*xprd*yprd*zprd_slab);
err = log(lpr) - log(spr);
er2 = er1;
er1 = err;
gew2 = gew1;
gew1 = g_ewald;
if ((er1 - er2) == 0.0) g_ewald = gew1 + er1;
else g_ewald = gew1 + er1*(gew2 - gew1)/(er1 - er2);
ncount++; ncount++;
if (ncount > LARGE) error->all("Cannot compute PPPM G"); if (ncount > LARGE) error->all("Cannot compute PPPM G");
} }
} }
// compute final RMS precision // final RMS precision
double lprx = rms(dx,xprd,natoms,q2,acons); double lprx = rms(hx,xprd,natoms,q2,acons);
double lpry = rms(dy,yprd,natoms,q2,acons); double lpry = rms(hy,yprd,natoms,q2,acons);
double lprz = rms(dz,zprd_slab,natoms,q2,acons); double lprz = rms(hz,zprd_slab,natoms,q2,acons);
lpr = sqrt(lprx*lprx + lpry*lpry + lprz*lprz) / sqrt(3.0); double lpr = sqrt(lprx*lprx + lpry*lpry + lprz*lprz) / sqrt(3.0);
double spr = 2.0*q2 * exp(-g_ewald*g_ewald*cutoff*cutoff) / double spr = 2.0*q2 * exp(-g_ewald*g_ewald*cutoff*cutoff) /
sqrt(natoms*cutoff*xprd*yprd*zprd_slab); sqrt(natoms*cutoff*xprd*yprd*zprd_slab);
@ -1019,6 +991,28 @@ double PPPM::rms(double h, double prd, double natoms,
return value; return value;
} }
/* ----------------------------------------------------------------------
compute difference in real-space and kspace RMS precision
------------------------------------------------------------------------- */
double PPPM::diffpr(double hx, double hy, double hz, double q2, double **acons)
{
double lprx,lpry,lprz,kspace_prec,real_prec;
double xprd = domain->xprd;
double yprd = domain->yprd;
double zprd = domain->zprd;
double natoms = atom->natoms;
lprx = rms(hx,xprd,natoms,q2,acons);
lpry = rms(hy,yprd,natoms,q2,acons);
lprz = rms(hz,zprd*slab_volfactor,natoms,q2,acons);
kspace_prec = sqrt(lprx*lprx + lpry*lpry + lprz*lprz) / sqrt(3.0);
real_prec = 2.0*q2 * exp(-g_ewald*g_ewald*cutoff*cutoff) /
sqrt(natoms*cutoff*xprd*yprd*zprd);
double value = kspace_prec - real_prec;
return value;
}
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
denominator for Hockney-Eastwood Green's function denominator for Hockney-Eastwood Green's function
of x,y,z = sin(kx*deltax/2), etc of x,y,z = sin(kx*deltax/2), etc

View File

@ -78,6 +78,7 @@ class PPPM : public KSpace {
void deallocate(); void deallocate();
int factorable(int); int factorable(int);
double rms(double, double, double, double, double **); double rms(double, double, double, double, double **);
double diffpr(double, double, double, double, double **);
void compute_gf_denom(); void compute_gf_denom();
double gf_denom(double, double, double); double gf_denom(double, double, double);
virtual void particle_map(); virtual void particle_map();