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

This commit is contained in:
sjplimp 2010-04-02 16:53:40 +00:00
parent 02ac8178c5
commit 75c51a178d
30 changed files with 3477 additions and 3896 deletions

View File

@ -125,6 +125,7 @@ class Fix : protected Pointers {
virtual void min_clearstore() {}
virtual void min_pushstore() {}
virtual void min_popstore() {}
virtual int min_reset_ref() {return 0;}
virtual void min_step(double, double *) {}
virtual double max_alpha(double *) {return 0.0;}
virtual int min_dof() {return 0;}

View File

@ -27,13 +27,17 @@
#include "modify.h"
#include "compute.h"
#include "error.h"
#include "math_extra.h"
using namespace LAMMPS_NS;
#define MIN(A,B) ((A) < (B)) ? (A) : (B)
#define MAX(A,B) ((A) > (B)) ? (A) : (B)
enum{XYZ,XY,YZ,XZ,ANISO};
enum{NONE,XYZ,XY,YZ,XZ};
enum{ISO,ANISO,TRICLINIC};
#define MAX_LIFO_DEPTH 2 // 3 box0 arrays in *.h dimensioned to this
/* ---------------------------------------------------------------------- */
@ -42,66 +46,118 @@ FixBoxRelax::FixBoxRelax(LAMMPS *lmp, int narg, char **arg) :
{
if (narg < 4) error->all("Illegal fix box/relax command");
scalar_flag = 1;
extscalar = 1;
global_freq = 1;
box_change = 1;
no_change_box = 1;
if (strcmp(arg[3],"xyz") == 0) {
if (narg < 5) error->all("Illegal fix box/relax command");
press_couple = XYZ;
p_target[0] = p_target[1] = p_target[2] = atof(arg[4]);
p_flag[0] = p_flag[1] = p_flag[2] = 1;
if (domain->dimension == 2) p_flag[2] = 0;
} else {
if (strcmp(arg[3],"xy") == 0) press_couple = XY;
else if (strcmp(arg[3],"yz") == 0) press_couple = YZ;
else if (strcmp(arg[3],"xz") == 0) press_couple = XZ;
else if (strcmp(arg[3],"aniso") == 0) press_couple = ANISO;
else error->all("Illegal fix box/relax command");
if (narg < 7) error->all("Illegal fix box/relax command");
if (domain->dimension == 2 &&
(press_couple == XY || press_couple == YZ || press_couple == XZ))
error->all("Invalid fix box/relax command for a 2d simulation");
if (strcmp(arg[4],"NULL") == 0) {
p_target[0] = 0.0;
p_flag[0] = 0;
} else {
p_target[0] = atof(arg[4]);
p_flag[0] = 1;
}
if (strcmp(arg[5],"NULL") == 0) {
p_target[1] = 0.0;
p_flag[1] = 0;
} else {
p_target[1] = atof(arg[5]);
p_flag[1] = 1;
}
if (strcmp(arg[6],"NULL") == 0) {
p_target[2] = 0.0;
p_flag[2] = 0;
} else {
if (domain->dimension == 2)
error->all("Invalid fix box/relax command for a 2d simulation");
p_target[2] = atof(arg[6]);
p_flag[2] = 1;
}
}
pflagsum = p_flag[0] + p_flag[1] + p_flag[2];
// process extra keywords
// default values
pcouple = NONE;
allremap = 1;
vmax = 0.0001;
deviatoric_flag = 0;
nreset_h0 = 0;
int iarg;
if (press_couple == XYZ) iarg = 5;
else iarg = 7;
p_target[0] = p_target[1] = p_target[2] =
p_target[3] = p_target[4] = p_target[5] = 0.0;
// process keywords
dimension = domain->dimension;
int iarg = 3;
while (iarg < narg) {
if (strcmp(arg[iarg],"dilate") == 0) {
if (strcmp(arg[iarg],"iso") == 0) {
if (iarg+4 > narg) error->all("Illegal fix box/relax command");
pcouple = XYZ;
p_target[0] = p_target[1] = p_target[2] = atof(arg[iarg+1]);
p_flag[0] = p_flag[1] = p_flag[2] = 1;
if (dimension == 2) {
p_target[2] = 0.0;
p_flag[2] = 0;
}
iarg += 4;
} else if (strcmp(arg[iarg],"aniso") == 0) {
if (iarg+4 > narg) error->all("Illegal fix box/relax command");
pcouple = NONE;
p_target[0] = p_target[1] = p_target[2] = atof(arg[iarg+1]);
p_flag[0] = p_flag[1] = p_flag[2] = 1;
if (dimension == 2) {
p_target[2] = 0.0;
p_flag[2] = 0;
}
iarg += 4;
} else if (strcmp(arg[iarg],"tri") == 0) {
if (iarg+4 > narg) error->all("Illegal fix box/relax command");
pcouple = NONE;
p_target[0] = p_target[1] = p_target[2] = atof(arg[iarg+1]);
p_flag[0] = p_flag[1] = p_flag[2] = 1;
p_target[3] = p_target[4] = p_target[5] = 0.0;
p_flag[3] = p_flag[4] = p_flag[5] = 1;
if (dimension == 2) {
p_target[2] = p_target[3] = p_target[4] = 0.0;
p_flag[2] = p_flag[3] = p_flag[4] = 0;
}
iarg += 4;
} else if (strcmp(arg[iarg],"x") == 0) {
if (iarg+4 > narg) error->all("Illegal fix box/relax command");
p_target[0] = atof(arg[iarg+1]);
p_flag[0] = 1;
deviatoric_flag = 1;
iarg += 4;
} else if (strcmp(arg[iarg],"y") == 0) {
if (iarg+4 > narg) error->all("Illegal fix box/relax command");
p_target[1] = atof(arg[iarg+1]);
p_flag[1] = 1;
deviatoric_flag = 1;
iarg += 4;
} else if (strcmp(arg[iarg],"z") == 0) {
if (iarg+4 > narg) error->all("Illegal fix box/relax command");
p_target[2] = atof(arg[iarg+1]);
p_flag[2] = 1;
deviatoric_flag = 1;
iarg += 4;
if (dimension == 2)
error->all("Invalid fix box/relax command for a 2d simulation");
} else if (strcmp(arg[iarg],"yz") == 0) {
if (iarg+4 > narg) error->all("Illegal fix box/relax command");
p_target[3] = atof(arg[iarg+1]);
p_flag[3] = 1;
deviatoric_flag = 1;
iarg += 4;
if (dimension == 2)
error->all("Invalid fix box/relax command for a 2d simulation");
} else if (strcmp(arg[iarg],"xz") == 0) {
if (iarg+4 > narg) error->all("Illegal fix box/relax command");
p_target[4] = atof(arg[iarg+1]);
p_flag[4] = 1;
deviatoric_flag = 1;
iarg += 4;
if (dimension == 2)
error->all("Invalid fix box/relax command for a 2d simulation");
} else if (strcmp(arg[iarg],"xy") == 0) {
if (iarg+4 > narg) error->all("Illegal fix box/relax command");
p_target[5] = atof(arg[iarg+1]);
p_flag[5] = 1;
deviatoric_flag = 1;
iarg += 4;
} else if (strcmp(arg[iarg],"couple") == 0) {
if (iarg+2 > narg) error->all("Illegal fix box/relax command");
if (strcmp(arg[iarg+1],"xyz") == 0) pcouple = XYZ;
else if (strcmp(arg[iarg+1],"xy") == 0) pcouple = XY;
else if (strcmp(arg[iarg+1],"yz") == 0) pcouple = YZ;
else if (strcmp(arg[iarg+1],"xz") == 0) pcouple = XZ;
else if (strcmp(arg[iarg+1],"none") == 0) pcouple = NONE;
else error->all("Illegal fix box/relax command");
iarg += 2;
} else if (strcmp(arg[iarg],"dilate") == 0) {
if (iarg+2 > narg) error->all("Illegal fix box/relax command");
if (strcmp(arg[iarg+1],"all") == 0) allremap = 1;
else if (strcmp(arg[iarg+1],"partial") == 0) allremap = 0;
@ -111,24 +167,29 @@ FixBoxRelax::FixBoxRelax(LAMMPS *lmp, int narg, char **arg) :
if (iarg+2 > narg) error->all("Illegal fix box/relax command");
vmax = atof(arg[iarg+1]);
iarg += 2;
} else if (strcmp(arg[iarg],"nreset") == 0) {
if (iarg+2 > narg) error->all("Illegal fix box/relax command");
nreset_h0 = atoi(arg[iarg+1]);
if (nreset_h0 < 0) error->all("Illegal fix box/relax command");
iarg += 2;
} else error->all("Illegal fix box/relax command");
}
// error checks
if (press_couple == XY && (p_flag[0] == 0 || p_flag[1] == 0))
error->all("Illegal fix box/relax command");
if (press_couple == YZ && (p_flag[1] == 0 || p_flag[2] == 0))
error->all("Illegal fix box/relax command");
if (press_couple == XZ && (p_flag[0] == 0 || p_flag[2] == 0))
error->all("Illegal fix box/relax command");
if (dimension == 2 && (p_flag[2] || p_flag[3] || p_flag[4]))
error->all("Invalid fix box/relax command for a 2d simulation");
if (dimension == 2 && (pcouple == YZ || pcouple == XZ))
error->all("Invalid fix box/relax command for a 2d simulation");
if (press_couple == XY && p_target[0] != p_target[1])
error->all("Illegal fix box/relax command");
if (press_couple == YZ && p_target[1] != p_target[2])
error->all("Illegal fix box/relax command");
if (press_couple == XZ && p_target[0] != p_target[2])
error->all("Illegal fix box/relax command");
if (pcouple == XYZ && (p_flag[0] == 0 || p_flag[1] == 0 || p_flag[2] == 0))
error->all("Invalid fix box/relax command pressure settings");
if (pcouple == XY && (p_flag[0] == 0 || p_flag[1] == 0))
error->all("Invalid fix box/relax command pressure settings");
if (pcouple == YZ && (p_flag[1] == 0 || p_flag[2] == 0))
error->all("Invalid fix box/relax command pressure settings");
if (pcouple == XZ && (p_flag[0] == 0 || p_flag[2] == 0))
error->all("Invalid fix box/relax command pressure settings");
if (p_flag[0] && domain->xperiodic == 0)
error->all("Cannot use fix box/relax on a non-periodic dimension");
@ -136,9 +197,37 @@ FixBoxRelax::FixBoxRelax(LAMMPS *lmp, int narg, char **arg) :
error->all("Cannot use fix box/relax on a non-periodic dimension");
if (p_flag[2] && domain->zperiodic == 0)
error->all("Cannot use fix box/relax on a non-periodic dimension");
if (p_flag[3] && domain->zperiodic == 0)
error->all("Cannot use fix box/relax on a 2nd non-periodic dimension");
if (p_flag[4] && domain->zperiodic == 0)
error->all("Cannot use fix box/relax on a 2nd non-periodic dimension");
if (p_flag[5] && domain->yperiodic == 0)
error->all("Cannot use fix box/relax on a 2nd non-periodic dimension");
if (!domain->triclinic && (p_flag[3] || p_flag[4] || p_flag[5]))
error->all("Can not specify Pxy/Pxz/Pyz in "
"fix box/relax with non-triclinic box");
if (pcouple == XYZ &&
(p_target[0] != p_target[1] || p_target[0] != p_target[2]))
error->all("Invalid fix box/relax pressure settings");
if (pcouple == XY && p_target[0] != p_target[1])
error->all("Invalid fix box/relax pressure settings");
if (pcouple == YZ && p_target[1] != p_target[2])
error->all("Invalid fix box/relax pressure settings");
if (pcouple == XZ && p_target[0] != p_target[2])
error->all("Invalid fix box/relax pressure settings");
if (vmax <= 0.0) error->all("Illegal fix box/relax command");
// pstyle = TRICLINIC if any off-diagonal term is controlled -> 6 dof
// else pstyle = ISO if XYZ coupling or XY coupling in 2d -> 1 dof
// else pstyle = ANISO -> 3 dof
if (p_flag[3] || p_flag[4] || p_flag[5]) pstyle = TRICLINIC;
else if (pcouple == XYZ || (dimension == 2 && pcouple == XY)) pstyle = ISO;
else pstyle = ANISO;
// create a new compute temp style
// id = fix-ID + temp
// compute group = all since pressure is always global (group all)
@ -221,13 +310,6 @@ void FixBoxRelax::init()
if (icompute < 0) error->all("Pressure ID for fix box/relax does not exist");
pressure = modify->compute[icompute];
// initial box dimensions
xprdinit = domain->xprd;
yprdinit = domain->yprd;
zprdinit = domain->zprd;
if (dimension == 3) volinit = domain->xprd*domain->yprd*domain->zprd;
else volinit = domain->xprd*domain->yprd;
pv2e = 1.0 / force->nktv2p;
// detect if any rigid fixes exist so rigid bodies move when box is remapped
@ -245,6 +327,19 @@ void FixBoxRelax::init()
for (int i = 0; i < modify->nfix; i++)
if (modify->fix[i]->rigid_flag) rfix[nrigid++] = i;
}
// initial box dimensions
xprdinit = domain->xprd;
yprdinit = domain->yprd;
zprdinit = domain->zprd;
if (dimension == 2) zprdinit = 1.0;
vol0 = xprdinit * yprdinit * zprdinit;
// hydrostatic target pressure and deviatoric target stress
compute_press_target();
if (deviatoric_flag) compute_sigma();
}
/* ----------------------------------------------------------------------
@ -253,12 +348,11 @@ void FixBoxRelax::init()
double FixBoxRelax::min_energy(double *fextra)
{
double eng,scale,scalex,scaley,scalez;
double eng,scale,scalex,scaley,scalez,scalevol;
double t_current = temperature->compute_scalar();
if (press_couple == XYZ) {
double tmp = pressure->compute_scalar();
} else {
if (pstyle == ISO) double tmp = pressure->compute_scalar();
else {
temperature->compute_vector();
pressure->compute_vector();
}
@ -272,14 +366,14 @@ double FixBoxRelax::min_energy(double *fextra)
// returned eng = PV must be in units of energy
// returned fextra must likewise be in units of energy
if (press_couple == XYZ) {
if (pstyle == ISO) {
scale = domain->xprd/xprdinit;
if (dimension == 3) {
eng = pv2e * p_target[0] * (scale*scale*scale-1.0)*volinit;
fextra[0] = pv2e * (p_current[0] - p_target[0])*3.0*scale*scale*volinit;
eng = pv2e * p_target[0] * (scale*scale*scale-1.0)*vol0;
fextra[0] = pv2e * (p_current[0] - p_target[0])*3.0*scale*scale*vol0;
} else {
eng = pv2e * p_target[0] * (scale*scale-1.0)*volinit;
fextra[0] = pv2e * (p_current[0] - p_target[0])*2.0*scale*volinit;
eng = pv2e * p_target[0] * (scale*scale-1.0)*vol0;
fextra[0] = pv2e * (p_current[0] - p_target[0])*2.0*scale*vol0;
}
} else {
@ -288,15 +382,38 @@ double FixBoxRelax::min_energy(double *fextra)
if (p_flag[0]) scalex = domain->xprd/xprdinit;
if (p_flag[1]) scaley = domain->yprd/yprdinit;
if (p_flag[2]) scalez = domain->zprd/zprdinit;
eng = pv2e * (p_flag[0]*p_target[0] + p_flag[1]*p_target[1] +
p_flag[2]*p_target[2])/pflagsum *
(scalex*scaley*scalez-1.0)*volinit;
scalevol = scalex*scaley*scalez;
eng = pv2e * p_hydro * (scalevol-1.0)*vol0;
if (p_flag[0])
fextra[0] = pv2e * (p_current[0] - p_target[0])*scaley*scalez*volinit;
fextra[0] = pv2e * (p_current[0] - p_hydro)*scaley*scalez*vol0;
if (p_flag[1])
fextra[1] = pv2e * (p_current[1] - p_target[1])*scalex*scalez*volinit;
fextra[1] = pv2e * (p_current[1] - p_hydro)*scalex*scalez*vol0;
if (p_flag[2])
fextra[2] = pv2e * (p_current[2] - p_target[2])*scalex*scaley*volinit;
fextra[2] = pv2e * (p_current[2] - p_hydro)*scalex*scaley*vol0;
if (pstyle == TRICLINIC) {
fextra[3] = fextra[4] = fextra[5] = 0.0;
if (p_flag[3])
fextra[3] = pv2e*p_current[3]*scaley*yprdinit*scalex*xprdinit*yprdinit;
if (p_flag[4])
fextra[4] = pv2e*p_current[4]*scalex*xprdinit*scaley*yprdinit*xprdinit;
if (p_flag[5])
fextra[5] = pv2e*p_current[5]*scalex*xprdinit*scalez*zprdinit*xprdinit;
}
if (deviatoric_flag) {
compute_deviatoric();
if (p_flag[0]) fextra[0] -= fdev[0]*xprdinit;
if (p_flag[1]) fextra[1] -= fdev[1]*yprdinit;
if (p_flag[2]) fextra[2] -= fdev[2]*zprdinit;
if (pstyle == TRICLINIC) {
if (p_flag[3]) fextra[3] -= fdev[3]*yprdinit;
if (p_flag[4]) fextra[4] -= fdev[4]*xprdinit;
if (p_flag[5]) fextra[5] -= fdev[5]*xprdinit;
}
eng += compute_strain_energy();
}
}
return eng;
@ -319,6 +436,11 @@ void FixBoxRelax::min_store()
s0[0] = (boxhi0[current_lifo][0]-boxlo0[current_lifo][0])/xprdinit;
s0[1] = (boxhi0[current_lifo][1]-boxlo0[current_lifo][1])/yprdinit;
s0[2] = (boxhi0[current_lifo][2]-boxlo0[current_lifo][2])/zprdinit;
if (pstyle == TRICLINIC) {
boxtilt0[current_lifo][0] = domain->yz;
boxtilt0[current_lifo][1] = domain->xz;
boxtilt0[current_lifo][2] = domain->xy;
}
}
/* ----------------------------------------------------------------------
@ -340,7 +462,6 @@ void FixBoxRelax::min_pushstore()
error->all("Attempt to push beyond stack limit in fix box/relax");
return;
}
current_lifo++;
}
@ -355,24 +476,51 @@ void FixBoxRelax::min_popstore()
error->all("Attempt to pop empty stack in fix box/relax");
return;
}
current_lifo--;
}
/* ----------------------------------------------------------------------
check if time to reset reference state. If so, do so.
------------------------------------------------------------------------- */
int FixBoxRelax::min_reset_ref()
{
int itmp = 0;
// if nreset_h0 > 0, reset reference box
// every nreset_h0 timesteps
// only needed for deviatoric external stress
if (deviatoric_flag && nreset_h0 > 0) {
int delta = update->ntimestep - update->beginstep;
if (delta % nreset_h0 == 0) {
compute_sigma();
itmp = 1;
}
}
return itmp;
}
/* ----------------------------------------------------------------------
change the box dimensions by fraction ds = alpha*hextra
------------------------------------------------------------------------- */
void FixBoxRelax::min_step(double alpha, double *hextra)
{
if (press_couple == XYZ) {
if (pstyle == ISO) {
ds[0] = ds[1] = ds[2] = alpha*hextra[0];
} else {
ds[0] = ds[1] = ds[2] = 0.0;
if (p_flag[0]) ds[0] = alpha*hextra[0];
if (p_flag[1]) ds[1] = alpha*hextra[1];
if (p_flag[2]) ds[2] = alpha*hextra[2];
if (pstyle == TRICLINIC) {
ds[3] = ds[4] = ds[5] = 0.0;
if (p_flag[3]) ds[3] = alpha*hextra[3];
if (p_flag[4]) ds[4] = alpha*hextra[4];
if (p_flag[5]) ds[5] = alpha*hextra[5];
}
}
remap();
}
@ -382,12 +530,17 @@ void FixBoxRelax::min_step(double alpha, double *hextra)
double FixBoxRelax::max_alpha(double *hextra)
{
double alpha = 0.0;
if (press_couple == XYZ) alpha = vmax/fabs(hextra[0]);
double alpha = 1.0;
if (pstyle == ISO) alpha = vmax/fabs(hextra[0]);
else {
alpha = vmax/fabs(hextra[0]);
alpha = MIN(alpha,vmax/fabs(hextra[1]));
alpha = MIN(alpha,vmax/fabs(hextra[2]));
if (p_flag[0]) alpha = MIN(alpha,vmax/fabs(hextra[0]));
if (p_flag[1]) alpha = MIN(alpha,vmax/fabs(hextra[1]));
if (p_flag[2]) alpha = MIN(alpha,vmax/fabs(hextra[2]));
if (pstyle == TRICLINIC) {
if (p_flag[3]) alpha = MIN(alpha,vmax/fabs(hextra[3]));
if (p_flag[4]) alpha = MIN(alpha,vmax/fabs(hextra[4]));
if (p_flag[5]) alpha = MIN(alpha,vmax/fabs(hextra[5]));
}
}
return alpha;
}
@ -398,7 +551,8 @@ double FixBoxRelax::max_alpha(double *hextra)
int FixBoxRelax::min_dof()
{
if (press_couple == XYZ) return 1;
if (pstyle == ISO) return 1;
if (pstyle == TRICLINIC) return 6;
return 3;
}
@ -441,8 +595,16 @@ void FixBoxRelax::remap()
ctr = 0.5 * (currentBoxLo0 + currentBoxHi0);
domain->boxlo[i] = currentBoxLo0 + (currentBoxLo0-ctr)*ds[i]/s0[i];
domain->boxhi[i] = currentBoxHi0 + (currentBoxHi0-ctr)*ds[i]/s0[i];
if (domain->boxlo[i] >= domain->boxhi[i])
error->all("fix box/relax generated negative dimension");
}
if (pstyle == TRICLINIC) {
if (p_flag[3]) domain->yz = boxtilt0[current_lifo][0]+ds[3]*yprdinit;
if (p_flag[4]) domain->xz = boxtilt0[current_lifo][1]+ds[4]*xprdinit;
if (p_flag[5]) domain->xy = boxtilt0[current_lifo][2]+ds[5]*xprdinit;
}
domain->set_global_box();
domain->set_local_box();
@ -466,25 +628,36 @@ void FixBoxRelax::couple()
{
double *tensor = pressure->vector;
if (press_couple == XYZ)
if (pstyle == ISO)
p_current[0] = p_current[1] = p_current[2] = pressure->scalar;
else if (press_couple == XY) {
else if (pcouple == XYZ) {
double ave = 1.0/3.0 * (tensor[0] + tensor[1] + tensor[2]);
p_current[0] = p_current[1] = p_current[2] = ave;
} else if (pcouple == XY) {
double ave = 0.5 * (tensor[0] + tensor[1]);
p_current[0] = p_current[1] = ave;
p_current[2] = tensor[2];
} else if (press_couple == YZ) {
} else if (pcouple == YZ) {
double ave = 0.5 * (tensor[1] + tensor[2]);
p_current[1] = p_current[2] = ave;
p_current[0] = tensor[0];
} else if (press_couple == XZ) {
} else if (pcouple == XZ) {
double ave = 0.5 * (tensor[0] + tensor[2]);
p_current[0] = p_current[2] = ave;
p_current[1] = tensor[1];
} else if (press_couple == ANISO) {
} else {
p_current[0] = tensor[0];
p_current[1] = tensor[1];
p_current[2] = tensor[2];
}
// switch order from xy-xz-yz to Voigt
if (pstyle == TRICLINIC) {
p_current[3] = tensor[5];
p_current[4] = tensor[4];
p_current[5] = tensor[3];
}
}
/* ---------------------------------------------------------------------- */
@ -540,3 +713,187 @@ int FixBoxRelax::modify_param(int narg, char **arg)
}
return 0;
}
/* ----------------------------------------------------------------------
compute sigma tensor (needed whenever reference box is reset)
-----------------------------------------------------------------------*/
void FixBoxRelax::compute_sigma()
{
double pdevmod[3][3],pdeviatoric[3][3],htmp[3][3];
double tmp1[3][3],sigma_tensor[3][3],h_invtmp[3][3];
// reset reference box dimensions
xprdinit = domain->xprd;
yprdinit = domain->yprd;
zprdinit = domain->zprd;
if (dimension == 2) zprdinit = 1.0;
vol0 = xprdinit * yprdinit * zprdinit;
h0[0] = domain->h[0];
h0[1] = domain->h[1];
h0[2] = domain->h[2];
h0[3] = domain->h[3];
h0[4] = domain->h[4];
h0[5] = domain->h[5];
h0_inv[0] = domain->h_inv[0];
h0_inv[1] = domain->h_inv[1];
h0_inv[2] = domain->h_inv[2];
h0_inv[3] = domain->h_inv[3];
h0_inv[4] = domain->h_inv[4];
h0_inv[5] = domain->h_inv[5];
htmp[0][0] = h0[0];
htmp[1][1] = h0[1];
htmp[2][2] = h0[2];
htmp[1][2] = h0[3];
htmp[0][2] = h0[4];
htmp[0][1] = h0[5];
htmp[2][1] = 0.0;
htmp[2][0] = 0.0;
htmp[1][0] = 0.0;
h_invtmp[0][0] = h0_inv[0];
h_invtmp[1][1] = h0_inv[1];
h_invtmp[2][2] = h0_inv[2];
h_invtmp[1][2] = h0_inv[3];
h_invtmp[0][2] = h0_inv[4];
h_invtmp[0][1] = h0_inv[5];
h_invtmp[2][1] = 0.0;
h_invtmp[2][0] = 0.0;
h_invtmp[1][0] = 0.0;
// compute target deviatoric stress tensor pdevmod
pdeviatoric[0][0] = pdeviatoric[1][1] = pdeviatoric[2][2] = 0.0;
if (p_flag[0]) pdeviatoric[0][0] = p_target[0] - p_hydro;
if (p_flag[1]) pdeviatoric[1][1] = p_target[1] - p_hydro;
if (p_flag[2]) pdeviatoric[2][2] = p_target[2] - p_hydro;
pdeviatoric[1][2] = pdeviatoric[2][1] = p_target[3];
pdeviatoric[0][2] = pdeviatoric[2][0] = p_target[4];
pdeviatoric[0][1] = pdeviatoric[1][0] = p_target[5];
// Modify to account for off-diagonal terms
// These equations come from the stationarity relation:
// Pdev,sys = Pdev,targ*hinv^t*hdiag
// where:
// Pdev,sys is the system deviatoric stress tensor,
// Pdev,targ = pdeviatoric, effective target deviatoric stress
// hinv^t is the transpose of the inverse h tensor
// hdiag is the diagonal part of the h tensor
pdeviatoric[1][1] -= pdeviatoric[1][2]*h0_inv[3]*h0[1];
pdeviatoric[0][1] -= pdeviatoric[0][2]*h0_inv[3]*h0[1];
pdeviatoric[1][0] = pdeviatoric[0][1];
pdeviatoric[0][0] -= pdeviatoric[0][1]*h0_inv[5]*h0[0] +
pdeviatoric[0][2]*h0_inv[4]*h0[0];
// compute symmetric sigma tensor
MathExtra::times3(h_invtmp,pdeviatoric,tmp1);
MathExtra::times3_transpose(tmp1,h_invtmp,sigma_tensor);
MathExtra::scalar_times3(vol0,sigma_tensor);
sigma[0] = sigma_tensor[0][0];
sigma[1] = sigma_tensor[1][1];
sigma[2] = sigma_tensor[2][2];
sigma[3] = sigma_tensor[1][2];
sigma[4] = sigma_tensor[0][2];
sigma[5] = sigma_tensor[0][1];
}
/* ----------------------------------------------------------------------
compute strain energy
-----------------------------------------------------------------------*/
double FixBoxRelax::compute_strain_energy()
{
// compute strain energy = 0.5*Tr(sigma*h*h^t) in energy units
double* h = domain->h;
double d0,d1,d2;
if (dimension == 3) {
d0 =
sigma[0]*(h[0]*h[0]+h[5]*h[5]+h[4]*h[4]) +
sigma[5]*( h[1]*h[5]+h[3]*h[4]) +
sigma[4]*( h[2]*h[4]);
d1 =
sigma[5]*( h[5]*h[1]+h[4]*h[3]) +
sigma[1]*( h[1]*h[1]+h[3]*h[3]) +
sigma[3]*( h[2]*h[3]);
d2 =
sigma[4]*( h[4]*h[2]) +
sigma[3]*( h[3]*h[2]) +
sigma[2]*( h[2]*h[2]);
} else {
d0 = sigma[0]*(h[0]*h[0]+h[5]*h[5]) + sigma[5]*h[1]*h[5];
d1 = sigma[5]*h[5]*h[1] + sigma[1]*h[1]*h[1];
d2 = 0.0;
}
double energy = 0.5*(d0+d1+d2)*pv2e;
return energy;
}
/* ----------------------------------------------------------------------
compute deviatoric barostat force = h*sigma*h^t
-----------------------------------------------------------------------*/
void FixBoxRelax::compute_deviatoric()
{
double* h = domain->h;
// [ 0 5 4 ] [ 0 5 4 ] [ 0 5 4 ]
// [ 5 1 3 ] = [ - 1 3 ] [ 5 1 3 ]
// [ 4 3 2 ] [ - - 2 ] [ 4 3 2 ]
if (dimension == 3) {
fdev[0] = pv2e*(h[0]*sigma[0]+h[5]*sigma[5]+h[4]*sigma[4]);
fdev[1] = pv2e*(h[1]*sigma[1]+h[3]*sigma[3]);
fdev[2] = pv2e*(h[2]*sigma[2]);
fdev[3] = pv2e*(h[1]*sigma[3]+h[3]*sigma[2]);
fdev[4] = pv2e*(h[0]*sigma[4]+h[5]*sigma[3]+h[4]*sigma[2]);
fdev[5] = pv2e*(h[0]*sigma[5]+h[5]*sigma[1]+h[4]*sigma[3]);
} else {
fdev[0] = pv2e*(h[0]*sigma[0]+h[5]*sigma[5]);
fdev[1] = pv2e*(h[1]*sigma[1]);
fdev[5] = pv2e*(h[0]*sigma[5]+h[5]*sigma[1]);
}
}
/* ----------------------------------------------------------------------
compute hydrostatic target pressure
-----------------------------------------------------------------------*/
void FixBoxRelax::compute_press_target()
{
pflagsum = p_flag[0] + p_flag[1] + p_flag[2];
p_hydro = 0.0;
for (int i = 0; i < 3; i++)
if (p_flag[i]) p_hydro += p_target[i];
if (pflagsum) p_hydro /= pflagsum;
for (int i = 0; i < 3; i++) {
if (p_flag[i] && fabs(p_hydro - p_target[i] > 1.0e-6)) deviatoric_flag = 1;
}
if (pstyle == TRICLINIC) {
for (int i = 3; i < 6; i++)
if (p_flag[i] && fabs(p_target[i]) > 1.0e-6) deviatoric_flag = 1;
}
}
/* ----------------------------------------------------------------------
compute PV and strain energy for access to the user
/* ---------------------------------------------------------------------- */
double FixBoxRelax::compute_scalar()
{
double ftmp[6] = {0.0,0.0,0.0,0.0,0.0,0.0};
if (update->ntimestep == 0) return 0.0;
return min_energy(ftmp);
}

View File

@ -22,8 +22,6 @@ FixStyle(box/relax,FixBoxRelax)
#include "fix.h"
const int MAX_LIFO_DEPTH = 2; // to meet the needs of min_hftn
namespace LAMMPS_NS {
class FixBoxRelax : public Fix {
@ -38,6 +36,7 @@ class FixBoxRelax : public Fix {
void min_clearstore();
void min_pushstore();
void min_popstore();
int min_reset_ref();
void min_step(double, double *);
double max_alpha(double *);
int min_dof();
@ -45,19 +44,19 @@ class FixBoxRelax : public Fix {
int modify_param(int, char **);
private:
int p_flag[3];
int press_couple,allremap;
int p_flag[6];
int pstyle,pcouple,allremap;
int dimension;
double p_target[3],p_current[3];
double dilation[3];
double volinit,xprdinit,yprdinit,zprdinit;
double p_target[6],p_current[6];
double vol0,xprdinit,yprdinit,zprdinit;
double vmax,pv2e,pflagsum;
int current_lifo; // LIFO stack pointer
double boxlo0[MAX_LIFO_DEPTH][3]; // box bounds at start of line search
double boxhi0[MAX_LIFO_DEPTH][3];
double s0[6]; // scale matrix in Voigt notation
double ds[6]; // increment in scale matrix
int current_lifo; // LIFO stack pointer
double boxlo0[2][3]; // box bounds at start of line search
double boxhi0[2][3];
double boxtilt0[2][3]; // xy,xz,yz tilts at start of line search
double s0[3]; // scale matrix at start of line search
double ds[6]; // increment in scale matrix
char *id_temp,*id_press;
class Compute *temperature,*pressure;
@ -66,8 +65,25 @@ class FixBoxRelax : public Fix {
int nrigid;
int *rfix;
double sigma[6]; // scaled target stress
double utsigma[3]; // weighting for upper-tri elements
// of modified sigma
int sigmamod_flag; // 1 if modified sigma to be used
double fdev[6]; // Deviatoric force on cell
int deviatoric_flag; // 0 if target stress tensor is hydrostatic
double h0[6]; // h_inv of reference (zero strain) box
double h0_inv[6]; // h_inv of reference (zero strain) box
int nreset_h0; // interval for resetting h0
double p_hydro; // hydrostatic component of target stress
void remap();
void couple();
void compute_sigma();
void compute_deviatoric();
double compute_strain_energy();
void compute_press_target();
double compute_scalar();
};
}

View File

@ -181,14 +181,14 @@ FixDeform::FixDeform(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg)
if ((set[0].style && domain->xperiodic == 0) ||
(set[1].style && domain->yperiodic == 0) ||
(set[2].style && domain->zperiodic == 0))
error->all("Cannot fix deform on a non-periodic boundary");
error->all("Cannot use fix deform on a non-periodic boundary");
if (set[3].style && (domain->yperiodic == 0 || domain->zperiodic == 0))
error->all("Cannot fix deform on a non-periodic boundary");
if (set[4].style && (domain->xperiodic == 0 || domain->zperiodic == 0))
error->all("Cannot fix deform on a non-periodic boundary");
if (set[5].style && (domain->xperiodic == 0 || domain->yperiodic == 0))
error->all("Cannot fix deform on a non-periodic boundary");
if (set[3].style && domain->zperiodic == 0)
error->all("Cannot use fix deform on a 2nd non-periodic boundary");
if (set[4].style && domain->zperiodic == 0)
error->all("Cannot use fix deform on a 2nd non-periodic boundary");
if (set[5].style && domain->yperiodic == 0)
error->all("Cannot use fix deform on a 2nd non-periodic boundary");
// apply scaling to FINAL,DELTA,VEL,WIGGLE since they have distance/vel units

1872
src/fix_nh.cpp Normal file

File diff suppressed because it is too large Load Diff

119
src/fix_nh.h Normal file
View File

@ -0,0 +1,119 @@
/* ----------------------------------------------------------------------
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.
------------------------------------------------------------------------- */
#ifndef LMP_FIX_NH_H
#define LMP_FIX_NH_H
#include "fix.h"
namespace LAMMPS_NS {
class FixNH : public Fix {
public:
FixNH(class LAMMPS *, int, char **);
virtual ~FixNH();
int setmask();
virtual void init();
void setup(int);
virtual void initial_integrate(int);
virtual void final_integrate();
void initial_integrate_respa(int, int, int);
void final_integrate_respa(int, int);
double compute_scalar();
double compute_vector(int);
void write_restart(FILE *);
void restart(char *);
int modify_param(int, char **);
void reset_dt();
protected:
int dimension,which;
double dtv,dtf,dthalf,dt4,dt8;
double boltz,nktv2p,tdof;
double vol0,t0;
double t_start,t_stop;
double t_current,t_target;
double t_freq;
int tstat_flag; // 1 if control T
int pstat_flag; // 1 if control P
int pstyle,pcouple,allremap;
int p_flag[6]; // 1 if control P on this dim, 0 if not
double p_start[6],p_stop[6];
double p_freq[6],p_target[6];
double omega[6],omega_dot[6];
double omega_mass[6];
double p_current[6],dilation[6];
double drag,drag_factor; // drag factor on particle thermostat
double factor[6]; // velocity scaling due to barostat
int kspace_flag; // 1 if KSpace invoked, 0 if not
int nrigid; // number of rigid fixes
int *rfix; // indices of rigid fixes
int nlevels_respa;
double *step_respa;
char *id_temp,*id_press;
class Compute *temperature,*pressure;
int tflag,pflag;
double *eta,*eta_dot; // chain thermostat for particles
double *eta_dotdot;
double *eta_mass;
int mtchain; // length of chain
double *etap; // chain thermostat for barostat
double *etap_dot;
double *etap_dotdot;
double *etap_mass;
int mpchain; // length of chain
int mtk_flag; // 0 if using Hoover barostat
int pdim; // number of barostatted dims
double mvv_current[3]; // diagonal of KE tensor
double mtk_factor; // MTK factor
double p_freq_max; // maximum barostat frequency
double p_hydro; // hydrostatic target pressure
int nc_tchain,nc_pchain;
double factor_eta;
double sigma[6]; // scaled target stress
double fdev[6]; // deviatoric force on barostat
int deviatoric_flag; // 0 if target stress tensor is hydrostatic
double h0_inv[6]; // h_inv of reference (zero strain) box
int nreset_h0; // interval for resetting h0
void couple();
void couple_ke();
void remap();
void nhc_temp_integrate();
void nhc_press_integrate();
virtual void nve_x(); // may be overwritten by child classes
virtual void nve_v();
virtual void nh_v_press();
virtual void nh_v_temp();
void compute_sigma();
void compute_deviatoric();
double compute_strain_energy();
void compute_press_target();
void nh_omega_dot();
};
}
#endif

238
src/fix_nh_asphere.cpp Normal file
View File

@ -0,0 +1,238 @@
/* ----------------------------------------------------------------------
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 author: Mike Brown (SNL)
------------------------------------------------------------------------- */
#include "string.h"
#include "stdlib.h"
#include "math.h"
#include "math_extra.h"
#include "fix_nh_asphere.h"
#include "atom.h"
#include "atom_vec.h"
#include "group.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
enum{NOBIAS,BIAS};
/* ---------------------------------------------------------------------- */
FixNHAsphere::FixNHAsphere(LAMMPS *lmp, int narg, char **arg) :
FixNH(lmp, narg, arg)
{
inertia =
memory->create_2d_double_array(atom->ntypes+1,3,"fix_nvt_asphere:inertia");
if (!atom->quat_flag || !atom->angmom_flag || !atom->torque_flag ||
!atom->avec->shape_type)
error->all("Fix nvt/nph/npt asphere requires atom attributes "
"quat, angmom, torque, shape");
if (atom->radius_flag || atom->rmass_flag)
error->all("Fix nvt/nph/npt asphere cannot be used with atom attributes "
"diameter or rmass");
}
/* ---------------------------------------------------------------------- */
FixNHAsphere::~FixNHAsphere()
{
memory->destroy_2d_double_array(inertia);
}
/* ---------------------------------------------------------------------- */
void FixNHAsphere::init()
{
// check that all particles are finite-size
// no point particles allowed, spherical is OK
double **shape = atom->shape;
int *type = atom->type;
int *mask = atom->mask;
int nlocal = atom->nlocal;
if (igroup == atom->firstgroup) nlocal = atom->nfirst;
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit)
if (shape[type[i]][0] == 0.0)
error->one("Fix nvt/nph/npt asphere requires extended particles");
FixNH::init();
calculate_inertia();
}
/* ----------------------------------------------------------------------
Richardson iteration to update quaternion accurately
------------------------------------------------------------------------- */
void FixNHAsphere::richardson(double *q, double *m, double *moments)
{
// compute omega at 1/2 step from m at 1/2 step and q at 0
double w[3];
omega_from_mq(q,m,moments,w);
// full update from dq/dt = 1/2 w q
double wq[4];
MathExtra::multiply_vec_quat(w,q,wq);
double qfull[4];
qfull[0] = q[0] + dtq * wq[0];
qfull[1] = q[1] + dtq * wq[1];
qfull[2] = q[2] + dtq * wq[2];
qfull[3] = q[3] + dtq * wq[3];
MathExtra::normalize4(qfull);
// 1st half of update from dq/dt = 1/2 w q
double qhalf[4];
qhalf[0] = q[0] + 0.5*dtq * wq[0];
qhalf[1] = q[1] + 0.5*dtq * wq[1];
qhalf[2] = q[2] + 0.5*dtq * wq[2];
qhalf[3] = q[3] + 0.5*dtq * wq[3];
MathExtra::normalize4(qhalf);
// re-compute omega at 1/2 step from m at 1/2 step and q at 1/2 step
// recompute wq
omega_from_mq(qhalf,m,moments,w);
MathExtra::multiply_vec_quat(w,qhalf,wq);
// 2nd half of update from dq/dt = 1/2 w q
qhalf[0] += 0.5*dtq * wq[0];
qhalf[1] += 0.5*dtq * wq[1];
qhalf[2] += 0.5*dtq * wq[2];
qhalf[3] += 0.5*dtq * wq[3];
MathExtra::normalize4(qhalf);
// corrected Richardson update
q[0] = 2.0*qhalf[0] - qfull[0];
q[1] = 2.0*qhalf[1] - qfull[1];
q[2] = 2.0*qhalf[2] - qfull[2];
q[3] = 2.0*qhalf[3] - qfull[3];
MathExtra::normalize4(q);
}
/* ----------------------------------------------------------------------
compute omega from angular momentum
w = omega = angular velocity in space frame
wbody = angular velocity in body frame
project space-frame angular momentum onto body axes
and divide by principal moments
------------------------------------------------------------------------- */
void FixNHAsphere::omega_from_mq(double *q, double *m, double *inertia,
double *w)
{
double rot[3][3];
MathExtra::quat_to_mat(q,rot);
double wbody[3];
MathExtra::transpose_times_column3(rot,m,wbody);
wbody[0] /= inertia[0];
wbody[1] /= inertia[1];
wbody[2] /= inertia[2];
MathExtra::times_column3(rot,wbody,w);
}
/* ----------------------------------------------------------------------
principal moments of inertia for ellipsoids
------------------------------------------------------------------------- */
void FixNHAsphere::calculate_inertia()
{
double *mass = atom->mass;
double **shape = atom->shape;
for (int i = 1; i <= atom->ntypes; i++) {
inertia[i][0] = 0.2*mass[i] *
(shape[i][1]*shape[i][1]+shape[i][2]*shape[i][2]);
inertia[i][1] = 0.2*mass[i] *
(shape[i][0]*shape[i][0]+shape[i][2]*shape[i][2]);
inertia[i][2] = 0.2*mass[i] *
(shape[i][0]*shape[i][0]+shape[i][1]*shape[i][1]);
}
}
/* ----------------------------------------------------------------------
perform half-step update of velocities
-----------------------------------------------------------------------*/
void FixNHAsphere::nve_v()
{
// standard nhc_nve_v velocity update
FixNH::nve_v();
int *type = atom->type;
double **quat = atom->quat;
double **angmom = atom->angmom;
double **torque = atom->torque;
int *mask = atom->mask;
int nlocal = atom->nlocal;
if (igroup == atom->firstgroup) nlocal = atom->nfirst;
// set timestep here since dt may have changed or come via rRESPA
dtq = 0.5 * dtv;
// update angular momentum by 1/2 step for all particles
// update quaternion a full step via Richardson iteration
// returns new normalized quaternion
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
angmom[i][0] += dtf*torque[i][0];
angmom[i][1] += dtf*torque[i][1];
angmom[i][2] += dtf*torque[i][2];
richardson(quat[i],angmom[i],inertia[type[i]]);
}
}
}
/* ----------------------------------------------------------------------
perform half-step temperature scaling of velocities
-----------------------------------------------------------------------*/
void FixNHAsphere::nh_v_temp()
{
// standard nhc_nh_v velocity update
FixNH::nh_v_temp();
double **angmom = atom->angmom;
int *mask = atom->mask;
int nlocal = atom->nlocal;
if (igroup == atom->firstgroup) nlocal = atom->nfirst;
// set timestep here since dt may have changed or come via rRESPA
double factor_rotate = exp(-dthalf*eta_dot[0]);
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
angmom[i][0] *= factor_rotate;
angmom[i][1] *= factor_rotate;
angmom[i][2] *= factor_rotate;
}
}
}

40
src/fix_nh_asphere.h Normal file
View File

@ -0,0 +1,40 @@
/* ----------------------------------------------------------------------
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.
------------------------------------------------------------------------- */
#ifndef LMP_FIX_NH_ASPHERE_H
#define LMP_FIX_NH_ASPHERE_H
#include "fix_nh.h"
namespace LAMMPS_NS {
class FixNHAsphere : public FixNH {
public:
FixNHAsphere(class LAMMPS *, int, char **);
virtual ~FixNHAsphere();
void init();
protected:
double dtq;
double **inertia;
void richardson(double *, double *, double *);
void omega_from_mq(double *, double *, double *, double *);
void calculate_inertia();
void nve_v();
void nh_v_temp();
};
}
#endif

191
src/fix_nh_sphere.cpp Normal file
View File

@ -0,0 +1,191 @@
/* ----------------------------------------------------------------------
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 author: Mike Brown (SNL)
------------------------------------------------------------------------- */
#include "math.h"
#include "fix_nh_sphere.h"
#include "atom.h"
#include "atom_vec.h"
#include "group.h"
#include "error.h"
using namespace LAMMPS_NS;
#define INERTIA 0.4 // moment of inertia for sphere
enum{NOBIAS,BIAS};
/* ---------------------------------------------------------------------- */
FixNHSphere::FixNHSphere(LAMMPS *lmp, int narg, char **arg) :
FixNH(lmp, narg, arg)
{
if (!atom->omega_flag || !atom->torque_flag)
error->all("Fix nvt/nph/npt sphere requires "
"atom attributes omega, torque");
if (!atom->radius_flag && !atom->avec->shape_type)
error->all("Fix nvt/nph/npt sphere requires "
"atom attribute radius or shape");
}
/* ---------------------------------------------------------------------- */
void FixNHSphere::init()
{
int i,itype;
// check that all particles are finite-size and spherical
// no point particles allowed
if (atom->radius_flag) {
double *radius = atom->radius;
int *mask = atom->mask;
int nlocal = atom->nlocal;
if (igroup == atom->firstgroup) nlocal = atom->nfirst;
for (i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
if (radius[i] == 0.0)
error->one("Fix nvt/sphere requires extended particles");
}
} else {
double **shape = atom->shape;
int *type = atom->type;
int *mask = atom->mask;
int nlocal = atom->nlocal;
if (igroup == atom->firstgroup) nlocal = atom->nfirst;
for (i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
itype = type[i];
if (shape[itype][0] == 0.0)
error->one("Fix nvt/sphere requires extended particles");
if (shape[itype][0] != shape[itype][1] ||
shape[itype][0] != shape[itype][2])
error->one("Fix nvt/sphere requires spherical particle shapes");
}
}
FixNH::init();
}
/* ----------------------------------------------------------------------
perform half-step update of velocities
-----------------------------------------------------------------------*/
void FixNHSphere::nve_v()
{
// standard nve_v velocity update
FixNH::nve_v();
double **omega = atom->omega;
double **torque = atom->torque;
double *radius = atom->radius;
double *rmass = atom->rmass;
double *mass = atom->mass;
double **shape = atom->shape;
int *type = atom->type;
int *mask = atom->mask;
int nlocal = atom->nlocal;
if (igroup == atom->firstgroup) nlocal = atom->nfirst;
// set timestep here since dt may have changed or come via rRESPA
double dtfrotate = dtf / INERTIA;
double dtirotate;
int itype;
// update omega for all particles
// d_omega/dt = torque / inertia
// 4 cases depending on radius vs shape and rmass vs mass
if (radius) {
if (rmass) {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtirotate = dtfrotate / (radius[i]*radius[i]*rmass[i]);
omega[i][0] += dtirotate*torque[i][0];
omega[i][1] += dtirotate*torque[i][1];
omega[i][2] += dtirotate*torque[i][2];
}
}
} else {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtirotate = dtfrotate / (radius[i]*radius[i]*mass[type[i]]);
omega[i][0] += dtirotate*torque[i][0];
omega[i][1] += dtirotate*torque[i][1];
omega[i][2] += dtirotate*torque[i][2];
}
}
}
} else {
if (rmass) {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
itype = type[i];
dtirotate = dtfrotate / (shape[itype][0]*shape[itype][0]*rmass[i]);
omega[i][0] += dtirotate*torque[i][0];
omega[i][1] += dtirotate*torque[i][1];
omega[i][2] += dtirotate*torque[i][2];
}
}
} else {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
itype = type[i];
dtirotate = dtfrotate /
(shape[itype][0]*shape[itype][0]*mass[itype]);
omega[i][0] += dtirotate*torque[i][0];
omega[i][1] += dtirotate*torque[i][1];
omega[i][2] += dtirotate*torque[i][2];
}
}
}
}
}
/* ----------------------------------------------------------------------
perform half-step scaling of velocities
-----------------------------------------------------------------------*/
void FixNHSphere::nh_v_temp()
{
// standard nh_v_temp velocity update
FixNH::nh_v_temp();
double **omega = atom->omega;
int *mask = atom->mask;
int nlocal = atom->nlocal;
if (igroup == atom->firstgroup) nlocal = atom->nfirst;
// set timestep here since dt may have changed or come via rRESPA
double factor_rotate = exp(-dthalf*eta_dot[0]);
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
omega[i][0] *= factor_rotate;
omega[i][1] *= factor_rotate;
omega[i][2] *= factor_rotate;
}
}
}

34
src/fix_nh_sphere.h Normal file
View File

@ -0,0 +1,34 @@
/* ----------------------------------------------------------------------
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.
------------------------------------------------------------------------- */
#ifndef LMP_FIX_NH_SPHERE_H
#define LMP_FIX_NH_SPHERE_H
#include "fix_nh.h"
namespace LAMMPS_NS {
class FixNHSphere : public FixNH {
public:
FixNHSphere(class LAMMPS *, int, char **);
virtual ~FixNHSphere() {}
void init();
protected:
void nve_v();
void nh_v_temp();
};
}
#endif

View File

@ -11,182 +11,39 @@
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Mark Stevens (SNL)
------------------------------------------------------------------------- */
#include "string.h"
#include "stdlib.h"
#include "math.h"
#include "fix_nph.h"
#include "atom.h"
#include "force.h"
#include "comm.h"
#include "domain.h"
#include "group.h"
#include "modify.h"
#include "fix_deform.h"
#include "compute.h"
#include "kspace.h"
#include "update.h"
#include "respa.h"
#include "domain.h"
#include "error.h"
using namespace LAMMPS_NS;
#define MIN(A,B) ((A) < (B)) ? (A) : (B)
#define MAX(A,B) ((A) > (B)) ? (A) : (B)
enum{XYZ,XY,YZ,XZ,ANISO};
/* ---------------------------------------------------------------------- */
FixNPH::FixNPH(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg)
FixNH(lmp, narg, arg)
{
if (narg < 4) error->all("Illegal fix nph command");
restart_global = 1;
box_change = 1;
time_integrate = 1;
scalar_flag = 1;
global_freq = 1;
extscalar = 1;
double p_period[3];
if (strcmp(arg[3],"xyz") == 0) {
if (narg < 7) error->all("Illegal fix nph command");
press_couple = XYZ;
p_start[0] = p_start[1] = p_start[2] = atof(arg[4]);
p_stop[0] = p_stop[1] = p_stop[2] = atof(arg[5]);
p_period[0] = p_period[1] = p_period[2] = atof(arg[6]);
p_flag[0] = p_flag[1] = p_flag[2] = 1;
if (domain->dimension == 2) {
p_start[2] = p_stop[2] = p_period[2] = 0.0;
p_flag[2] = 0;
}
} else {
if (strcmp(arg[3],"xy") == 0) press_couple = XY;
else if (strcmp(arg[3],"yz") == 0) press_couple = YZ;
else if (strcmp(arg[3],"xz") == 0) press_couple = XZ;
else if (strcmp(arg[3],"aniso") == 0) press_couple = ANISO;
else error->all("Illegal fix nph command");
if (narg < 11) error->all("Illegal fix nph command");
if (domain->dimension == 2 &&
(press_couple == XY || press_couple == YZ || press_couple == XZ))
error->all("Invalid fix nph command for a 2d simulation");
if (strcmp(arg[4],"NULL") == 0) {
p_start[0] = p_stop[0] = p_period[0] = 0.0;
p_flag[0] = 0;
} else {
p_start[0] = atof(arg[4]);
p_stop[0] = atof(arg[5]);
p_flag[0] = 1;
}
if (strcmp(arg[6],"NULL") == 0) {
p_start[1] = p_stop[1] = p_period[1] = 0.0;
p_flag[1] = 0;
} else {
p_start[1] = atof(arg[6]);
p_stop[1] = atof(arg[7]);
p_flag[1] = 1;
}
if (strcmp(arg[8],"NULL") == 0) {
p_start[2] = p_stop[2] = p_period[2] = 0.0;
p_flag[2] = 0;
} else {
if (domain->dimension == 2)
error->all("Invalid fix nph command for a 2d simulation");
p_start[2] = atof(arg[8]);
p_stop[2] = atof(arg[9]);
p_flag[2] = 1;
}
double period = atof(arg[10]);
if (p_flag[0]) p_period[0] = period;
if (p_flag[1]) p_period[1] = period;
if (p_flag[2]) p_period[2] = period;
}
// process extra keywords
drag = 0.0;
allremap = 1;
int iarg;
if (press_couple == XYZ) iarg = 7;
else iarg = 11;
while (iarg < narg) {
if (strcmp(arg[iarg],"drag") == 0) {
if (iarg+2 > narg) error->all("Illegal fix nph command");
drag = atof(arg[iarg+1]);
iarg += 2;
} else if (strcmp(arg[iarg],"dilate") == 0) {
if (iarg+2 > narg) error->all("Illegal fix nph command");
if (strcmp(arg[iarg+1],"all") == 0) allremap = 1;
else if (strcmp(arg[iarg+1],"partial") == 0) allremap = 0;
else error->all("Illegal fix nph command");
iarg += 2;
} else error->all("Illegal fix nph command");
}
// error checks
if (press_couple == XY && (p_flag[0] == 0 || p_flag[1] == 0))
error->all("Invalid fix nph command pressure settings");
if (press_couple == YZ && (p_flag[1] == 0 || p_flag[2] == 0))
error->all("Invalid fix nph command pressure settings");
if (press_couple == XZ && (p_flag[0] == 0 || p_flag[2] == 0))
error->all("Invalid fix nph command pressure settings");
if (press_couple == XY &&
(p_start[0] != p_start[1] || p_stop[0] != p_stop[1]))
error->all("Invalid fix nph command pressure settings");
if (press_couple == YZ &&
(p_start[1] != p_start[2] || p_stop[1] != p_stop[2]))
error->all("Invalid fix nph command pressure settings");
if (press_couple == XZ &&
(p_start[0] != p_start[2] || p_stop[0] != p_stop[2]))
error->all("Invalid fix nph command pressure settings");
if (p_flag[0] && domain->xperiodic == 0)
error->all("Cannot use fix nph on a non-periodic dimension");
if (p_flag[1] && domain->yperiodic == 0)
error->all("Cannot use fix nph on a non-periodic dimension");
if (p_flag[2] && domain->zperiodic == 0)
error->all("Cannot use fix nph on a non-periodic dimension");
// convert input periods to frequencies
if ((p_flag[0] && p_period[0] <= 0.0) ||
(p_flag[1] && p_period[1] <= 0.0) || (p_flag[2] && p_period[2] <= 0.0))
error->all("Fix nph periods must be > 0.0");
p_freq[0] = p_freq[1] = p_freq[2] = 0.0;
if (p_flag[0]) p_freq[0] = 1.0 / p_period[0];
if (p_flag[1]) p_freq[1] = 1.0 / p_period[1];
if (p_flag[2]) p_freq[2] = 1.0 / p_period[2];
if (tstat_flag)
error->all("Temperature control can not be used with fix nph");
if (!pstat_flag)
error->all("Pressure control must be used with fix nph");
// create a new compute temp style
// id = fix-ID + temp
// compute group = all since pressure is always global (group all)
// and thus its KE/temperature contribution should use group all
// and thus its KE/temperature contribution should use group all
int n = strlen(id) + 6;
id_temp = new char[n];
strcpy(id_temp,id);
strcat(id_temp,"_temp");
char **newarg = new char*[3];
newarg[0] = id_temp;
newarg[1] = (char *) "all";
newarg[2] = (char *) "temp";
modify->add_compute(3,newarg);
delete [] newarg;
tflag = 1;
@ -199,7 +56,7 @@ FixNPH::FixNPH(LAMMPS *lmp, int narg, char **arg) :
id_press = new char[n];
strcpy(id_press,id);
strcat(id_press,"_press");
newarg = new char*[4];
newarg[0] = id_press;
newarg[1] = (char *) "all";
@ -208,659 +65,4 @@ FixNPH::FixNPH(LAMMPS *lmp, int narg, char **arg) :
modify->add_compute(4,newarg);
delete [] newarg;
pflag = 1;
// Nose/Hoover pressure init
omega[0] = omega[1] = omega[2] = 0.0;
omega_dot[0] = omega_dot[1] = omega_dot[2] = 0.0;
nrigid = 0;
rfix = NULL;
}
/* ---------------------------------------------------------------------- */
FixNPH::~FixNPH()
{
delete [] rfix;
// delete temperature and pressure if fix created them
if (tflag) modify->delete_compute(id_temp);
if (pflag) modify->delete_compute(id_press);
delete [] id_temp;
delete [] id_press;
}
/* ---------------------------------------------------------------------- */
int FixNPH::setmask()
{
int mask = 0;
mask |= INITIAL_INTEGRATE;
mask |= FINAL_INTEGRATE;
mask |= THERMO_ENERGY;
mask |= INITIAL_INTEGRATE_RESPA;
mask |= FINAL_INTEGRATE_RESPA;
return mask;
}
/* ---------------------------------------------------------------------- */
void FixNPH::init()
{
if (domain->triclinic) error->all("Cannot use fix nph with triclinic box");
for (int i = 0; i < modify->nfix; i++)
if (strcmp(modify->fix[i]->style,"deform") == 0) {
int *dimflag = ((FixDeform *) modify->fix[i])->dimflag;
if ((p_flag[0] && dimflag[0]) || (p_flag[1] && dimflag[1]) ||
(p_flag[2] && dimflag[2]))
error->all("Cannot use fix npt and fix deform on same dimension");
}
// set temperature and pressure ptrs
int icompute = modify->find_compute(id_temp);
if (icompute < 0) error->all("Temperature ID for fix nph does not exist");
temperature = modify->compute[icompute];
icompute = modify->find_compute(id_press);
if (icompute < 0) error->all("Pressure ID for fix nph does not exist");
pressure = modify->compute[icompute];
// set timesteps and frequencies
dtv = update->dt;
dtf = 0.5 * update->dt * force->ftm2v;
dthalf = 0.5 * update->dt;
double freq = MAX(p_freq[0],p_freq[1]);
freq = MAX(freq,p_freq[2]);
drag_factor = 1.0 - (update->dt * freq * drag);
boltz = force->boltz;
nktv2p = force->nktv2p;
dimension = domain->dimension;
if (dimension == 3) vol0 = domain->xprd * domain->yprd * domain->zprd;
else vol0 = domain->xprd * domain->yprd;
if (force->kspace) kspace_flag = 1;
else kspace_flag = 0;
if (strcmp(update->integrate_style,"respa") == 0) {
nlevels_respa = ((Respa *) update->integrate)->nlevels;
step_respa = ((Respa *) update->integrate)->step;
}
// detect if any rigid fixes exist so rigid bodies move when box is remapped
// rfix[] = indices to each fix rigid
delete [] rfix;
nrigid = 0;
rfix = NULL;
for (int i = 0; i < modify->nfix; i++)
if (modify->fix[i]->rigid_flag) nrigid++;
if (nrigid) {
rfix = new int[nrigid];
nrigid = 0;
for (int i = 0; i < modify->nfix; i++)
if (modify->fix[i]->rigid_flag) rfix[nrigid++] = i;
}
}
/* ----------------------------------------------------------------------
compute T,P before integrator starts
------------------------------------------------------------------------- */
void FixNPH::setup(int vflag)
{
// Nkt = initial value for piston mass and energy conservation
// cannot be done in init() b/c temperature cannot be called there
// is b/c Modify::init() inits computes after fixes due to dof dependence
// guesstimate a unit-dependent t_initial if actual T = 0.0
double t_initial = temperature->compute_scalar();
if (t_initial == 0.0) {
if (strcmp(update->unit_style,"lj") == 0) t_initial = 1.0;
else t_initial = 300.0;
}
nkt = atom->natoms * boltz * t_initial;
p_target[0] = p_start[0]; // used by compute_scalar()
p_target[1] = p_start[1];
p_target[2] = p_start[2];
if (press_couple == XYZ) {
double tmp = temperature->compute_scalar();
tmp = pressure->compute_scalar();
} else {
temperature->compute_vector();
pressure->compute_vector();
}
couple();
// trigger virial computation on next timestep
pressure->addstep(update->ntimestep+1);
}
/* ----------------------------------------------------------------------
1st half of Verlet update
------------------------------------------------------------------------- */
void FixNPH::initial_integrate(int vflag)
{
int i;
double dtfm;
double delta = update->ntimestep - update->beginstep;
delta /= update->endstep - update->beginstep;
// update omega_dot
// for non-varying dims, p_freq is 0.0, so omega doesn't change
double f_omega,volume;
if (dimension == 3) volume = domain->xprd*domain->yprd*domain->zprd;
else volume = domain->xprd*domain->yprd;
double denskt = nkt / volume * nktv2p;
for (i = 0; i < 3; i++) {
p_target[i] = p_start[i] + delta * (p_stop[i]-p_start[i]);
f_omega = p_freq[i]*p_freq[i] * (p_current[i]-p_target[i])/denskt;
omega_dot[i] += f_omega*dthalf;
omega_dot[i] *= drag_factor;
omega[i] += dtv*omega_dot[i];
factor[i] = exp(-dthalf*omega_dot[i]);
dilation[i] = exp(dthalf*omega_dot[i]);
}
// v update only for atoms in NPH group
double **x = atom->x;
double **v = atom->v;
double **f = atom->f;
double *rmass = atom->rmass;
double *mass = atom->mass;
int *type = atom->type;
int *mask = atom->mask;
int nlocal = atom->nlocal;
if (rmass) {
for (i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtfm = dtf / rmass[i];
v[i][0] = v[i][0]*factor[0] + dtfm*f[i][0];
v[i][1] = v[i][1]*factor[1] + dtfm*f[i][1];
v[i][2] = v[i][2]*factor[2] + dtfm*f[i][2];
}
}
} else {
for (i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtfm = dtf / mass[type[i]];
v[i][0] = v[i][0]*factor[0] + dtfm*f[i][0];
v[i][1] = v[i][1]*factor[1] + dtfm*f[i][1];
v[i][2] = v[i][2]*factor[2] + dtfm*f[i][2];
}
}
}
// remap simulation box by 1/2 step
remap();
// x update by full step only for atoms in NPH group
for (i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
x[i][0] += dtv * v[i][0];
x[i][1] += dtv * v[i][1];
x[i][2] += dtv * v[i][2];
}
}
// remap simulation box by 1/2 step
// redo KSpace coeffs since volume has changed
remap();
if (kspace_flag) force->kspace->setup();
}
/* ----------------------------------------------------------------------
2nd half of Verlet update
------------------------------------------------------------------------- */
void FixNPH::final_integrate()
{
int i;
double dtfm;
// v update only for atoms in NPH group
double **v = atom->v;
double **f = atom->f;
double *rmass = atom->rmass;
double *mass = atom->mass;
int *type = atom->type;
int *mask = atom->mask;
int nlocal = atom->nlocal;
if (rmass) {
for (i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtfm = dtf / rmass[i];
v[i][0] = (v[i][0] + dtfm*f[i][0]) * factor[0];
v[i][1] = (v[i][1] + dtfm*f[i][1]) * factor[1];
v[i][2] = (v[i][2] + dtfm*f[i][2]) * factor[2];
}
}
} else {
for (i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtfm = dtf / mass[type[i]];
v[i][0] = (v[i][0] + dtfm*f[i][0]) * factor[0];
v[i][1] = (v[i][1] + dtfm*f[i][1]) * factor[1];
v[i][2] = (v[i][2] + dtfm*f[i][2]) * factor[2];
}
}
}
// compute new pressure
if (press_couple == XYZ) {
double tmp = temperature->compute_scalar();
tmp = pressure->compute_scalar();
} else {
temperature->compute_vector();
pressure->compute_vector();
}
couple();
// trigger virial computation on next timestep
pressure->addstep(update->ntimestep+1);
// update omega_dot
// for non-varying dims, p_freq is 0.0, so omega_dot doesn't change
double f_omega,volume;
if (dimension == 3) volume = domain->xprd*domain->yprd*domain->zprd;
else volume = domain->xprd*domain->yprd;
double denskt = nkt / volume * nktv2p;
for (i = 0; i < 3; i++) {
f_omega = p_freq[i]*p_freq[i] * (p_current[i]-p_target[i])/denskt;
omega_dot[i] += f_omega*dthalf;
omega_dot[i] *= drag_factor;
}
}
/* ---------------------------------------------------------------------- */
void FixNPH::initial_integrate_respa(int vflag, int ilevel, int iloop)
{
// set timesteps by level
double dtfm;
dtv = step_respa[ilevel];
dtf = 0.5 * step_respa[ilevel] * force->ftm2v;
dthalf = 0.5 * step_respa[ilevel];
// atom quantities
double **x = atom->x;
double **v = atom->v;
double **f = atom->f;
double *rmass = atom->rmass;
double *mass = atom->mass;
int *type = atom->type;
int *mask = atom->mask;
int nlocal = atom->nlocal;
// outermost level - update omega_dot, apply to v, remap box
// all other levels - NVE update of v
// x,v updates only performed for atoms in NPH group
if (ilevel == nlevels_respa-1) {
double delta = update->ntimestep - update->beginstep;
delta /= update->endstep - update->beginstep;
// update omega_dot
// for non-varying dims, p_freq is 0.0, so omega doesn't change
double f_omega,volume;
if (dimension == 3) volume = domain->xprd*domain->yprd*domain->zprd;
else volume = domain->xprd*domain->yprd;
double denskt = nkt / volume * nktv2p;
for (int i = 0; i < 3; i++) {
p_target[i] = p_start[i] + delta * (p_stop[i]-p_start[i]);
f_omega = p_freq[i]*p_freq[i] * (p_current[i]-p_target[i])/denskt;
omega_dot[i] += f_omega*dthalf;
omega_dot[i] *= drag_factor;
omega[i] += dtv*omega_dot[i];
factor[i] = exp(-dthalf*omega_dot[i]);
dilation[i] = exp(dthalf*omega_dot[i]);
}
// v update only for atoms in NPH group
if (rmass) {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtfm = dtf / rmass[i];
v[i][0] = v[i][0]*factor[0] + dtfm*f[i][0];
v[i][1] = v[i][1]*factor[1] + dtfm*f[i][1];
v[i][2] = v[i][2]*factor[2] + dtfm*f[i][2];
}
}
} else {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtfm = dtf / mass[type[i]];
v[i][0] = v[i][0]*factor[0] + dtfm*f[i][0];
v[i][1] = v[i][1]*factor[1] + dtfm*f[i][1];
v[i][2] = v[i][2]*factor[2] + dtfm*f[i][2];
}
}
}
// remap simulation box by 1/2 step
remap();
remap2flag = 1;
} else {
// v update only for atoms in NPH group
if (rmass) {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtfm = dtf / rmass[i];
v[i][0] += dtfm*f[i][0];
v[i][1] += dtfm*f[i][1];
v[i][2] += dtfm*f[i][2];
}
}
} else {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtfm = dtf / mass[type[i]];
v[i][0] += dtfm*f[i][0];
v[i][1] += dtfm*f[i][1];
v[i][2] += dtfm*f[i][2];
}
}
}
}
// innermost level - also update x for atoms in group
// if remap2flag:
// this is 1st call at innermost level from rRESPA after 1st half remap
// perform 2nd half of box remap
// redo KSpace coeffs since volume has changed
if (ilevel == 0) {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
x[i][0] += dtv * v[i][0];
x[i][1] += dtv * v[i][1];
x[i][2] += dtv * v[i][2];
}
}
if (remap2flag) {
remap();
if (kspace_flag) force->kspace->setup();
remap2flag = 0;
}
}
}
/* ---------------------------------------------------------------------- */
void FixNPH::final_integrate_respa(int ilevel, int iloop)
{
double dtfm;
// set timesteps by level
dtf = 0.5 * step_respa[ilevel] * force->ftm2v;
dthalf = 0.5 * step_respa[ilevel];
// outermost level - update omega_dot, apply to v via final_integrate()
// all other levels - NVE update of v
// v update only performed for atoms in NPH group
if (ilevel == nlevels_respa-1) final_integrate();
else {
// v update only for atoms in NPH group
double **v = atom->v;
double **f = atom->f;
double *rmass = atom->rmass;
double *mass = atom->mass;
int *type = atom->type;
int *mask = atom->mask;
int nlocal = atom->nlocal;
if (rmass) {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtfm = dtf / rmass[i];
v[i][0] += dtfm*f[i][0];
v[i][1] += dtfm*f[i][1];
v[i][2] += dtfm*f[i][2];
}
}
} else {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtfm = dtf / mass[type[i]];
v[i][0] += dtfm*f[i][0];
v[i][1] += dtfm*f[i][1];
v[i][2] += dtfm*f[i][2];
}
}
}
}
}
/* ---------------------------------------------------------------------- */
void FixNPH::couple()
{
double *tensor = pressure->vector;
if (press_couple == XYZ)
p_current[0] = p_current[1] = p_current[2] = pressure->scalar;
else if (press_couple == XY) {
double ave = 0.5 * (tensor[0] + tensor[1]);
p_current[0] = p_current[1] = ave;
p_current[2] = tensor[2];
} else if (press_couple == YZ) {
double ave = 0.5 * (tensor[1] + tensor[2]);
p_current[1] = p_current[2] = ave;
p_current[0] = tensor[0];
} else if (press_couple == XZ) {
double ave = 0.5 * (tensor[0] + tensor[2]);
p_current[0] = p_current[2] = ave;
p_current[1] = tensor[1];
} else if (press_couple == ANISO) {
p_current[0] = tensor[0];
p_current[1] = tensor[1];
p_current[2] = tensor[2];
}
}
/* ----------------------------------------------------------------------
change box size
remap all atoms or fix group atoms depending on allremap flag
if rigid bodies exist, scale rigid body centers-of-mass
------------------------------------------------------------------------- */
void FixNPH::remap()
{
int i;
double oldlo,oldhi,ctr;
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
// convert pertinent atoms and rigid bodies to lamda coords
if (allremap) domain->x2lamda(nlocal);
else {
for (i = 0; i < nlocal; i++)
if (mask[i] & groupbit)
domain->x2lamda(x[i],x[i]);
}
if (nrigid)
for (i = 0; i < nrigid; i++)
modify->fix[rfix[i]]->deform(0);
// reset global and local box to new size/shape
for (i = 0; i < 3; i++) {
if (p_flag[i]) {
oldlo = domain->boxlo[i];
oldhi = domain->boxhi[i];
ctr = 0.5 * (oldlo + oldhi);
domain->boxlo[i] = (oldlo-ctr)*dilation[i] + ctr;
domain->boxhi[i] = (oldhi-ctr)*dilation[i] + ctr;
}
}
domain->set_global_box();
domain->set_local_box();
// convert pertinent atoms and rigid bodies back to box coords
if (allremap) domain->lamda2x(nlocal);
else {
for (i = 0; i < nlocal; i++)
if (mask[i] & groupbit)
domain->lamda2x(x[i],x[i]);
}
if (nrigid)
for (i = 0; i < nrigid; i++)
modify->fix[rfix[i]]->deform(1);
}
/* ----------------------------------------------------------------------
pack entire state of Fix into one write
------------------------------------------------------------------------- */
void FixNPH::write_restart(FILE *fp)
{
int n = 0;
double list[6];
list[n++] = omega[0];
list[n++] = omega[1];
list[n++] = omega[2];
list[n++] = omega_dot[0];
list[n++] = omega_dot[1];
list[n++] = omega_dot[2];
if (comm->me == 0) {
int size = n * sizeof(double);
fwrite(&size,sizeof(int),1,fp);
fwrite(list,sizeof(double),n,fp);
}
}
/* ----------------------------------------------------------------------
use state info from restart file to restart the Fix
------------------------------------------------------------------------- */
void FixNPH::restart(char *buf)
{
int n = 0;
double *list = (double *) buf;
omega[0] = list[n++];
omega[1] = list[n++];
omega[2] = list[n++];
omega_dot[0] = list[n++];
omega_dot[1] = list[n++];
omega_dot[2] = list[n++];
}
/* ---------------------------------------------------------------------- */
int FixNPH::modify_param(int narg, char **arg)
{
if (strcmp(arg[0],"temp") == 0) {
if (narg < 2) error->all("Illegal fix_modify command");
if (tflag) {
modify->delete_compute(id_temp);
tflag = 0;
}
delete [] id_temp;
int n = strlen(arg[1]) + 1;
id_temp = new char[n];
strcpy(id_temp,arg[1]);
int icompute = modify->find_compute(id_temp);
if (icompute < 0) error->all("Could not find fix_modify temperature ID");
temperature = modify->compute[icompute];
if (temperature->tempflag == 0)
error->all("Fix_modify temperature ID does not compute temperature");
if (temperature->igroup != 0 && comm->me == 0)
error->warning("Temperature for NPH is not for group all");
// reset id_temp of pressure to new temperature ID
icompute = modify->find_compute(id_press);
if (icompute < 0) error->all("Pressure ID for fix npt does not exist");
modify->compute[icompute]->reset_extra_compute_fix(id_temp);
return 2;
} else if (strcmp(arg[0],"press") == 0) {
if (narg < 2) error->all("Illegal fix_modify command");
if (pflag) {
modify->delete_compute(id_press);
pflag = 0;
}
delete [] id_press;
int n = strlen(arg[1]) + 1;
id_press = new char[n];
strcpy(id_press,arg[1]);
int icompute = modify->find_compute(id_press);
if (icompute < 0) error->all("Could not find fix_modify pressure ID");
pressure = modify->compute[icompute];
if (pressure->pressflag == 0)
error->all("Fix_modify pressure ID does not compute pressure");
return 2;
}
return 0;
}
/* ---------------------------------------------------------------------- */
double FixNPH::compute_scalar()
{
double volume;
if (dimension == 3) volume = domain->xprd * domain->yprd * domain->zprd;
else volume = domain->xprd * domain->yprd;
int pdim = p_flag[0] + p_flag[1] + p_flag[2];
double energy = 0.0;
for (int i = 0; i < 3; i++)
if (p_freq[i] > 0.0)
energy += 0.5*nkt*omega_dot[i]*omega_dot[i] /
(p_freq[i]*p_freq[i]) + p_target[i]*(volume-vol0) / (pdim*nktv2p);
return energy;
}

View File

@ -20,54 +20,14 @@ FixStyle(nph,FixNPH)
#ifndef LMP_FIX_NPH_H
#define LMP_FIX_NPH_H
#include "fix.h"
#include "fix_nh.h"
namespace LAMMPS_NS {
class FixNPH : public Fix {
class FixNPH : public FixNH {
public:
FixNPH(class LAMMPS *, int, char **);
~FixNPH();
int setmask();
void init();
void setup(int);
void initial_integrate(int);
void final_integrate();
void initial_integrate_respa(int, int, int);
void final_integrate_respa(int, int);
double compute_scalar();
void write_restart(FILE *);
void restart(char *);
int modify_param(int, char **);
private:
int dimension;
double dtv,dtf,dthalf;
double boltz,nktv2p;
double vol0,nkt;
int press_couple,allremap;
int p_flag[3]; // 1 if control P on this dim, 0 if not
double p_start[3],p_stop[3];
double p_freq[3],p_target[3];
double omega[3],omega_dot[3];
double p_current[3],dilation[3];
double drag,drag_factor;
double factor[3];
int kspace_flag; // 1 if KSpace invoked, 0 if not
int nrigid; // number of rigid fixes
int *rfix; // indices of rigid fixes
int nlevels_respa;
double *step_respa;
int remap2flag; // flag for performing 2nd half remap()
char *id_temp,*id_press;
class Compute *temperature,*pressure;
int tflag,pflag;
void couple();
void remap();
~FixNPH() {}
};
}

68
src/fix_nph_sphere.cpp Normal file
View File

@ -0,0 +1,68 @@
/* ----------------------------------------------------------------------
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.
------------------------------------------------------------------------- */
#include "string.h"
#include "fix_nph_sphere.h"
#include "group.h"
#include "modify.h"
#include "error.h"
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
FixNPHSphere::FixNPHSphere(LAMMPS *lmp, int narg, char **arg) :
FixNHSphere(lmp, narg, arg)
{
if (tstat_flag)
error->all("Temperature control can not be used with fix nph/sphere");
if (!pstat_flag)
error->all("Pressure control must be used with fix nph/sphere");
// create a new compute temp style
// id = fix-ID + temp
// compute group = all since pressure is always global (group all)
// and thus its KE/temperature contribution should use group all
int n = strlen(id) + 6;
id_temp = new char[n];
strcpy(id_temp,id);
strcat(id_temp,"_temp");
char **newarg = new char*[3];
newarg[0] = id_temp;
newarg[1] = (char *) "all";
newarg[2] = (char *) "temp/sphere";
modify->add_compute(3,newarg);
delete [] newarg;
tflag = 1;
// create a new compute pressure style
// id = fix-ID + press, compute group = all
// pass id_temp as 4th arg to pressure constructor
n = strlen(id) + 7;
id_press = new char[n];
strcpy(id_press,id);
strcat(id_press,"_press");
newarg = new char*[4];
newarg[0] = id_press;
newarg[1] = (char *) "all";
newarg[2] = (char *) "pressure";
newarg[3] = id_temp;
modify->add_compute(4,newarg);
delete [] newarg;
pflag = 1;
}

36
src/fix_nph_sphere.h Normal file
View File

@ -0,0 +1,36 @@
/* ----------------------------------------------------------------------
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.
------------------------------------------------------------------------- */
#ifdef FIX_CLASS
FixStyle(nph/sphere,FixNPHSphere)
#else
#ifndef LMP_FIX_NPH_SPHERE_H
#define LMP_FIX_NPH_SPHERE_H
#include "fix_nh_sphere.h"
namespace LAMMPS_NS {
class FixNPHSphere : public FixNHSphere {
public:
FixNPHSphere(class LAMMPS *, int, char **);
~FixNPHSphere() {}
};
}
#endif
#endif

View File

@ -11,193 +11,38 @@
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Mark Stevens (SNL)
------------------------------------------------------------------------- */
#include "string.h"
#include "stdlib.h"
#include "math.h"
#include "fix_npt.h"
#include "atom.h"
#include "force.h"
#include "comm.h"
#include "modify.h"
#include "fix_deform.h"
#include "compute.h"
#include "kspace.h"
#include "update.h"
#include "respa.h"
#include "domain.h"
#include "error.h"
using namespace LAMMPS_NS;
#define MIN(A,B) ((A) < (B)) ? (A) : (B)
#define MAX(A,B) ((A) > (B)) ? (A) : (B)
enum{NOBIAS,BIAS};
enum{XYZ,XY,YZ,XZ,ANISO};
/* ---------------------------------------------------------------------- */
FixNPT::FixNPT(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg)
FixNH(lmp, narg, arg)
{
if (narg < 7) error->all("Illegal fix npt command");
restart_global = 1;
box_change = 1;
time_integrate = 1;
scalar_flag = 1;
global_freq = 1;
extscalar = 1;
t_start = atof(arg[3]);
t_stop = atof(arg[4]);
double t_period = atof(arg[5]);
if (t_start < 0.0 || t_stop <= 0.0)
error->all("Target T for fix npt cannot be 0.0");
double p_period[3];
if (strcmp(arg[6],"xyz") == 0) {
if (narg < 10) error->all("Illegal fix npt command");
press_couple = XYZ;
p_start[0] = p_start[1] = p_start[2] = atof(arg[7]);
p_stop[0] = p_stop[1] = p_stop[2] = atof(arg[8]);
p_period[0] = p_period[1] = p_period[2] = atof(arg[9]);
p_flag[0] = p_flag[1] = p_flag[2] = 1;
if (domain->dimension == 2) {
p_start[2] = p_stop[2] = p_period[2] = 0.0;
p_flag[2] = 0;
}
} else {
if (strcmp(arg[6],"xy") == 0) press_couple = XY;
else if (strcmp(arg[6],"yz") == 0) press_couple = YZ;
else if (strcmp(arg[6],"xz") == 0) press_couple = XZ;
else if (strcmp(arg[6],"aniso") == 0) press_couple = ANISO;
else error->all("Illegal fix npt command");
if (narg < 14) error->all("Illegal fix npt command");
if (domain->dimension == 2 &&
(press_couple == XY || press_couple == YZ || press_couple == XZ))
error->all("Invalid fix npt command for a 2d simulation");
if (strcmp(arg[7],"NULL") == 0) {
p_start[0] = p_stop[0] = p_period[0] = 0.0;
p_flag[0] = 0;
} else {
p_start[0] = atof(arg[7]);
p_stop[0] = atof(arg[8]);
p_flag[0] = 1;
}
if (strcmp(arg[9],"NULL") == 0) {
p_start[1] = p_stop[1] = p_period[1] = 0.0;
p_flag[1] = 0;
} else {
p_start[1] = atof(arg[9]);
p_stop[1] = atof(arg[10]);
p_flag[1] = 1;
}
if (strcmp(arg[11],"NULL") == 0) {
p_start[2] = p_stop[2] = p_period[2] = 0.0;
p_flag[2] = 0;
} else {
if (domain->dimension == 2)
error->all("Invalid fix npt command for a 2d simulation");
p_start[2] = atof(arg[11]);
p_stop[2] = atof(arg[12]);
p_flag[2] = 1;
}
double period = atof(arg[13]);
if (p_flag[0]) p_period[0] = period;
if (p_flag[1]) p_period[1] = period;
if (p_flag[2]) p_period[2] = period;
}
// process extra keywords
drag = 0.0;
allremap = 1;
int iarg;
if (press_couple == XYZ) iarg = 10;
else iarg = 14;
while (iarg < narg) {
if (strcmp(arg[iarg],"drag") == 0) {
if (iarg+2 > narg) error->all("Illegal fix npt command");
drag = atof(arg[iarg+1]);
iarg += 2;
} else if (strcmp(arg[iarg],"dilate") == 0) {
if (iarg+2 > narg) error->all("Illegal fix npt command");
if (strcmp(arg[iarg+1],"all") == 0) allremap = 1;
else if (strcmp(arg[iarg+1],"partial") == 0) allremap = 0;
else error->all("Illegal fix npt command");
iarg += 2;
} else error->all("Illegal fix npt command");
}
// error checks
if (press_couple == XY && (p_flag[0] == 0 || p_flag[1] == 0))
error->all("Invalid fix npt command pressure settings");
if (press_couple == YZ && (p_flag[1] == 0 || p_flag[2] == 0))
error->all("Invalid fix npt command pressure settings");
if (press_couple == XZ && (p_flag[0] == 0 || p_flag[2] == 0))
error->all("Invalid fix npt command pressure settings");
if (press_couple == XY &&
(p_start[0] != p_start[1] || p_stop[0] != p_stop[1]))
error->all("Invalid fix npt command pressure settings");
if (press_couple == YZ &&
(p_start[1] != p_start[2] || p_stop[1] != p_stop[2]))
error->all("Invalid fix npt command pressure settings");
if (press_couple == XZ &&
(p_start[0] != p_start[2] || p_stop[0] != p_stop[2]))
error->all("Invalid fix npt command pressure settings");
if (p_flag[0] && domain->xperiodic == 0)
error->all("Cannot use fix npt on a non-periodic dimension");
if (p_flag[1] && domain->yperiodic == 0)
error->all("Cannot use fix npt on a non-periodic dimension");
if (p_flag[2] && domain->zperiodic == 0)
error->all("Cannot use fix npt on a non-periodic dimension");
// convert input periods to frequencies
if (t_period <= 0.0 || (p_flag[0] && p_period[0] <= 0.0) ||
(p_flag[1] && p_period[1] <= 0.0) || (p_flag[2] && p_period[2] <= 0.0))
error->all("Fix npt periods must be > 0.0");
t_freq = 1.0 / t_period;
p_freq[0] = p_freq[1] = p_freq[2] = 0.0;
if (p_flag[0]) p_freq[0] = 1.0 / p_period[0];
if (p_flag[1]) p_freq[1] = 1.0 / p_period[1];
if (p_flag[2]) p_freq[2] = 1.0 / p_period[2];
if (!tstat_flag)
error->all("Temperature control must be used with fix npt");
if (!pstat_flag)
error->all("Pressure control must be used with fix npt");
// create a new compute temp style
// id = fix-ID + temp
// compute group = all since pressure is always global (group all)
// and thus its KE/temperature contribution should use group all
// and thus its KE/temperature contribution should use group all
int n = strlen(id) + 6;
id_temp = new char[n];
strcpy(id_temp,id);
strcat(id_temp,"_temp");
char **newarg = new char*[3];
newarg[0] = id_temp;
newarg[1] = (char *) "all";
if (strcmp(style,"npt") == 0) newarg[2] = (char *) "temp";
else if (strcmp(style,"npt/asphere") == 0)
newarg[2] = (char *) "temp/asphere";
else if (strcmp(style,"npt/sphere") == 0)
newarg[2] = (char *) "temp/sphere";
newarg[2] = (char *) "temp";
modify->add_compute(3,newarg);
delete [] newarg;
tflag = 1;
@ -210,7 +55,7 @@ FixNPT::FixNPT(LAMMPS *lmp, int narg, char **arg) :
id_press = new char[n];
strcpy(id_press,id);
strcat(id_press,"_press");
newarg = new char*[4];
newarg[0] = id_press;
newarg[1] = (char *) "all";
@ -219,766 +64,4 @@ FixNPT::FixNPT(LAMMPS *lmp, int narg, char **arg) :
modify->add_compute(4,newarg);
delete [] newarg;
pflag = 1;
// Nose/Hoover temp and pressure init
eta = eta_dot = 0.0;
omega[0] = omega[1] = omega[2] = 0.0;
omega_dot[0] = omega_dot[1] = omega_dot[2] = 0.0;
nrigid = 0;
rfix = NULL;
}
/* ---------------------------------------------------------------------- */
FixNPT::~FixNPT()
{
delete [] rfix;
// delete temperature and pressure if fix created them
if (tflag) modify->delete_compute(id_temp);
if (pflag) modify->delete_compute(id_press);
delete [] id_temp;
delete [] id_press;
}
/* ---------------------------------------------------------------------- */
int FixNPT::setmask()
{
int mask = 0;
mask |= INITIAL_INTEGRATE;
mask |= FINAL_INTEGRATE;
mask |= THERMO_ENERGY;
mask |= INITIAL_INTEGRATE_RESPA;
mask |= FINAL_INTEGRATE_RESPA;
return mask;
}
/* ---------------------------------------------------------------------- */
void FixNPT::init()
{
if (domain->triclinic) error->all("Cannot use fix npt with triclinic box");
for (int i = 0; i < modify->nfix; i++)
if (strcmp(modify->fix[i]->style,"deform") == 0) {
int *dimflag = ((FixDeform *) modify->fix[i])->dimflag;
if ((p_flag[0] && dimflag[0]) || (p_flag[1] && dimflag[1]) ||
(p_flag[2] && dimflag[2]))
error->all("Cannot use fix npt and fix deform on same dimension");
}
// set temperature and pressure ptrs
int icompute = modify->find_compute(id_temp);
if (icompute < 0) error->all("Temperature ID for fix npt does not exist");
temperature = modify->compute[icompute];
if (temperature->tempbias) which = BIAS;
else which = NOBIAS;
icompute = modify->find_compute(id_press);
if (icompute < 0) error->all("Pressure ID for fix npt does not exist");
pressure = modify->compute[icompute];
// set timesteps and frequencies
dtv = update->dt;
dtf = 0.5 * update->dt * force->ftm2v;
dthalf = 0.5 * update->dt;
double freq = MAX(p_freq[0],p_freq[1]);
freq = MAX(freq,p_freq[2]);
drag_factor = 1.0 - (update->dt * freq * drag);
boltz = force->boltz;
nktv2p = force->nktv2p;
dimension = domain->dimension;
if (dimension == 3) vol0 = domain->xprd * domain->yprd * domain->zprd;
else vol0 = domain->xprd * domain->yprd;
if (force->kspace) kspace_flag = 1;
else kspace_flag = 0;
if (strcmp(update->integrate_style,"respa") == 0) {
nlevels_respa = ((Respa *) update->integrate)->nlevels;
step_respa = ((Respa *) update->integrate)->step;
}
// detect if any rigid fixes exist so rigid bodies move when box is remapped
// rfix[] = indices to each fix rigid
delete [] rfix;
nrigid = 0;
rfix = NULL;
for (int i = 0; i < modify->nfix; i++)
if (modify->fix[i]->rigid_flag) nrigid++;
if (nrigid) {
rfix = new int[nrigid];
nrigid = 0;
for (int i = 0; i < modify->nfix; i++)
if (modify->fix[i]->rigid_flag) rfix[nrigid++] = i;
}
}
/* ----------------------------------------------------------------------
compute T,P before integrator starts
------------------------------------------------------------------------- */
void FixNPT::setup(int vflag)
{
t_target = t_start; // used by compute_scalar()
p_target[0] = p_start[0];
p_target[1] = p_start[1];
p_target[2] = p_start[2];
t_current = temperature->compute_scalar();
if (press_couple == XYZ) {
double tmp = pressure->compute_scalar();
} else {
temperature->compute_vector();
pressure->compute_vector();
}
couple();
// trigger virial computation on next timestep
pressure->addstep(update->ntimestep+1);
}
/* ----------------------------------------------------------------------
1st half of Verlet update
------------------------------------------------------------------------- */
void FixNPT::initial_integrate(int vflag)
{
int i;
double dtfm;
double delta = update->ntimestep - update->beginstep;
delta /= update->endstep - update->beginstep;
// update eta_dot
t_target = t_start + delta * (t_stop-t_start);
f_eta = t_freq*t_freq * (t_current/t_target - 1.0);
eta_dot += f_eta*dthalf;
eta_dot *= drag_factor;
eta += dtv*eta_dot;
// update omega_dot
// for non-varying dims, p_freq is 0.0, so omega_dot doesn't change
double f_omega,volume;
if (dimension == 3) volume = domain->xprd*domain->yprd*domain->zprd;
else volume = domain->xprd*domain->yprd;
double denskt = atom->natoms*boltz*t_target / volume * nktv2p;
for (i = 0; i < 3; i++) {
p_target[i] = p_start[i] + delta * (p_stop[i]-p_start[i]);
f_omega = p_freq[i]*p_freq[i] * (p_current[i]-p_target[i])/denskt;
omega_dot[i] += f_omega*dthalf;
omega_dot[i] *= drag_factor;
omega[i] += dtv*omega_dot[i];
factor[i] = exp(-dthalf*(eta_dot+omega_dot[i]));
dilation[i] = exp(dthalf*omega_dot[i]);
}
// update v and x of atoms in group
// for BIAS:
// calculate temperature since some computes require temp
// computed on current nlocal atoms to remove bias
// OK to not test returned v = 0, since factor is multiplied by v
double **x = atom->x;
double **v = atom->v;
double **f = atom->f;
double *rmass = atom->rmass;
double *mass = atom->mass;
int *type = atom->type;
int *mask = atom->mask;
int nlocal = atom->nlocal;
if (igroup == atom->firstgroup) nlocal = atom->nfirst;
if (rmass) {
if (which == NOBIAS) {
for (i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtfm = dtf / rmass[i];
v[i][0] = v[i][0]*factor[0] + dtfm*f[i][0];
v[i][1] = v[i][1]*factor[1] + dtfm*f[i][1];
v[i][2] = v[i][2]*factor[2] + dtfm*f[i][2];
}
}
} else {
double tmp = temperature->compute_scalar();
for (i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
temperature->remove_bias(i,v[i]);
dtfm = dtf / rmass[i];
v[i][0] = v[i][0]*factor[0] + dtfm*f[i][0];
v[i][1] = v[i][1]*factor[1] + dtfm*f[i][1];
v[i][2] = v[i][2]*factor[2] + dtfm*f[i][2];
temperature->restore_bias(i,v[i]);
}
}
}
} else {
if (which == NOBIAS) {
for (i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtfm = dtf / mass[type[i]];
v[i][0] = v[i][0]*factor[0] + dtfm*f[i][0];
v[i][1] = v[i][1]*factor[1] + dtfm*f[i][1];
v[i][2] = v[i][2]*factor[2] + dtfm*f[i][2];
}
}
} else {
double tmp = temperature->compute_scalar();
for (i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
temperature->remove_bias(i,v[i]);
dtfm = dtf / mass[type[i]];
v[i][0] = v[i][0]*factor[0] + dtfm*f[i][0];
v[i][1] = v[i][1]*factor[1] + dtfm*f[i][1];
v[i][2] = v[i][2]*factor[2] + dtfm*f[i][2];
temperature->restore_bias(i,v[i]);
}
}
}
}
// remap simulation box by 1/2 step
remap();
// update x by full step for atoms in group
for (i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
x[i][0] += dtv * v[i][0];
x[i][1] += dtv * v[i][1];
x[i][2] += dtv * v[i][2];
}
}
// remap simulation box by 1/2 step
// redo KSpace coeffs since volume has changed
remap();
if (kspace_flag) force->kspace->setup();
}
/* ----------------------------------------------------------------------
2nd half of Verlet update
------------------------------------------------------------------------- */
void FixNPT::final_integrate()
{
int i;
double dtfm;
// update v of atoms in group
// for BIAS:
// calculate temperature since some computes require temp
// computed on current nlocal atoms to remove bias
// OK to not test returned v = 0, since factor is multiplied by v
double **v = atom->v;
double **f = atom->f;
double *rmass = atom->rmass;
double *mass = atom->mass;
int *type = atom->type;
int *mask = atom->mask;
int nlocal = atom->nlocal;
if (igroup == atom->firstgroup) nlocal = atom->nfirst;
if (rmass) {
if (which == NOBIAS) {
for (i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtfm = dtf / rmass[i];
v[i][0] = (v[i][0] + dtfm*f[i][0]) * factor[0];
v[i][1] = (v[i][1] + dtfm*f[i][1]) * factor[1];
v[i][2] = (v[i][2] + dtfm*f[i][2]) * factor[2];
}
}
} else {
double tmp = temperature->compute_scalar();
for (i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
temperature->remove_bias(i,v[i]);
dtfm = dtf / rmass[i];
v[i][0] = (v[i][0] + dtfm*f[i][0]) * factor[0];
v[i][1] = (v[i][1] + dtfm*f[i][1]) * factor[1];
v[i][2] = (v[i][2] + dtfm*f[i][2]) * factor[2];
temperature->restore_bias(i,v[i]);
}
}
}
} else {
if (which == NOBIAS) {
for (i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtfm = dtf / mass[type[i]];
v[i][0] = (v[i][0] + dtfm*f[i][0]) * factor[0];
v[i][1] = (v[i][1] + dtfm*f[i][1]) * factor[1];
v[i][2] = (v[i][2] + dtfm*f[i][2]) * factor[2];
}
}
} else {
double tmp = temperature->compute_scalar();
for (i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
temperature->remove_bias(i,v[i]);
dtfm = dtf / mass[type[i]];
v[i][0] = (v[i][0] + dtfm*f[i][0]) * factor[0];
v[i][1] = (v[i][1] + dtfm*f[i][1]) * factor[1];
v[i][2] = (v[i][2] + dtfm*f[i][2]) * factor[2];
temperature->restore_bias(i,v[i]);
}
}
}
}
// compute new T,P
t_current = temperature->compute_scalar();
if (press_couple == XYZ) {
double tmp = pressure->compute_scalar();
} else {
temperature->compute_vector();
pressure->compute_vector();
}
couple();
// trigger virial computation on next timestep
pressure->addstep(update->ntimestep+1);
// update eta_dot
f_eta = t_freq*t_freq * (t_current/t_target - 1.0);
eta_dot += f_eta*dthalf;
eta_dot *= drag_factor;
// update omega_dot
// for non-varying dims, p_freq is 0.0, so omega_dot doesn't change
double f_omega,volume;
if (dimension == 3) volume = domain->xprd*domain->yprd*domain->zprd;
else volume = domain->xprd*domain->yprd;
double denskt = atom->natoms*boltz*t_target / volume * nktv2p;
for (i = 0; i < 3; i++) {
f_omega = p_freq[i]*p_freq[i] * (p_current[i]-p_target[i])/denskt;
omega_dot[i] += f_omega*dthalf;
omega_dot[i] *= drag_factor;
}
}
/* ---------------------------------------------------------------------- */
void FixNPT::initial_integrate_respa(int vflag, int ilevel, int iloop)
{
// set timesteps by level
double dtfm;
dtv = step_respa[ilevel];
dtf = 0.5 * step_respa[ilevel] * force->ftm2v;
dthalf = 0.5 * step_respa[ilevel];
// atom quantities
double **x = atom->x;
double **v = atom->v;
double **f = atom->f;
double *rmass = atom->rmass;
double *mass = atom->mass;
int *type = atom->type;
int *mask = atom->mask;
int nlocal = atom->nlocal;
if (igroup == atom->firstgroup) nlocal = atom->nfirst;
// outermost level - update eta_dot and omega_dot, apply to v, remap box
// all other levels - NVE update of v
// x,v updates performed for atoms in group
if (ilevel == nlevels_respa-1) {
double delta = update->ntimestep - update->beginstep;
delta /= update->endstep - update->beginstep;
// update eta_dot
t_target = t_start + delta * (t_stop-t_start);
f_eta = t_freq*t_freq * (t_current/t_target - 1.0);
eta_dot += f_eta*dthalf;
eta_dot *= drag_factor;
eta += dtv*eta_dot;
// update omega_dot
// for non-varying dims, p_freq is 0.0, so omega_dot doesn't change
double f_omega,volume;
if (dimension == 3) volume = domain->xprd*domain->yprd*domain->zprd;
else volume = domain->xprd*domain->yprd;
double denskt = atom->natoms*boltz*t_target / volume * nktv2p;
for (int i = 0; i < 3; i++) {
p_target[i] = p_start[i] + delta * (p_stop[i]-p_start[i]);
f_omega = p_freq[i]*p_freq[i] * (p_current[i]-p_target[i])/denskt;
omega_dot[i] += f_omega*dthalf;
omega_dot[i] *= drag_factor;
omega[i] += dtv*omega_dot[i];
factor[i] = exp(-dthalf*(eta_dot+omega_dot[i]));
dilation[i] = exp(dthalf*omega_dot[i]);
}
// update v for atoms in group
if (rmass) {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtfm = dtf / rmass[i];
v[i][0] = v[i][0]*factor[0] + dtfm*f[i][0];
v[i][1] = v[i][1]*factor[1] + dtfm*f[i][1];
v[i][2] = v[i][2]*factor[2] + dtfm*f[i][2];
}
}
} else {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtfm = dtf / mass[type[i]];
v[i][0] = v[i][0]*factor[0] + dtfm*f[i][0];
v[i][1] = v[i][1]*factor[1] + dtfm*f[i][1];
v[i][2] = v[i][2]*factor[2] + dtfm*f[i][2];
}
}
}
// remap simulation box by 1/2 step
remap();
remap2flag = 1;
} else {
// update v for atoms in group
if (rmass) {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtfm = dtf / rmass[i];
v[i][0] += dtfm*f[i][0];
v[i][1] += dtfm*f[i][1];
v[i][2] += dtfm*f[i][2];
}
}
} else {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtfm = dtf / mass[type[i]];
v[i][0] += dtfm*f[i][0];
v[i][1] += dtfm*f[i][1];
v[i][2] += dtfm*f[i][2];
}
}
}
}
// innermost level - also update x for atoms in group
// if remap2flag:
// this is 1st call at innermost level from rRESPA after 1st half remap
// perform 2nd half of box remap
// redo KSpace coeffs since volume has changed
if (ilevel == 0) {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
x[i][0] += dtv * v[i][0];
x[i][1] += dtv * v[i][1];
x[i][2] += dtv * v[i][2];
}
}
if (remap2flag) {
remap();
if (kspace_flag) force->kspace->setup();
remap2flag = 0;
}
}
}
/* ---------------------------------------------------------------------- */
void FixNPT::final_integrate_respa(int ilevel, int iloop)
{
double dtfm;
// set timesteps by level
dtf = 0.5 * step_respa[ilevel] * force->ftm2v;
dthalf = 0.5 * step_respa[ilevel];
// outermost level - update eta_dot and omega_dot,
// apply to v via final_integrate()
// all other levels - NVE update of v
// update v for atoms in group
if (ilevel == nlevels_respa-1) final_integrate();
else {
// update v for atoms in group
double **v = atom->v;
double **f = atom->f;
double *rmass = atom->rmass;
double *mass = atom->mass;
int *type = atom->type;
int *mask = atom->mask;
int nlocal = atom->nlocal;
if (igroup == atom->firstgroup) nlocal = atom->nfirst;
if (rmass) {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtfm = dtf / rmass[i];
v[i][0] += dtfm*f[i][0];
v[i][1] += dtfm*f[i][1];
v[i][2] += dtfm*f[i][2];
}
}
} else {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtfm = dtf / mass[type[i]];
v[i][0] += dtfm*f[i][0];
v[i][1] += dtfm*f[i][1];
v[i][2] += dtfm*f[i][2];
}
}
}
}
}
/* ---------------------------------------------------------------------- */
void FixNPT::couple()
{
double *tensor = pressure->vector;
if (press_couple == XYZ)
p_current[0] = p_current[1] = p_current[2] = pressure->scalar;
else if (press_couple == XY) {
double ave = 0.5 * (tensor[0] + tensor[1]);
p_current[0] = p_current[1] = ave;
p_current[2] = tensor[2];
} else if (press_couple == YZ) {
double ave = 0.5 * (tensor[1] + tensor[2]);
p_current[1] = p_current[2] = ave;
p_current[0] = tensor[0];
} else if (press_couple == XZ) {
double ave = 0.5 * (tensor[0] + tensor[2]);
p_current[0] = p_current[2] = ave;
p_current[1] = tensor[1];
} else if (press_couple == ANISO) {
p_current[0] = tensor[0];
p_current[1] = tensor[1];
p_current[2] = tensor[2];
}
}
/* ----------------------------------------------------------------------
change box size
remap all atoms or fix group atoms depending on allremap flag
if rigid bodies exist, scale rigid body centers-of-mass
------------------------------------------------------------------------- */
void FixNPT::remap()
{
int i;
double oldlo,oldhi,ctr;
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
// convert pertinent atoms and rigid bodies to lamda coords
if (allremap) domain->x2lamda(nlocal);
else {
for (i = 0; i < nlocal; i++)
if (mask[i] & groupbit)
domain->x2lamda(x[i],x[i]);
}
if (nrigid)
for (i = 0; i < nrigid; i++)
modify->fix[rfix[i]]->deform(0);
// reset global and local box to new size/shape
for (i = 0; i < 3; i++) {
if (p_flag[i]) {
oldlo = domain->boxlo[i];
oldhi = domain->boxhi[i];
ctr = 0.5 * (oldlo + oldhi);
domain->boxlo[i] = (oldlo-ctr)*dilation[i] + ctr;
domain->boxhi[i] = (oldhi-ctr)*dilation[i] + ctr;
}
}
domain->set_global_box();
domain->set_local_box();
// convert pertinent atoms and rigid bodies back to box coords
if (allremap) domain->lamda2x(nlocal);
else {
for (i = 0; i < nlocal; i++)
if (mask[i] & groupbit)
domain->lamda2x(x[i],x[i]);
}
if (nrigid)
for (i = 0; i < nrigid; i++)
modify->fix[rfix[i]]->deform(1);
}
/* ----------------------------------------------------------------------
pack entire state of Fix into one write
------------------------------------------------------------------------- */
void FixNPT::write_restart(FILE *fp)
{
int n = 0;
double list[8];
list[n++] = eta;
list[n++] = eta_dot;
list[n++] = omega[0];
list[n++] = omega[1];
list[n++] = omega[2];
list[n++] = omega_dot[0];
list[n++] = omega_dot[1];
list[n++] = omega_dot[2];
if (comm->me == 0) {
int size = n * sizeof(double);
fwrite(&size,sizeof(int),1,fp);
fwrite(list,sizeof(double),n,fp);
}
}
/* ----------------------------------------------------------------------
use state info from restart file to restart the Fix
------------------------------------------------------------------------- */
void FixNPT::restart(char *buf)
{
int n = 0;
double *list = (double *) buf;
eta = list[n++];
eta_dot = list[n++];
omega[0] = list[n++];
omega[1] = list[n++];
omega[2] = list[n++];
omega_dot[0] = list[n++];
omega_dot[1] = list[n++];
omega_dot[2] = list[n++];
}
/* ---------------------------------------------------------------------- */
int FixNPT::modify_param(int narg, char **arg)
{
if (strcmp(arg[0],"temp") == 0) {
if (narg < 2) error->all("Illegal fix_modify command");
if (tflag) {
modify->delete_compute(id_temp);
tflag = 0;
}
delete [] id_temp;
int n = strlen(arg[1]) + 1;
id_temp = new char[n];
strcpy(id_temp,arg[1]);
int icompute = modify->find_compute(arg[1]);
if (icompute < 0) error->all("Could not find fix_modify temperature ID");
temperature = modify->compute[icompute];
if (temperature->tempflag == 0)
error->all("Fix_modify temperature ID does not compute temperature");
if (temperature->igroup != 0 && comm->me == 0)
error->warning("Temperature for fix modify is not for group all");
// reset id_temp of pressure to new temperature ID
icompute = modify->find_compute(id_press);
if (icompute < 0) error->all("Pressure ID for fix modify does not exist");
modify->compute[icompute]->reset_extra_compute_fix(id_temp);
return 2;
} else if (strcmp(arg[0],"press") == 0) {
if (narg < 2) error->all("Illegal fix_modify command");
if (pflag) {
modify->delete_compute(id_press);
pflag = 0;
}
delete [] id_press;
int n = strlen(arg[1]) + 1;
id_press = new char[n];
strcpy(id_press,arg[1]);
int icompute = modify->find_compute(arg[1]);
if (icompute < 0) error->all("Could not find fix_modify pressure ID");
pressure = modify->compute[icompute];
if (pressure->pressflag == 0)
error->all("Fix_modify pressure ID does not compute pressure");
return 2;
}
return 0;
}
/* ---------------------------------------------------------------------- */
double FixNPT::compute_scalar()
{
double ke = temperature->dof * boltz * t_target;
double keplus = atom->natoms * boltz * t_target;
double volume;
if (dimension == 3) volume = domain->xprd * domain->yprd * domain->zprd;
else volume = domain->xprd * domain->yprd;
int pdim = p_flag[0] + p_flag[1] + p_flag[2];
double energy = ke * (eta + 0.5*eta_dot*eta_dot/(t_freq*t_freq));
for (int i = 0; i < 3; i++)
if (p_freq[i] > 0.0)
energy += 0.5*keplus*omega_dot[i]*omega_dot[i] /
(p_freq[i]*p_freq[i]) + p_target[i]*(volume-vol0) / (pdim*nktv2p);
return energy;
}
/* ---------------------------------------------------------------------- */
void FixNPT::reset_dt()
{
dtv = update->dt;
dtf = 0.5 * update->dt * force->ftm2v;
dthalf = 0.5 * update->dt;
double freq = MAX(p_freq[0],p_freq[1]);
freq = MAX(freq,p_freq[2]);
drag_factor = 1.0 - (update->dt * freq * drag);
}

View File

@ -20,60 +20,14 @@ FixStyle(npt,FixNPT)
#ifndef LMP_FIX_NPT_H
#define LMP_FIX_NPT_H
#include "fix.h"
#include "fix_nh.h"
namespace LAMMPS_NS {
class FixNPT : public Fix {
class FixNPT : public FixNH {
public:
FixNPT(class LAMMPS *, int, char **);
virtual ~FixNPT();
int setmask();
virtual void init();
void setup(int);
virtual void initial_integrate(int);
virtual void final_integrate();
void initial_integrate_respa(int, int, int);
void final_integrate_respa(int, int);
double compute_scalar();
void write_restart(FILE *);
void restart(char *);
int modify_param(int, char **);
void reset_dt();
protected:
int dimension,which;
double dtv,dtf,dthalf;
double boltz,nktv2p;
double vol0;
double t_start,t_stop;
double t_current,t_target;
double t_freq;
double f_eta,eta_dot,eta;
int press_couple,allremap;
int p_flag[3]; // 1 if control P on this dim, 0 if not
double p_start[3],p_stop[3];
double p_freq[3],p_target[3];
double omega[3],omega_dot[3];
double p_current[3],dilation[3];
double drag,drag_factor;
double factor[3];
int kspace_flag; // 1 if KSpace invoked, 0 if not
int nrigid; // number of rigid fixes
int *rfix; // indices of rigid fixes
int nlevels_respa;
double *step_respa;
int remap2flag; // flag for performing 2nd half remap()
char *id_temp,*id_press;
class Compute *temperature,*pressure;
int tflag,pflag;
void couple();
void remap();
~FixNPT() {}
};
}

View File

@ -12,497 +12,56 @@
------------------------------------------------------------------------- */
#include "string.h"
#include "stdlib.h"
#include "math.h"
#include "fix_npt_sphere.h"
#include "atom.h"
#include "atom_vec.h"
#include "force.h"
#include "compute.h"
#include "kspace.h"
#include "update.h"
#include "domain.h"
#include "modify.h"
#include "error.h"
using namespace LAMMPS_NS;
#define INERTIA 0.4 // moment of inertia for sphere
enum{NOBIAS,BIAS};
/* ---------------------------------------------------------------------- */
FixNPTSphere::FixNPTSphere(LAMMPS *lmp, int narg, char **arg) :
FixNPT(lmp, narg, arg)
FixNHSphere(lmp, narg, arg)
{
// error checks
if (!tstat_flag)
error->all("Temperature control must be used with fix npt/sphere");
if (!pstat_flag)
error->all("Pressure control must be used with fix npt/sphere");
if (!atom->omega_flag || !atom->torque_flag)
error->all("Fix npt/sphere requires atom attributes omega, torque");
if (!atom->radius_flag && !atom->avec->shape_type)
error->all("Fix npt/sphere requires atom attribute radius or shape");
}
/* ---------------------------------------------------------------------- */
void FixNPTSphere::init()
{
int i,itype;
// check that all particles are finite-size and spherical
// no point particles allowed
if (atom->radius_flag) {
double *radius = atom->radius;
int *mask = atom->mask;
int nlocal = atom->nlocal;
if (igroup == atom->firstgroup) nlocal = atom->nfirst;
for (i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
if (radius[i] == 0.0)
error->one("Fix nvt/sphere requires extended particles");
}
} else {
double **shape = atom->shape;
int *type = atom->type;
int *mask = atom->mask;
int nlocal = atom->nlocal;
if (igroup == atom->firstgroup) nlocal = atom->nfirst;
for (i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
itype = type[i];
if (shape[itype][0] == 0.0)
error->one("Fix nvt/sphere requires extended particles");
if (shape[itype][0] != shape[itype][1] ||
shape[itype][0] != shape[itype][2])
error->one("Fix nvt/sphere requires spherical particle shapes");
}
}
FixNPT::init();
}
/* ---------------------------------------------------------------------- */
void FixNPTSphere::initial_integrate(int vflag)
{
int i,itype;
double dtfm,dtirotate;
double delta = update->ntimestep - update->beginstep;
delta /= update->endstep - update->beginstep;
// update eta_dot
t_target = t_start + delta * (t_stop-t_start);
f_eta = t_freq*t_freq * (t_current/t_target - 1.0);
eta_dot += f_eta*dthalf;
eta_dot *= drag_factor;
eta += dtv*eta_dot;
// update omega_dot
// for non-varying dims, p_freq is 0.0, so omega_dot doesn't change
double f_omega,volume;
if (dimension == 3) volume = domain->xprd*domain->yprd*domain->zprd;
else volume = domain->xprd*domain->yprd;
double denskt = atom->natoms*boltz*t_target / volume * nktv2p;
for (i = 0; i < 3; i++) {
p_target[i] = p_start[i] + delta * (p_stop[i]-p_start[i]);
f_omega = p_freq[i]*p_freq[i] * (p_current[i]-p_target[i])/denskt;
omega_dot[i] += f_omega*dthalf;
omega_dot[i] *= drag_factor;
omega[i] += dtv*omega_dot[i];
factor[i] = exp(-dthalf*(eta_dot+omega_dot[i]));
dilation[i] = exp(dthalf*omega_dot[i]);
}
factor_rotate = exp(-dthalf*eta_dot);
// update v of atoms in group
// for BIAS:
// calculate temperature since some computes require temp
// computed on current nlocal atoms to remove bias
// OK to not test returned v = 0, since factor is multiplied by v
double **x = atom->x;
double **v = atom->v;
double **f = atom->f;
double **omega = atom->omega;
double **torque = atom->torque;
double *radius = atom->radius;
double *rmass = atom->rmass;
double *mass = atom->mass;
double **shape = atom->shape;
int *type = atom->type;
int *mask = atom->mask;
int nlocal = atom->nlocal;
if (igroup == atom->firstgroup) nlocal = atom->nfirst;
if (rmass) {
if (which == NOBIAS) {
for (i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtfm = dtf / rmass[i];
v[i][0] = v[i][0]*factor[0] + dtfm*f[i][0];
v[i][1] = v[i][1]*factor[1] + dtfm*f[i][1];
v[i][2] = v[i][2]*factor[2] + dtfm*f[i][2];
}
}
} else {
double tmp = temperature->compute_scalar();
for (i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
temperature->remove_bias(i,v[i]);
dtfm = dtf / rmass[i];
v[i][0] = v[i][0]*factor[0] + dtfm*f[i][0];
v[i][1] = v[i][1]*factor[1] + dtfm*f[i][1];
v[i][2] = v[i][2]*factor[2] + dtfm*f[i][2];
temperature->restore_bias(i,v[i]);
}
}
}
} else {
if (which == NOBIAS) {
for (i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtfm = dtf / mass[type[i]];
v[i][0] = v[i][0]*factor[0] + dtfm*f[i][0];
v[i][1] = v[i][1]*factor[1] + dtfm*f[i][1];
v[i][2] = v[i][2]*factor[2] + dtfm*f[i][2];
}
}
} else {
double tmp = temperature->compute_scalar();
for (i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
temperature->remove_bias(i,v[i]);
dtfm = dtf / mass[type[i]];
v[i][0] = v[i][0]*factor[0] + dtfm*f[i][0];
v[i][1] = v[i][1]*factor[1] + dtfm*f[i][1];
v[i][2] = v[i][2]*factor[2] + dtfm*f[i][2];
temperature->restore_bias(i,v[i]);
}
}
}
}
// remap simulation box by 1/2 step
remap();
// update x by full step for atoms in group
for (i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
x[i][0] += dtv * v[i][0];
x[i][1] += dtv * v[i][1];
x[i][2] += dtv * v[i][2];
}
}
// set timestep here since dt may have changed or come via rRESPA
double dtfrotate = dtf / INERTIA;
// update omega for all particles
// d_omega/dt = torque / inertia
// 4 cases depending on radius vs shape and rmass vs mass
if (radius) {
if (rmass) {
for (i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtirotate = dtfrotate / (radius[i]*radius[i]*rmass[i]);
omega[i][0] = omega[i][0]*factor_rotate + dtirotate*torque[i][0];
omega[i][1] = omega[i][1]*factor_rotate + dtirotate*torque[i][1];
omega[i][2] = omega[i][2]*factor_rotate + dtirotate*torque[i][2];
}
}
} else {
for (i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtirotate = dtfrotate / (radius[i]*radius[i]*mass[type[i]]);
omega[i][0] = omega[i][0]*factor_rotate + dtirotate*torque[i][0];
omega[i][1] = omega[i][1]*factor_rotate + dtirotate*torque[i][1];
omega[i][2] = omega[i][2]*factor_rotate + dtirotate*torque[i][2];
}
}
}
} else {
if (rmass) {
for (i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
itype = type[i];
dtirotate = dtfrotate / (shape[itype][0]*shape[itype][0]*rmass[i]);
omega[i][0] = omega[i][0]*factor_rotate + dtirotate*torque[i][0];
omega[i][1] = omega[i][1]*factor_rotate + dtirotate*torque[i][1];
omega[i][2] = omega[i][2]*factor_rotate + dtirotate*torque[i][2];
}
}
} else {
for (i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
itype = type[i];
dtirotate = dtfrotate /
(shape[itype][0]*shape[itype][0]*mass[itype]);
omega[i][0] = omega[i][0]*factor_rotate + dtirotate*torque[i][0];
omega[i][1] = omega[i][1]*factor_rotate + dtirotate*torque[i][1];
omega[i][2] = omega[i][2]*factor_rotate + dtirotate*torque[i][2];
}
}
}
}
// remap simulation box by 1/2 step
// redo KSpace coeffs since volume has changed
remap();
if (kspace_flag) force->kspace->setup();
}
/* ---------------------------------------------------------------------- */
void FixNPTSphere::final_integrate()
{
int i,itype;
double dtfm,dtirotate;
double **v = atom->v;
double **f = atom->f;
double **omega = atom->omega;
double **torque = atom->torque;
double *radius = atom->radius;
double *rmass = atom->rmass;
double *mass = atom->mass;
double **shape = atom->shape;
int *type = atom->type;
int *mask = atom->mask;
int nlocal = atom->nlocal;
if (igroup == atom->firstgroup) nlocal = atom->nfirst;
// set timestep here since dt may have changed or come via rRESPA
double dtfrotate = dtf / INERTIA;
// update v,omega of atoms in group
// d_omega/dt = torque / inertia
// 8 cases depending on radius vs shape, rmass vs mass, bias vs nobias
// for BIAS:
// calculate temperature since some computes require temp
// computed on current nlocal atoms to remove bias
// OK to not test returned v = 0, since factor is multiplied by v
if (radius) {
if (rmass) {
if (which == NOBIAS) {
for (i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtfm = dtf / rmass[i];
v[i][0] = (v[i][0] + dtfm*f[i][0]) * factor[0];
v[i][1] = (v[i][1] + dtfm*f[i][1]) * factor[1];
v[i][2] = (v[i][2] + dtfm*f[i][2]) * factor[2];
dtirotate = dtfrotate / (radius[i]*radius[i]*rmass[i]);
omega[i][0] = (omega[i][0] + dtirotate*torque[i][0]) *
factor_rotate;
omega[i][1] = (omega[i][1] + dtirotate*torque[i][1]) *
factor_rotate;
omega[i][2] = (omega[i][2] + dtirotate*torque[i][2]) *
factor_rotate;
}
}
} else {
double tmp = temperature->compute_scalar();
for (i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
temperature->remove_bias(i,v[i]);
dtfm = dtf / rmass[i];
v[i][0] = (v[i][0] + dtfm*f[i][0]) * factor[0];
v[i][1] = (v[i][1] + dtfm*f[i][1]) * factor[1];
v[i][2] = (v[i][2] + dtfm*f[i][2]) * factor[2];
temperature->restore_bias(i,v[i]);
dtirotate = dtfrotate / (radius[i]*radius[i]*rmass[i]);
omega[i][0] = (omega[i][0] + dtirotate*torque[i][0]) *
factor_rotate;
omega[i][1] = (omega[i][1] + dtirotate*torque[i][1]) *
factor_rotate;
omega[i][2] = (omega[i][2] + dtirotate*torque[i][2]) *
factor_rotate;
}
}
}
} else {
if (which == NOBIAS) {
for (i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
itype = type[i];
dtfm = dtf / mass[itype];
v[i][0] = (v[i][0] + dtfm*f[i][0]) * factor[0];
v[i][1] = (v[i][1] + dtfm*f[i][1]) * factor[1];
v[i][2] = (v[i][2] + dtfm*f[i][2]) * factor[2];
dtirotate = dtfrotate / (radius[i]*radius[i]*mass[itype]);
omega[i][0] = (omega[i][0] + dtirotate*torque[i][0]) *
factor_rotate;
omega[i][1] = (omega[i][1] + dtirotate*torque[i][1]) *
factor_rotate;
omega[i][2] = (omega[i][2] + dtirotate*torque[i][2]) *
factor_rotate;
}
}
} else {
for (i = 0; i < nlocal; i++) {
double tmp = temperature->compute_scalar();
if (mask[i] & groupbit) {
itype = type[i];
temperature->remove_bias(i,v[i]);
dtfm = dtf / mass[itype];
v[i][0] = (v[i][0] + dtfm*f[i][0]) * factor[0];
v[i][1] = (v[i][1] + dtfm*f[i][1]) * factor[1];
v[i][2] = (v[i][2] + dtfm*f[i][2]) * factor[2];
temperature->restore_bias(i,v[i]);
dtirotate = dtfrotate / (radius[i]*radius[i]*mass[itype]);
omega[i][0] = (omega[i][0] + dtirotate*torque[i][0]) *
factor_rotate;
omega[i][1] = (omega[i][1] + dtirotate*torque[i][1]) *
factor_rotate;
omega[i][2] = (omega[i][2] + dtirotate*torque[i][2]) *
factor_rotate;
}
}
}
}
} else {
if (rmass) {
if (which == NOBIAS) {
for (i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
itype = type[i];
dtfm = dtf / rmass[i];
v[i][0] = (v[i][0] + dtfm*f[i][0]) * factor[0];
v[i][1] = (v[i][1] + dtfm*f[i][1]) * factor[1];
v[i][2] = (v[i][2] + dtfm*f[i][2]) * factor[2];
dtirotate = dtfrotate / (shape[itype][0]*shape[itype][0]*rmass[i]);
omega[i][0] = (omega[i][0] + dtirotate*torque[i][0]) *
factor_rotate;
omega[i][1] = (omega[i][1] + dtirotate*torque[i][1]) *
factor_rotate;
omega[i][2] = (omega[i][2] + dtirotate*torque[i][2]) *
factor_rotate;
}
}
} else {
double tmp = temperature->compute_scalar();
for (i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
itype = type[i];
temperature->remove_bias(i,v[i]);
dtfm = dtf / rmass[i];
v[i][0] = (v[i][0] + dtfm*f[i][0]) * factor[0];
v[i][1] = (v[i][1] + dtfm*f[i][1]) * factor[1];
v[i][2] = (v[i][2] + dtfm*f[i][2]) * factor[2];
temperature->restore_bias(i,v[i]);
dtirotate = dtfrotate / (shape[itype][0]*shape[itype][0]*rmass[i]);
omega[i][0] = (omega[i][0] + dtirotate*torque[i][0]) *
factor_rotate;
omega[i][1] = (omega[i][1] + dtirotate*torque[i][1]) *
factor_rotate;
omega[i][2] = (omega[i][2] + dtirotate*torque[i][2]) *
factor_rotate;
}
}
}
} else {
if (which == NOBIAS) {
for (i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
itype = type[i];
dtfm = dtf / mass[itype];
v[i][0] = (v[i][0] + dtfm*f[i][0]) * factor[0];
v[i][1] = (v[i][1] + dtfm*f[i][1]) * factor[1];
v[i][2] = (v[i][2] + dtfm*f[i][2]) * factor[2];
dtirotate = dtfrotate /
(shape[itype][0]*shape[itype][0]*mass[itype]);
omega[i][0] = (omega[i][0] + dtirotate*torque[i][0]) *
factor_rotate;
omega[i][1] = (omega[i][1] + dtirotate*torque[i][1]) *
factor_rotate;
omega[i][2] = (omega[i][2] + dtirotate*torque[i][2]) *
factor_rotate;
}
}
} else {
double tmp = temperature->compute_scalar();
for (i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
itype = type[i];
temperature->remove_bias(i,v[i]);
dtfm = dtf / mass[itype];
v[i][0] = (v[i][0] + dtfm*f[i][0]) * factor[0];
v[i][1] = (v[i][1] + dtfm*f[i][1]) * factor[1];
v[i][2] = (v[i][2] + dtfm*f[i][2]) * factor[2];
temperature->restore_bias(i,v[i]);
dtirotate = dtfrotate /
(shape[itype][0]*shape[itype][0]*mass[itype]);
omega[i][0] = (omega[i][0] + dtirotate*torque[i][0]) *
factor_rotate;
omega[i][1] = (omega[i][1] + dtirotate*torque[i][1]) *
factor_rotate;
omega[i][2] = (omega[i][2] + dtirotate*torque[i][2]) *
factor_rotate;
}
}
}
}
}
// compute new T,P
t_current = temperature->compute_scalar();
if (press_couple == 0) {
double tmp = pressure->compute_scalar();
} else {
temperature->compute_vector();
pressure->compute_vector();
}
couple();
// trigger virial computation on next timestep
pressure->addstep(update->ntimestep+1);
// update eta_dot
f_eta = t_freq*t_freq * (t_current/t_target - 1.0);
eta_dot += f_eta*dthalf;
eta_dot *= drag_factor;
// update omega_dot
// for non-varying dims, p_freq is 0.0, so omega_dot doesn't change
double f_omega,volume;
if (dimension == 3) volume = domain->xprd*domain->yprd*domain->zprd;
else volume = domain->xprd*domain->yprd;
double denskt = atom->natoms*boltz*t_target / volume * nktv2p;
for (i = 0; i < 3; i++) {
f_omega = p_freq[i]*p_freq[i] * (p_current[i]-p_target[i])/denskt;
omega_dot[i] += f_omega*dthalf;
omega_dot[i] *= drag_factor;
}
// create a new compute temp style
// id = fix-ID + temp
// compute group = all since pressure is always global (group all)
// and thus its KE/temperature contribution should use group all
int n = strlen(id) + 6;
id_temp = new char[n];
strcpy(id_temp,id);
strcat(id_temp,"_temp");
char **newarg = new char*[3];
newarg[0] = id_temp;
newarg[1] = (char *) "all";
newarg[2] = (char *) "temp/sphere";
modify->add_compute(3,newarg);
delete [] newarg;
tflag = 1;
// create a new compute pressure style
// id = fix-ID + press, compute group = all
// pass id_temp as 4th arg to pressure constructor
n = strlen(id) + 7;
id_press = new char[n];
strcpy(id_press,id);
strcat(id_press,"_press");
newarg = new char*[4];
newarg[0] = id_press;
newarg[1] = (char *) "all";
newarg[2] = (char *) "pressure";
newarg[3] = id_temp;
modify->add_compute(4,newarg);
delete [] newarg;
pflag = 1;
}

View File

@ -20,20 +20,14 @@ FixStyle(npt/sphere,FixNPTSphere)
#ifndef LMP_FIX_NPT_SPHERE_H
#define LMP_FIX_NPT_SPHERE_H
#include "fix_npt.h"
#include "fix_nh_sphere.h"
namespace LAMMPS_NS {
class FixNPTSphere : public FixNPT {
class FixNPTSphere : public FixNHSphere {
public:
FixNPTSphere(class LAMMPS *, int, char **);
~FixNPTSphere() {}
void init();
void initial_integrate(int);
void final_integrate();
private:
double factor_rotate;
};
}

View File

@ -11,693 +11,38 @@
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing authors: Mark Stevens (SNL)
Andy Ballard (U Maryland) for Nose/Hoover chains
------------------------------------------------------------------------- */
#include "string.h"
#include "stdlib.h"
#include "math.h"
#include "fix_nvt.h"
#include "atom.h"
#include "force.h"
#include "comm.h"
#include "group.h"
#include "update.h"
#include "respa.h"
#include "modify.h"
#include "compute.h"
#include "error.h"
using namespace LAMMPS_NS;
enum{NOBIAS,BIAS};
/* ---------------------------------------------------------------------- */
FixNVT::FixNVT(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg)
FixNH(lmp, narg, arg)
{
if (narg < 6) error->all("Illegal fix nvt command");
restart_global = 1;
time_integrate = 1;
scalar_flag = 1;
global_freq = 1;
extscalar = 1;
t_start = atof(arg[3]);
t_stop = atof(arg[4]);
double t_period = atof(arg[5]);
drag = 0.0;
chain = 1;
int iarg = 6;
while (iarg < narg) {
if (strcmp(arg[iarg],"drag") == 0) {
if (iarg+2 > narg) error->all("Illegal fix nvt command");
drag = atof(arg[iarg+1]);
if (drag < 0.0) error->all("Illegal fix nvt command");
iarg += 2;
} else if (strcmp(arg[iarg],"chain") == 0) {
if (iarg+2 > narg) error->all("Illegal fix nvt command");
if (strcmp(arg[iarg+1],"yes") == 0) chain = 1;
else if (strcmp(arg[iarg+1],"no") == 0) chain = 0;
else error->all("Illegal fix nvt command");
iarg += 2;
} else error->all("Illegal fix nvt command");
}
// error checks
// convert input period to frequency
if (t_start < 0.0 || t_stop <= 0.0)
error->all("Target T for fix nvt cannot be 0.0");
if (t_period <= 0.0) error->all("Fix nvt period must be > 0.0");
t_freq = 1.0 / t_period;
if (!tstat_flag)
error->all("Temperature control must be used with fix nvt");
if (pstat_flag)
error->all("Pressure control can not be used with fix nvt");
// create a new compute temp style
// id = fix-ID + temp, compute group = fix group
// id = fix-ID + temp
int n = strlen(id) + 6;
id_temp = new char[n];
strcpy(id_temp,id);
strcat(id_temp,"_temp");
char **newarg = new char*[3];
newarg[0] = id_temp;
newarg[1] = group->names[igroup];
if (strcmp(style,"nvt") == 0)
newarg[2] = (char *) "temp";
else if (strcmp(style,"nvt/asphere") == 0)
newarg[2] = (char *) "temp/asphere";
else if (strcmp(style,"nvt/sllod") == 0)
newarg[2] = (char *) "temp/deform";
else if (strcmp(style,"nvt/sphere") == 0)
newarg[2] = (char *) "temp/sphere";
newarg[2] = (char *) "temp";
modify->add_compute(3,newarg);
delete [] newarg;
tflag = 1;
// Nose/Hoover temp init
eta = eta_dot = 0.0;
eta2 = eta2_dot = 0.0;
}
/* ---------------------------------------------------------------------- */
FixNVT::~FixNVT()
{
// delete temperature if fix created it
if (tflag) modify->delete_compute(id_temp);
delete [] id_temp;
}
/* ---------------------------------------------------------------------- */
int FixNVT::setmask()
{
int mask = 0;
mask |= INITIAL_INTEGRATE;
mask |= FINAL_INTEGRATE;
mask |= THERMO_ENERGY;
mask |= INITIAL_INTEGRATE_RESPA;
mask |= FINAL_INTEGRATE_RESPA;
return mask;
}
/* ---------------------------------------------------------------------- */
void FixNVT::init()
{
int icompute = modify->find_compute(id_temp);
if (icompute < 0) error->all("Temperature ID for fix nvt does not exist");
temperature = modify->compute[icompute];
if (temperature->tempbias) which = BIAS;
else which = NOBIAS;
// set timesteps and frequencies
dtv = update->dt;
dtf = 0.5 * update->dt * force->ftm2v;
dthalf = 0.5 * update->dt;
dt4 = 0.25 * update->dt;
dt8 = 0.125 * update->dt;
drag_factor = 1.0 - (update->dt * t_freq * drag);
if (strcmp(update->integrate_style,"respa") == 0) {
nlevels_respa = ((Respa *) update->integrate)->nlevels;
step_respa = ((Respa *) update->integrate)->step;
}
}
/* ---------------------------------------------------------------------- */
void FixNVT::setup(int vflag)
{
t_target = t_start; // used by compute_scalar()
t_current = temperature->compute_scalar();
}
/* ---------------------------------------------------------------------- */
void FixNVT::initial_integrate(int vflag)
{
double dtfm;
double delta = update->ntimestep - update->beginstep;
delta /= update->endstep - update->beginstep;
t_target = t_start + delta * (t_stop-t_start);
// update eta, eta_dot, eta2, eta2_dot
int nlocal = atom->nlocal;
if (igroup == atom->firstgroup) nlocal = atom->nfirst;
if (chain) {
eta2_dot += (temperature->dof * eta_dot*eta_dot - t_freq*t_freq) * dt4;
factor2 = exp(-dt8*eta2_dot);
eta_dot *= factor2;
f_eta = t_freq*t_freq * (t_current/t_target - 1.0);
eta_dot += f_eta*dt4;
eta_dot *= drag_factor;
eta_dot *= factor2;
eta += dthalf*eta_dot;
eta2 += dthalf*eta2_dot;
} else {
f_eta = t_freq*t_freq * (t_current/t_target - 1.0);
eta_dot += f_eta*dthalf;
eta_dot *= drag_factor;
eta += dtv*eta_dot;
}
factor = exp(-dthalf*eta_dot);
// update v and x of atoms in group
// for BIAS:
// calculate temperature since some computes require temp
// computed on current nlocal atoms to remove bias
// OK to not test returned v = 0, since factor is multiplied by v
double **x = atom->x;
double **v = atom->v;
double **f = atom->f;
double *rmass = atom->rmass;
double *mass = atom->mass;
int *type = atom->type;
int *mask = atom->mask;
if (rmass) {
if (which == NOBIAS) {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtfm = dtf / rmass[i];
v[i][0] = v[i][0]*factor + dtfm*f[i][0];
v[i][1] = v[i][1]*factor + dtfm*f[i][1];
v[i][2] = v[i][2]*factor + dtfm*f[i][2];
x[i][0] += dtv * v[i][0];
x[i][1] += dtv * v[i][1];
x[i][2] += dtv * v[i][2];
}
}
} else {
double tmp = temperature->compute_scalar();
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
temperature->remove_bias(i,v[i]);
dtfm = dtf / rmass[i];
v[i][0] = v[i][0]*factor + dtfm*f[i][0];
v[i][1] = v[i][1]*factor + dtfm*f[i][1];
v[i][2] = v[i][2]*factor + dtfm*f[i][2];
temperature->restore_bias(i,v[i]);
x[i][0] += dtv * v[i][0];
x[i][1] += dtv * v[i][1];
x[i][2] += dtv * v[i][2];
}
}
}
} else {
if (which == NOBIAS) {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtfm = dtf / mass[type[i]];
v[i][0] = v[i][0]*factor + dtfm*f[i][0];
v[i][1] = v[i][1]*factor + dtfm*f[i][1];
v[i][2] = v[i][2]*factor + dtfm*f[i][2];
x[i][0] += dtv * v[i][0];
x[i][1] += dtv * v[i][1];
x[i][2] += dtv * v[i][2];
}
}
} else {
double tmp = temperature->compute_scalar();
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
temperature->remove_bias(i,v[i]);
dtfm = dtf / mass[type[i]];
v[i][0] = v[i][0]*factor + dtfm*f[i][0];
v[i][1] = v[i][1]*factor + dtfm*f[i][1];
v[i][2] = v[i][2]*factor + dtfm*f[i][2];
temperature->restore_bias(i,v[i]);
x[i][0] += dtv * v[i][0];
x[i][1] += dtv * v[i][1];
x[i][2] += dtv * v[i][2];
}
}
}
}
if (chain) {
eta_dot *= factor2;
f_eta = t_freq*t_freq * (factor * factor * t_current/t_target - 1.0);
eta_dot += f_eta * dt4;
eta_dot *= factor2;
eta2_dot += (temperature->dof * eta_dot*eta_dot - t_freq*t_freq) * dt4;
}
}
/* ---------------------------------------------------------------------- */
void FixNVT::final_integrate()
{
double dtfm;
// update v of atoms in group
// for BIAS:
// calculate temperature since some computes require temp
// computed on current nlocal atoms to remove bias
// OK to not test returned v = 0, since factor is multiplied by v
double **v = atom->v;
double **f = atom->f;
double *rmass = atom->rmass;
double *mass = atom->mass;
int *type = atom->type;
int *mask = atom->mask;
int nlocal = atom->nlocal;
if (igroup == atom->firstgroup) nlocal = atom->nfirst;
if (chain) factor = 1.0;
if (rmass) {
if (which == NOBIAS) {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtfm = dtf / rmass[i] * factor;
v[i][0] = v[i][0]*factor + dtfm*f[i][0];
v[i][1] = v[i][1]*factor + dtfm*f[i][1];
v[i][2] = v[i][2]*factor + dtfm*f[i][2];
}
}
} else {
double tmp = temperature->compute_scalar();
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
temperature->remove_bias(i,v[i]);
dtfm = dtf / rmass[i] * factor;
v[i][0] = v[i][0]*factor + dtfm*f[i][0];
v[i][1] = v[i][1]*factor + dtfm*f[i][1];
v[i][2] = v[i][2]*factor + dtfm*f[i][2];
temperature->restore_bias(i,v[i]);
}
}
}
} else {
if (which == NOBIAS) {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtfm = dtf / mass[type[i]] * factor;
v[i][0] = v[i][0]*factor + dtfm*f[i][0];
v[i][1] = v[i][1]*factor + dtfm*f[i][1];
v[i][2] = v[i][2]*factor + dtfm*f[i][2];
}
}
} else {
double tmp = temperature->compute_scalar();
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
temperature->remove_bias(i,v[i]);
dtfm = dtf / mass[type[i]] * factor;
v[i][0] = v[i][0]*factor + dtfm*f[i][0];
v[i][1] = v[i][1]*factor + dtfm*f[i][1];
v[i][2] = v[i][2]*factor + dtfm*f[i][2];
temperature->restore_bias(i,v[i]);
}
}
}
}
// compute current T
t_current = temperature->compute_scalar();
// update eta, eta_dot, eta2, eta2_dot
// chains require additional velocity update and recompute of current T
if (chain) {
eta2_dot += (temperature->dof * eta_dot*eta_dot - t_freq*t_freq) * dt4;
factor2 = exp(-dt8*eta2_dot);
eta_dot *= factor2;
f_eta = t_freq*t_freq * (t_current/t_target - 1.0);
eta_dot += f_eta*dt4;
eta_dot *= drag_factor;
eta_dot *= factor2;
eta += dthalf*eta_dot;
eta2 += dthalf*eta2_dot;
factor = exp(-dthalf*eta_dot);
if (rmass) {
if (which == NOBIAS) {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtfm = dtf / mass[type[i]];
v[i][0] *= factor;
v[i][1] *= factor;
v[i][2] *= factor;
}
}
} else {
double tmp = temperature->compute_scalar();
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
temperature->remove_bias(i,v[i]);
dtfm = dtf / mass[type[i]];
v[i][0] *= factor;
v[i][1] *= factor;
v[i][2] *= factor;
temperature->restore_bias(i,v[i]);
}
}
}
} else {
if (which == NOBIAS) {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtfm = dtf / mass[type[i]];
v[i][0] *= factor;
v[i][1] *= factor;
v[i][2] *= factor;
}
}
} else {
double tmp = temperature->compute_scalar();
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
temperature->remove_bias(i,v[i]);
dtfm = dtf / mass[type[i]];
v[i][0] *= factor;
v[i][1] *= factor;
v[i][2] *= factor;
temperature->restore_bias(i,v[i]);
}
}
}
}
t_current = temperature->compute_scalar();
eta_dot *= factor2;
f_eta = t_freq*t_freq * (t_current/t_target - 1.0);
eta_dot += f_eta * dt4;
eta_dot *= factor2;
eta2_dot += (temperature->dof * eta_dot*eta_dot - t_freq*t_freq) * dt4;
} else {
f_eta = t_freq*t_freq * (t_current/t_target - 1.0);
eta_dot += f_eta*dthalf;
eta_dot *= drag_factor;
}
}
/* ---------------------------------------------------------------------- */
void FixNVT::initial_integrate_respa(int vflag, int ilevel, int iloop)
{
// set timesteps by level
double dtfm;
dtv = step_respa[ilevel];
dtf = 0.5 * step_respa[ilevel] * force->ftm2v;
dthalf = 0.5 * step_respa[ilevel];
// atom quantities
double **x = atom->x;
double **v = atom->v;
double **f = atom->f;
double *rmass = atom->rmass;
double *mass = atom->mass;
int *type = atom->type;
int *mask = atom->mask;
int nlocal = atom->nlocal;
if (igroup == atom->firstgroup) nlocal = atom->nfirst;
// outermost level - update eta_dot and apply to v with factor
// all other levels - NVE update of v (factor = 1)
// innermost level - also update x
if (ilevel == nlevels_respa-1) {
double delta = update->ntimestep - update->beginstep;
delta /= update->endstep - update->beginstep;
t_target = t_start + delta * (t_stop-t_start);
if (chain) {
eta2_dot += (temperature->dof * eta_dot*eta_dot - t_freq*t_freq) * dt4;
factor2 = exp(-dt8*eta2_dot);
eta_dot *= factor2;
f_eta = t_freq*t_freq * (t_current/t_target - 1.0);
eta_dot += f_eta*dt4;
eta_dot *= drag_factor;
eta_dot *= factor2;
eta += dthalf*eta_dot;
eta2 += dthalf*eta2_dot;
} else {
f_eta = t_freq*t_freq * (t_current/t_target - 1.0);
eta_dot += f_eta*dthalf;
eta_dot *= drag_factor;
eta += dtv*eta_dot;
}
factor = exp(-dthalf*eta_dot);
} else factor = 1.0;
if (rmass) {
if (which == NOBIAS) {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtfm = dtf / rmass[i];
v[i][0] = v[i][0]*factor + dtfm*f[i][0];
v[i][1] = v[i][1]*factor + dtfm*f[i][1];
v[i][2] = v[i][2]*factor + dtfm*f[i][2];
}
}
} else {
double tmp = temperature->compute_scalar();
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
temperature->remove_bias(i,v[i]);
dtfm = dtf / rmass[i];
v[i][0] = v[i][0]*factor + dtfm*f[i][0];
v[i][1] = v[i][1]*factor + dtfm*f[i][1];
v[i][2] = v[i][2]*factor + dtfm*f[i][2];
temperature->restore_bias(i,v[i]);
}
}
}
} else {
if (which == NOBIAS) {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtfm = dtf / mass[type[i]];
v[i][0] = v[i][0]*factor + dtfm*f[i][0];
v[i][1] = v[i][1]*factor + dtfm*f[i][1];
v[i][2] = v[i][2]*factor + dtfm*f[i][2];
}
}
} else {
double tmp = temperature->compute_scalar();
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
temperature->remove_bias(i,v[i]);
dtfm = dtf / mass[type[i]];
v[i][0] = v[i][0]*factor + dtfm*f[i][0];
v[i][1] = v[i][1]*factor + dtfm*f[i][1];
v[i][2] = v[i][2]*factor + dtfm*f[i][2];
temperature->restore_bias(i,v[i]);
}
}
}
}
if (ilevel == 0) {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
x[i][0] += dtv * v[i][0];
x[i][1] += dtv * v[i][1];
x[i][2] += dtv * v[i][2];
}
}
}
if (ilevel == nlevels_respa-1 && chain) {
eta_dot *= factor2;
f_eta = t_freq*t_freq * (factor * factor * t_current/t_target - 1.0);
eta_dot += f_eta * dt4;
eta_dot *= factor2;
eta2_dot += (temperature->dof * eta_dot*eta_dot - t_freq*t_freq) * dt4;
}
}
/* ---------------------------------------------------------------------- */
void FixNVT::final_integrate_respa(int ilevel, int iloop)
{
// set timesteps by level
double dtfm;
dtf = 0.5 * step_respa[ilevel] * force->ftm2v;
dthalf = 0.5 * step_respa[ilevel];
// outermost level - update eta_dot and apply to v via final_integrate()
// all other levels - NVE update of v
if (ilevel == nlevels_respa-1) final_integrate();
else {
double **v = atom->v;
double **f = atom->f;
double *rmass = atom->rmass;
double *mass = atom->mass;
int *type = atom->type;
int *mask = atom->mask;
int nlocal = atom->nlocal;
if (igroup == atom->firstgroup) nlocal = atom->nfirst;
if (rmass) {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtfm = dtf / rmass[i];
v[i][0] += dtfm*f[i][0];
v[i][1] += dtfm*f[i][1];
v[i][2] += dtfm*f[i][2];
}
}
} else {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtfm = dtf / mass[type[i]];
v[i][0] += dtfm*f[i][0];
v[i][1] += dtfm*f[i][1];
v[i][2] += dtfm*f[i][2];
}
}
}
}
}
/* ----------------------------------------------------------------------
pack entire state of Fix into one write
------------------------------------------------------------------------- */
void FixNVT::write_restart(FILE *fp)
{
int n = 0;
double list[4];
list[n++] = eta;
list[n++] = eta_dot;
list[n++] = eta2;
list[n++] = eta2_dot;
if (comm->me == 0) {
int size = n * sizeof(double);
fwrite(&size,sizeof(int),1,fp);
fwrite(list,sizeof(double),n,fp);
}
}
/* ----------------------------------------------------------------------
use state info from restart file to restart the Fix
------------------------------------------------------------------------- */
void FixNVT::restart(char *buf)
{
int n = 0;
double *list = (double *) buf;
eta = list[n++];
eta_dot = list[n++];
eta2 = list[n++];
eta2_dot = list[n++];
}
/* ---------------------------------------------------------------------- */
int FixNVT::modify_param(int narg, char **arg)
{
if (strcmp(arg[0],"temp") == 0) {
if (narg < 2) error->all("Illegal fix_modify command");
if (tflag) {
modify->delete_compute(id_temp);
tflag = 0;
}
delete [] id_temp;
int n = strlen(arg[1]) + 1;
id_temp = new char[n];
strcpy(id_temp,arg[1]);
int icompute = modify->find_compute(id_temp);
if (icompute < 0) error->all("Could not find fix_modify temperature ID");
temperature = modify->compute[icompute];
if (temperature->tempflag == 0)
error->all("Fix_modify temperature ID does not compute temperature");
if (temperature->igroup != igroup && comm->me == 0)
error->warning("Group for fix_modify temp != fix group");
return 2;
}
return 0;
}
/* ---------------------------------------------------------------------- */
void FixNVT::reset_target(double t_new)
{
t_start = t_stop = t_new;
}
/* ---------------------------------------------------------------------- */
void FixNVT::reset_dt()
{
dtv = update->dt;
dtf = 0.5 * update->dt * force->ftm2v;
dthalf = 0.5 * update->dt;
dt4 = 0.25 * update->dt;
dt8 = 0.125 * update->dt;
drag_factor = 1.0 - (update->dt * t_freq * drag);
}
/* ---------------------------------------------------------------------- */
double FixNVT::compute_scalar()
{
double ke = temperature->dof * force->boltz * t_target;
double energy = ke * (eta + 0.5*eta_dot*eta_dot/(t_freq*t_freq));
return energy;
}

View File

@ -20,42 +20,14 @@ FixStyle(nvt,FixNVT)
#ifndef LMP_FIX_NVT_H
#define LMP_FIX_NVT_H
#include "fix.h"
#include "fix_nh.h"
namespace LAMMPS_NS {
class FixNVT : public Fix {
class FixNVT : public FixNH {
public:
FixNVT(class LAMMPS *, int, char **);
virtual ~FixNVT();
int setmask();
virtual void init();
void setup(int);
virtual void initial_integrate(int);
virtual void final_integrate();
virtual void initial_integrate_respa(int, int, int);
void final_integrate_respa(int, int);
double compute_scalar();
void write_restart(FILE *);
void restart(char *);
int modify_param(int, char **);
void reset_target(double);
void reset_dt();
protected:
int which,chain;
double t_start,t_stop;
double t_current,t_target;
double t_freq,drag,drag_factor;
double f_eta,eta_dot,eta,eta2_dot,eta2,factor,factor2;
double dtv,dtf,dthalf,dt4,dt8;
int nlevels_respa;
double *step_respa;
char *id_temp;
class Compute *temperature;
int tflag;
~FixNVT() {}
};
}

View File

@ -1,7 +1,7 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
www.cs.sandia.gov/~sjplimp/lammps.html
Steve Plimpton, sjplimp@sandia.gov, Sandia National Laboratories
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
@ -16,16 +16,11 @@
------------------------------------------------------------------------- */
#include "math.h"
#include "string.h"
#include "stdlib.h"
#include "fix_nvt_sllod.h"
#include "math_extra.h"
#include "fix_nvt_sllod.h"
#include "atom.h"
#include "force.h"
#include "domain.h"
#include "group.h"
#include "update.h"
#include "respa.h"
#include "modify.h"
#include "fix.h"
#include "fix_deform.h"
@ -35,17 +30,41 @@
using namespace LAMMPS_NS;
enum{NO_REMAP,X_REMAP,V_REMAP}; // same as fix_deform.cpp
enum{NOBIAS,BIAS};
/* ---------------------------------------------------------------------- */
FixNVTSlodd::FixNVTSlodd(LAMMPS *lmp, int narg, char **arg) :
FixNVT(lmp, narg, arg) {}
/* ---------------------------------------------------------------------- */
void FixNVTSlodd::init()
FixNVTSllod::FixNVTSllod(LAMMPS *lmp, int narg, char **arg) :
FixNH(lmp, narg, arg)
{
FixNVT::init();
if (!tstat_flag)
error->all("Temperature control must be used with fix nvt/sllod");
if (pstat_flag)
error->all("Pressure control can not be used with fix nvt/sllod");
// create a new compute temp style
// id = fix-ID + temp
int n = strlen(id) + 6;
id_temp = new char[n];
strcpy(id_temp,id);
strcat(id_temp,"_temp");
char **newarg = new char*[3];
newarg[0] = id_temp;
newarg[1] = group->names[igroup];
newarg[2] = (char *) "temp/deform";
modify->add_compute(3,newarg);
delete [] newarg;
tflag = 1;
}
/* ---------------------------------------------------------------------- */
void FixNVTSllod::init()
{
FixNH::init();
if (!temperature->tempbias)
error->all("Temperature for fix nvt/sllod does not have a bias");
@ -67,25 +86,12 @@ void FixNVTSlodd::init()
error->all("Using fix nvt/sllod with no fix deform defined");
}
/* ---------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
perform half-step scaling of velocities
-----------------------------------------------------------------------*/
void FixNVTSlodd::initial_integrate(int vflag)
void FixNVTSllod::nh_v_temp()
{
double dtfm;
double delta = update->ntimestep - update->firststep;
delta /= update->nsteps;
t_target = t_start + delta * (t_stop-t_start);
// update eta_dot
f_eta = t_freq*t_freq * (t_current/t_target - 1.0);
eta_dot += f_eta*dthalf;
eta_dot *= drag_factor;
eta += dtv*eta_dot;
factor = exp(-dthalf*eta_dot);
// update v and x of atoms in group
// remove and restore bias = streaming velocity = Hrate*lamda + Hratelo
// thermostat thermal velocity only
// vdelu = SLLOD correction = Hrate*Hinv*vthermal
@ -95,11 +101,7 @@ void FixNVTSlodd::initial_integrate(int vflag)
if (nondeformbias) double tmp = temperature->compute_scalar();
double **x = atom->x;
double **v = atom->v;
double **f = atom->f;
double *mass = atom->mass;
int *type = atom->type;
int *mask = atom->mask;
int nlocal = atom->nlocal;
if (igroup == atom->firstgroup) nlocal = atom->nfirst;
@ -113,144 +115,10 @@ void FixNVTSlodd::initial_integrate(int vflag)
vdelu[0] = h_two[0]*v[i][0] + h_two[5]*v[i][1] + h_two[4]*v[i][2];
vdelu[1] = h_two[1]*v[i][1] + h_two[3]*v[i][2];
vdelu[2] = h_two[2]*v[i][2];
dtfm = dtf / mass[type[i]];
v[i][0] = v[i][0]*factor + dtfm*f[i][0] - dthalf*vdelu[0];
v[i][1] = v[i][1]*factor + dtfm*f[i][1] - dthalf*vdelu[1];
v[i][2] = v[i][2]*factor + dtfm*f[i][2] - dthalf*vdelu[2];
temperature->restore_bias(i,v[i]);
x[i][0] += dtv * v[i][0];
x[i][1] += dtv * v[i][1];
x[i][2] += dtv * v[i][2];
}
}
}
/* ---------------------------------------------------------------------- */
void FixNVTSlodd::final_integrate()
{
double dtfm;
// update v of atoms in group
// remove and restore bias = streaming velocity = Hrate*lamda + Hratelo
// thermostat thermal velocity only
// vdelu = SLLOD correction = Hrate*Hinv*vthermal
// for non temp/deform BIAS:
// calculate temperature since some computes require temp
// computed on current nlocal atoms to remove bias
// OK to not test returned v = 0, since factor is multiplied by v
if (nondeformbias) double tmp = temperature->compute_scalar();
double **v = atom->v;
double **f = atom->f;
double *mass = atom->mass;
int *type = atom->type;
int *mask = atom->mask;
int nlocal = atom->nlocal;
if (igroup == atom->firstgroup) nlocal = atom->nfirst;
double h_two[6],vdelu[3];
MathExtra::multiply_shape_shape(domain->h_rate,domain->h_inv,h_two);
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
temperature->remove_bias(i,v[i]);
vdelu[0] = h_two[0]*v[i][0] + h_two[5]*v[i][1] + h_two[4]*v[i][2];
vdelu[1] = h_two[1]*v[i][1] + h_two[3]*v[i][2];
vdelu[2] = h_two[2]*v[i][2];
//dtfm = dtf / mass[type[i]] * factor;
dtfm = dtf / mass[type[i]];
v[i][0] = v[i][0]*factor + dtfm*f[i][0] - dthalf*vdelu[0];
v[i][1] = v[i][1]*factor + dtfm*f[i][1] - dthalf*vdelu[1];
v[i][2] = v[i][2]*factor + dtfm*f[i][2] - dthalf*vdelu[2];
v[i][0] = v[i][0]*factor_eta - dthalf*vdelu[0];
v[i][1] = v[i][1]*factor_eta - dthalf*vdelu[1];
v[i][2] = v[i][2]*factor_eta - dthalf*vdelu[2];
temperature->restore_bias(i,v[i]);
}
}
// compute current T
t_current = temperature->compute_scalar();
// update eta_dot
f_eta = t_freq*t_freq * (t_current/t_target - 1.0);
eta_dot += f_eta*dthalf;
eta_dot *= drag_factor;
}
/* ---------------------------------------------------------------------- */
void FixNVTSlodd::initial_integrate_respa(int vflag, int ilevel, int flag)
{
if (flag) return; // only used by NPT,NPH
// set timesteps by level
double dtfm;
dtv = step_respa[ilevel];
dtf = 0.5 * step_respa[ilevel] * force->ftm2v;
dthalf = 0.5 * step_respa[ilevel];
// atom quantities
double **x = atom->x;
double **v = atom->v;
double **f = atom->f;
double *mass = atom->mass;
int *type = atom->type;
int *mask = atom->mask;
int nlocal = atom->nlocal;
if (igroup == atom->firstgroup) nlocal = atom->nfirst;
// outermost level - update eta_dot and apply to v
// all other levels - NVE update of v
if (ilevel == nlevels_respa-1) {
double delta = update->ntimestep - update->firststep;
delta /= update->nsteps;
t_target = t_start + delta * (t_stop-t_start);
// update eta_dot
f_eta = t_freq*t_freq * (t_current/t_target - 1.0);
eta_dot += f_eta*dthalf;
eta_dot *= drag_factor;
eta += dtv*eta_dot;
factor = exp(-dthalf*eta_dot);
} else factor = 1.0;
// update v of atoms in group
if (nondeformbias) double tmp = temperature->compute_scalar();
double h_two[6],vdelu[3];
MathExtra::multiply_shape_shape(domain->h_rate,domain->h_inv,h_two);
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
temperature->remove_bias(i,v[i]);
vdelu[0] = h_two[0]*v[i][0] + h_two[5]*v[i][1] + h_two[4]*v[i][2];
vdelu[1] = h_two[1]*v[i][1] + h_two[3]*v[i][2];
vdelu[2] = h_two[2]*v[i][2];
dtfm = dtf / mass[type[i]];
v[i][0] = v[i][0]*factor + dtfm*f[i][0] - dthalf*vdelu[0];
v[i][1] = v[i][1]*factor + dtfm*f[i][1] - dthalf*vdelu[1];
v[i][2] = v[i][2]*factor + dtfm*f[i][2] - dthalf*vdelu[2];
temperature->restore_bias(i,v[i]);
}
}
// innermost level - also update x of only atoms in group
if (ilevel == 0) {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
x[i][0] += dtv * v[i][0];
x[i][1] += dtv * v[i][1];
x[i][2] += dtv * v[i][2];
}
}
}
}

View File

@ -1,7 +1,7 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
www.cs.sandia.gov/~sjplimp/lammps.html
Steve Plimpton, sjplimp@sandia.gov, Sandia National Laboratories
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
@ -13,27 +13,27 @@
#ifdef FIX_CLASS
FixStyle(nvt/sllod,FixNVTSlodd)
FixStyle(nvt/sllod,FixNVTSllod)
#else
#ifndef LMP_FIX_NVT_SLODD_H
#define LMP_FIX_NVT_SLODD_H
#ifndef LMP_FIX_NVT_SLLOD_H
#define LMP_FIX_NVT_SLLOD_H
#include "fix_nvt.h"
#include "fix_nh.h"
namespace LAMMPS_NS {
class FixNVTSlodd : public FixNVT {
class FixNVTSllod : public FixNH {
public:
FixNVTSlodd(class LAMMPS *, int, char **);
FixNVTSllod(class LAMMPS *, int, char **);
~FixNVTSllod() {}
void init();
void initial_integrate(int);
void final_integrate();
void initial_integrate_respa(int, int, int);
private:
int nondeformbias;
void nh_v_temp();
};
}

View File

@ -12,489 +12,37 @@
------------------------------------------------------------------------- */
#include "string.h"
#include "stdlib.h"
#include "math.h"
#include "fix_nvt_sphere.h"
#include "atom.h"
#include "atom_vec.h"
#include "force.h"
#include "comm.h"
#include "group.h"
#include "update.h"
#include "modify.h"
#include "compute.h"
#include "error.h"
using namespace LAMMPS_NS;
#define INERTIA 0.4 // moment of inertia for sphere
enum{NOBIAS,BIAS};
/* ---------------------------------------------------------------------- */
FixNVTSphere::FixNVTSphere(LAMMPS *lmp, int narg, char **arg) :
FixNVT(lmp, narg, arg)
FixNHSphere(lmp, narg, arg)
{
// error checks
if (!tstat_flag)
error->all("Temperature control must be used with fix nvt/sphere");
if (pstat_flag)
error->all("Pressure control can not be used with fix nvt/sphere");
if (!atom->omega_flag || !atom->torque_flag)
error->all("Fix nvt/sphere requires atom attributes omega, torque");
if (!atom->radius_flag && !atom->avec->shape_type)
error->all("Fix nvt/sphere requires atom attribute radius or shape");
}
/* ---------------------------------------------------------------------- */
void FixNVTSphere::init()
{
int i,itype;
// check that all particles are finite-size and spherical
// no point particles allowed
if (atom->radius_flag) {
double *radius = atom->radius;
int *mask = atom->mask;
int nlocal = atom->nlocal;
if (igroup == atom->firstgroup) nlocal = atom->nfirst;
for (i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
if (radius[i] == 0.0)
error->one("Fix nvt/sphere requires extended particles");
}
} else {
double **shape = atom->shape;
int *type = atom->type;
int *mask = atom->mask;
int nlocal = atom->nlocal;
if (igroup == atom->firstgroup) nlocal = atom->nfirst;
for (i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
itype = type[i];
if (shape[itype][0] == 0.0)
error->one("Fix nvt/sphere requires extended particles");
if (shape[itype][0] != shape[itype][1] ||
shape[itype][0] != shape[itype][2])
error->one("Fix nvt/sphere requires spherical particle shapes");
}
}
FixNVT::init();
}
/* ---------------------------------------------------------------------- */
void FixNVTSphere::initial_integrate(int vflag)
{
int itype;
double dtfm,dtirotate;
double delta = update->ntimestep - update->beginstep;
delta /= update->endstep - update->beginstep;
t_target = t_start + delta * (t_stop-t_start);
// update eta_dot
f_eta = t_freq*t_freq * (t_current/t_target - 1.0);
eta_dot += f_eta*dthalf;
eta_dot *= drag_factor;
eta += dtv*eta_dot;
factor = exp(-dthalf*eta_dot);
// update v and x of only atoms in group
double **x = atom->x;
double **v = atom->v;
double **f = atom->f;
double **omega = atom->omega;
double **torque = atom->torque;
double *radius = atom->radius;
double *rmass = atom->rmass;
double *mass = atom->mass;
double **shape = atom->shape;
int *type = atom->type;
int *mask = atom->mask;
int nlocal = atom->nlocal;
if (igroup == atom->firstgroup) nlocal = atom->nfirst;
// set timestep here since dt may have changed or come via rRESPA
double dtfrotate = dtf / INERTIA;
// update v,x,omega of atoms in group
// d_omega/dt = torque / inertia
// 8 cases depending on radius vs shape, rmass vs mass, bias vs nobias
// for BIAS:
// calculate temperature since some computes require temp
// computed on current nlocal atoms to remove bias
// OK to not test returned v = 0, since factor is multiplied by v
if (radius) {
if (rmass) {
if (which == NOBIAS) {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtfm = dtf / rmass[i];
v[i][0] = v[i][0]*factor + dtfm*f[i][0];
v[i][1] = v[i][1]*factor + dtfm*f[i][1];
v[i][2] = v[i][2]*factor + dtfm*f[i][2];
x[i][0] += dtv * v[i][0];
x[i][1] += dtv * v[i][1];
x[i][2] += dtv * v[i][2];
dtirotate = dtfrotate / (radius[i]*radius[i]*rmass[i]);
omega[i][0] = omega[i][0]*factor + dtirotate*torque[i][0];
omega[i][1] = omega[i][1]*factor + dtirotate*torque[i][1];
omega[i][2] = omega[i][2]*factor + dtirotate*torque[i][2];
}
}
} else {
double tmp = temperature->compute_scalar();
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
temperature->remove_bias(i,v[i]);
dtfm = dtf / rmass[i];
v[i][0] = v[i][0]*factor + dtfm*f[i][0];
v[i][1] = v[i][1]*factor + dtfm*f[i][1];
v[i][2] = v[i][2]*factor + dtfm*f[i][2];
temperature->restore_bias(i,v[i]);
x[i][0] += dtv * v[i][0];
x[i][1] += dtv * v[i][1];
x[i][2] += dtv * v[i][2];
dtirotate = dtfrotate / (radius[i]*radius[i]*rmass[i]);
omega[i][0] = omega[i][0]*factor + dtirotate*torque[i][0];
omega[i][1] = omega[i][1]*factor + dtirotate*torque[i][1];
omega[i][2] = omega[i][2]*factor + dtirotate*torque[i][2];
}
}
}
} else {
if (which == NOBIAS) {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
itype = type[i];
dtfm = dtf / mass[itype];
v[i][0] = v[i][0]*factor + dtfm*f[i][0];
v[i][1] = v[i][1]*factor + dtfm*f[i][1];
v[i][2] = v[i][2]*factor + dtfm*f[i][2];
x[i][0] += dtv * v[i][0];
x[i][1] += dtv * v[i][1];
x[i][2] += dtv * v[i][2];
dtirotate = dtfrotate / (radius[i]*radius[i]*mass[itype]);
omega[i][0] = omega[i][0]*factor + dtirotate*torque[i][0];
omega[i][1] = omega[i][1]*factor + dtirotate*torque[i][1];
omega[i][2] = omega[i][2]*factor + dtirotate*torque[i][2];
}
}
} else {
double tmp = temperature->compute_scalar();
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
itype = type[i];
temperature->remove_bias(i,v[i]);
dtfm = dtf / mass[itype];
v[i][0] = v[i][0]*factor + dtfm*f[i][0];
v[i][1] = v[i][1]*factor + dtfm*f[i][1];
v[i][2] = v[i][2]*factor + dtfm*f[i][2];
temperature->restore_bias(i,v[i]);
x[i][0] += dtv * v[i][0];
x[i][1] += dtv * v[i][1];
x[i][2] += dtv * v[i][2];
dtirotate = dtfrotate / (radius[i]*radius[i]*mass[itype]);
omega[i][0] = omega[i][0]*factor + dtirotate*torque[i][0];
omega[i][1] = omega[i][1]*factor + dtirotate*torque[i][1];
omega[i][2] = omega[i][2]*factor + dtirotate*torque[i][2];
}
}
}
}
} else {
if (rmass) {
if (which == NOBIAS) {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
itype = type[i];
dtfm = dtf / rmass[i];
v[i][0] = v[i][0]*factor + dtfm*f[i][0];
v[i][1] = v[i][1]*factor + dtfm*f[i][1];
v[i][2] = v[i][2]*factor + dtfm*f[i][2];
x[i][0] += dtv * v[i][0];
x[i][1] += dtv * v[i][1];
x[i][2] += dtv * v[i][2];
dtirotate = dtfrotate / (shape[itype][0]*shape[itype][0]*rmass[i]);
omega[i][0] = omega[i][0]*factor + dtirotate*torque[i][0];
omega[i][1] = omega[i][1]*factor + dtirotate*torque[i][1];
omega[i][2] = omega[i][2]*factor + dtirotate*torque[i][2];
}
}
} else {
double tmp = temperature->compute_scalar();
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
itype = type[i];
temperature->remove_bias(i,v[i]);
dtfm = dtf / rmass[i];
v[i][0] = v[i][0]*factor + dtfm*f[i][0];
v[i][1] = v[i][1]*factor + dtfm*f[i][1];
v[i][2] = v[i][2]*factor + dtfm*f[i][2];
temperature->restore_bias(i,v[i]);
x[i][0] += dtv * v[i][0];
x[i][1] += dtv * v[i][1];
x[i][2] += dtv * v[i][2];
dtirotate = dtfrotate / (shape[itype][0]*shape[itype][0]*rmass[i]);
omega[i][0] = omega[i][0]*factor + dtirotate*torque[i][0];
omega[i][1] = omega[i][1]*factor + dtirotate*torque[i][1];
omega[i][2] = omega[i][2]*factor + dtirotate*torque[i][2];
}
}
}
} else {
if (which == NOBIAS) {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
itype = type[i];
dtfm = dtf / mass[itype];
v[i][0] = v[i][0]*factor + dtfm*f[i][0];
v[i][1] = v[i][1]*factor + dtfm*f[i][1];
v[i][2] = v[i][2]*factor + dtfm*f[i][2];
x[i][0] += dtv * v[i][0];
x[i][1] += dtv * v[i][1];
x[i][2] += dtv * v[i][2];
dtirotate = dtfrotate /
(shape[itype][0]*shape[itype][0]*mass[itype]);
omega[i][0] = omega[i][0]*factor + dtirotate*torque[i][0];
omega[i][1] = omega[i][1]*factor + dtirotate*torque[i][1];
omega[i][2] = omega[i][2]*factor + dtirotate*torque[i][2];
}
}
} else {
double tmp = temperature->compute_scalar();
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
itype = type[i];
temperature->remove_bias(i,v[i]);
dtfm = dtf / mass[itype];
v[i][0] = v[i][0]*factor + dtfm*f[i][0];
v[i][1] = v[i][1]*factor + dtfm*f[i][1];
v[i][2] = v[i][2]*factor + dtfm*f[i][2];
temperature->restore_bias(i,v[i]);
x[i][0] += dtv * v[i][0];
x[i][1] += dtv * v[i][1];
x[i][2] += dtv * v[i][2];
dtirotate = dtfrotate /
(shape[itype][0]*shape[itype][0]*mass[itype]);
omega[i][0] = omega[i][0]*factor + dtirotate*torque[i][0];
omega[i][1] = omega[i][1]*factor + dtirotate*torque[i][1];
omega[i][2] = omega[i][2]*factor + dtirotate*torque[i][2];
}
}
}
}
}
}
/* ---------------------------------------------------------------------- */
void FixNVTSphere::final_integrate()
{
int itype;
double dtfm,dtirotate;
// update v,omega of atoms in group
// d_omega/dt = torque / inertia
// 8 cases depending on radius vs shape, rmass vs mass, bias vs nobias
// for BIAS:
// calculate temperature since some computes require temp
// computed on current nlocal atoms to remove bias
// OK to not test returned v = 0, since factor is multiplied by v
double **v = atom->v;
double **f = atom->f;
double **omega = atom->omega;
double **torque = atom->torque;
double *radius = atom->radius;
double *rmass = atom->rmass;
double *mass = atom->mass;
double **shape = atom->shape;
int *type = atom->type;
int *mask = atom->mask;
int nlocal = atom->nlocal;
if (igroup == atom->firstgroup) nlocal = atom->nfirst;
// set timestep here since dt may have changed or come via rRESPA
double dtfrotate = dtf / INERTIA;
if (radius) {
if (rmass) {
if (which == NOBIAS) {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtfm = dtf / rmass[i] * factor;
v[i][0] = v[i][0]*factor + dtfm*f[i][0];
v[i][1] = v[i][1]*factor + dtfm*f[i][1];
v[i][2] = v[i][2]*factor + dtfm*f[i][2];
dtirotate = dtfrotate / (radius[i]*radius[i]*rmass[i]);
omega[i][0] = (omega[i][0] + dtirotate*torque[i][0]) * factor;
omega[i][1] = (omega[i][1] + dtirotate*torque[i][1]) * factor;
omega[i][2] = (omega[i][2] + dtirotate*torque[i][2]) * factor;
}
}
} else {
double tmp = temperature->compute_scalar();
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
temperature->remove_bias(i,v[i]);
dtfm = dtf / rmass[i] * factor;
v[i][0] = v[i][0]*factor + dtfm*f[i][0];
v[i][1] = v[i][1]*factor + dtfm*f[i][1];
v[i][2] = v[i][2]*factor + dtfm*f[i][2];
temperature->restore_bias(i,v[i]);
dtirotate = dtfrotate / (radius[i]*radius[i]*rmass[i]);
omega[i][0] = (omega[i][0] + dtirotate*torque[i][0]) * factor;
omega[i][1] = (omega[i][1] + dtirotate*torque[i][1]) * factor;
omega[i][2] = (omega[i][2] + dtirotate*torque[i][2]) * factor;
}
}
}
} else {
if (which == NOBIAS) {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
itype = type[i];
dtfm = dtf / mass[itype] * factor;
v[i][0] = v[i][0]*factor + dtfm*f[i][0];
v[i][1] = v[i][1]*factor + dtfm*f[i][1];
v[i][2] = v[i][2]*factor + dtfm*f[i][2];
dtirotate = dtfrotate / (radius[i]*radius[i]*mass[itype]);
omega[i][0] = (omega[i][0] + dtirotate*torque[i][0]) * factor;
omega[i][1] = (omega[i][1] + dtirotate*torque[i][1]) * factor;
omega[i][2] = (omega[i][2] + dtirotate*torque[i][2]) * factor;
}
}
} else {
double tmp = temperature->compute_scalar();
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
itype = type[i];
temperature->remove_bias(i,v[i]);
dtfm = dtf / mass[itype] * factor;
v[i][0] = v[i][0]*factor + dtfm*f[i][0];
v[i][1] = v[i][1]*factor + dtfm*f[i][1];
v[i][2] = v[i][2]*factor + dtfm*f[i][2];
temperature->restore_bias(i,v[i]);
dtirotate = dtfrotate / (radius[i]*radius[i]*mass[itype]);
omega[i][0] = (omega[i][0] + dtirotate*torque[i][0]) * factor;
omega[i][1] = (omega[i][1] + dtirotate*torque[i][1]) * factor;
omega[i][2] = (omega[i][2] + dtirotate*torque[i][2]) * factor;
}
}
}
}
} else {
if (rmass) {
if (which == NOBIAS) {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
itype = type[i];
dtfm = dtf / rmass[i] * factor;
v[i][0] = v[i][0]*factor + dtfm*f[i][0];
v[i][1] = v[i][1]*factor + dtfm*f[i][1];
v[i][2] = v[i][2]*factor + dtfm*f[i][2];
dtirotate = dtfrotate / (shape[itype][0]*shape[itype][0]*rmass[i]);
omega[i][0] = (omega[i][0] + dtirotate*torque[i][0]) * factor;
omega[i][1] = (omega[i][1] + dtirotate*torque[i][1]) * factor;
omega[i][2] = (omega[i][2] + dtirotate*torque[i][2]) * factor;
}
}
} else {
double tmp = temperature->compute_scalar();
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
itype = type[i];
temperature->remove_bias(i,v[i]);
dtfm = dtf / rmass[i] * factor;
v[i][0] = v[i][0]*factor + dtfm*f[i][0];
v[i][1] = v[i][1]*factor + dtfm*f[i][1];
v[i][2] = v[i][2]*factor + dtfm*f[i][2];
temperature->restore_bias(i,v[i]);
dtirotate = dtfrotate / (shape[itype][0]*shape[itype][0]*rmass[i]);
omega[i][0] = (omega[i][0] + dtirotate*torque[i][0]) * factor;
omega[i][1] = (omega[i][1] + dtirotate*torque[i][1]) * factor;
omega[i][2] = (omega[i][2] + dtirotate*torque[i][2]) * factor;
}
}
}
} else {
if (which == NOBIAS) {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
itype = type[i];
dtfm = dtf / mass[itype] * factor;
v[i][0] = v[i][0]*factor + dtfm*f[i][0];
v[i][1] = v[i][1]*factor + dtfm*f[i][1];
v[i][2] = v[i][2]*factor + dtfm*f[i][2];
dtirotate = dtfrotate /
(shape[itype][0]*shape[itype][0]*mass[itype]);
omega[i][0] = (omega[i][0] + dtirotate*torque[i][0]) * factor;
omega[i][1] = (omega[i][1] + dtirotate*torque[i][1]) * factor;
omega[i][2] = (omega[i][2] + dtirotate*torque[i][2]) * factor;
}
}
} else {
double tmp = temperature->compute_scalar();
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
itype = type[i];
temperature->remove_bias(i,v[i]);
dtfm = dtf / mass[itype] * factor;
v[i][0] = v[i][0]*factor + dtfm*f[i][0];
v[i][1] = v[i][1]*factor + dtfm*f[i][1];
v[i][2] = v[i][2]*factor + dtfm*f[i][2];
temperature->restore_bias(i,v[i]);
dtirotate = dtfrotate /
(shape[itype][0]*shape[itype][0]*mass[itype]);
omega[i][0] = (omega[i][0] + dtirotate*torque[i][0]) * factor;
omega[i][1] = (omega[i][1] + dtirotate*torque[i][1]) * factor;
omega[i][2] = (omega[i][2] + dtirotate*torque[i][2]) * factor;
}
}
}
}
}
// compute current T
t_current = temperature->compute_scalar();
// update eta_dot
f_eta = t_freq*t_freq * (t_current/t_target - 1.0);
eta_dot += f_eta*dthalf;
eta_dot *= drag_factor;
// create a new compute temp style
// id = fix-ID + temp
int n = strlen(id) + 6;
id_temp = new char[n];
strcpy(id_temp,id);
strcat(id_temp,"_temp");
char **newarg = new char*[3];
newarg[0] = id_temp;
newarg[1] = group->names[igroup];
newarg[2] = (char *) "temp/sphere";
modify->add_compute(3,newarg);
delete [] newarg;
tflag = 1;
}

View File

@ -20,17 +20,14 @@ FixStyle(nvt/sphere,FixNVTSphere)
#ifndef LMP_FIX_NVT_SPHERE_H
#define LMP_FIX_NVT_SPHERE_H
#include "fix_nvt.h"
#include "fix_nh_sphere.h"
namespace LAMMPS_NS {
class FixNVTSphere : public FixNVT {
class FixNVTSphere : public FixNHSphere {
public:
FixNVTSphere(class LAMMPS *, int, char **);
~FixNVTSphere() {}
void init();
void initial_integrate(int);
void final_integrate();
};
}

View File

@ -33,7 +33,8 @@ using namespace LAMMPS_NS;
#define MAX(A,B) ((A) > (B)) ? (A) : (B)
enum{NOBIAS,BIAS};
enum{XYZ,XY,YZ,XZ,ANISO};
enum{NONE,XYZ,XY,YZ,XZ};
enum{ISO,ANISO};
/* ---------------------------------------------------------------------- */
@ -44,80 +45,89 @@ FixPressBerendsen::FixPressBerendsen(LAMMPS *lmp, int narg, char **arg) :
box_change = 1;
// Berendsen barostat should be applied every step
// Berendsen barostat applied every step
nevery = 1;
if (strcmp(arg[3],"xyz") == 0) {
if (narg < 7) error->all("Illegal fix press/berendsen command");
press_couple = XYZ;
p_start[0] = p_start[1] = p_start[2] = atof(arg[4]);
p_stop[0] = p_stop[1] = p_stop[2] = atof(arg[5]);
p_period[0] = p_period[1] = p_period[2] = atof(arg[6]);
p_flag[0] = p_flag[1] = p_flag[2] = 1;
if (domain->dimension == 2) {
p_start[2] = p_stop[2] = p_period[2] = 0.0;
p_flag[2] = 0;
}
} else {
if (strcmp(arg[3],"xy") == 0) press_couple = XY;
else if (strcmp(arg[3],"yz") == 0) press_couple = YZ;
else if (strcmp(arg[3],"xz") == 0) press_couple = XZ;
else if (strcmp(arg[3],"aniso") == 0) press_couple = ANISO;
else error->all("Illegal fix press/berendsen command");
if (narg < 8) error->all("Illegal fix press/berendsen command");
if (domain->dimension == 2 &&
(press_couple == XY || press_couple == YZ || press_couple == XZ))
error->all("Invalid fix press/berendsen command for a 2d simulation");
if (strcmp(arg[4],"NULL") == 0) {
p_start[0] = p_stop[0] = p_period[0] = 0.0;
p_flag[0] = 0;
} else {
p_start[0] = atof(arg[4]);
p_stop[0] = atof(arg[5]);
p_flag[0] = 1;
}
if (strcmp(arg[6],"NULL") == 0) {
p_start[1] = p_stop[1] = p_period[1] = 0.0;
p_flag[1] = 0;
} else {
p_start[1] = atof(arg[6]);
p_stop[1] = atof(arg[7]);
p_flag[1] = 1;
}
if (strcmp(arg[8],"NULL") == 0) {
p_start[2] = p_stop[2] = p_period[2] = 0.0;
p_flag[2] = 0;
} else {
if (domain->dimension == 2)
error->all("Invalid fix press/berendsen command for a 2d simulation");
p_start[2] = atof(arg[8]);
p_stop[2] = atof(arg[9]);
p_flag[2] = 1;
}
double period = atof(arg[10]);
if (p_flag[0]) p_period[0] = period;
if (p_flag[1]) p_period[1] = period;
if (p_flag[2]) p_period[2] = period;
}
// process extra keywords
// default values
pcouple = NONE;
bulkmodulus = 10.0;
allremap = 1;
int iarg;
if (press_couple == XYZ) iarg = 7;
else iarg = 11;
for (int i = 0; i < 3; i++) {
p_start[i] = p_stop[i] = p_period[i] = 0.0;
p_flag[i] = 0;
p_period[i] = 0.0;
}
// process keywords
dimension = domain->dimension;
int iarg = 3;
while (iarg < narg) {
if (strcmp(arg[iarg],"modulus") == 0) {
if (strcmp(arg[iarg],"iso") == 0) {
if (iarg+4 > narg) error->all("Illegal fix press/berendsen command");
pcouple = XYZ;
p_start[0] = p_start[1] = p_start[2] = atof(arg[iarg+1]);
p_stop[0] = p_stop[1] = p_stop[2] = atof(arg[iarg+2]);
p_period[0] = p_period[1] = p_period[2] = atof(arg[iarg+3]);
p_flag[0] = p_flag[1] = p_flag[2] = 1;
if (dimension == 2) {
p_start[2] = p_stop[2] = p_period[2] = 0.0;
p_flag[2] = 0;
}
iarg += 4;
} else if (strcmp(arg[iarg],"aniso") == 0) {
if (iarg+4 > narg) error->all("Illegal fix press/berendsen command");
pcouple = NONE;
p_start[0] = p_start[1] = p_start[2] = atof(arg[iarg+1]);
p_stop[0] = p_stop[1] = p_stop[2] = atof(arg[iarg+2]);
p_period[0] = p_period[1] = p_period[2] = atof(arg[iarg+3]);
p_flag[0] = p_flag[1] = p_flag[2] = 1;
if (dimension == 2) {
p_start[2] = p_stop[2] = p_period[2] = 0.0;
p_flag[2] = 0;
}
iarg += 4;
} else if (strcmp(arg[iarg],"x") == 0) {
if (iarg+4 > narg) error->all("Illegal fix press/berendsen command");
p_start[0] = atof(arg[iarg+1]);
p_stop[0] = atof(arg[iarg+2]);
p_period[0] = atof(arg[iarg+3]);
p_flag[0] = 1;
iarg += 4;
} else if (strcmp(arg[iarg],"y") == 0) {
if (iarg+4 > narg) error->all("Illegal fix press/berendsen command");
p_start[1] = atof(arg[iarg+1]);
p_stop[1] = atof(arg[iarg+2]);
p_period[1] = atof(arg[iarg+3]);
p_flag[1] = 1;
iarg += 4;
} else if (strcmp(arg[iarg],"z") == 0) {
if (iarg+4 > narg) error->all("Illegal fix press/berendsen command");
p_start[2] = atof(arg[iarg+1]);
p_stop[2] = atof(arg[iarg+2]);
p_period[2] = atof(arg[iarg+3]);
p_flag[2] = 1;
iarg += 4;
if (dimension == 2)
error->all("Invalid fix press/berendsen command for a 2d simulation");
} else if (strcmp(arg[iarg],"couple") == 0) {
if (iarg+2 > narg) error->all("Illegal fix press/berendsen command");
if (strcmp(arg[iarg+1],"xyz") == 0) pcouple = XYZ;
else if (strcmp(arg[iarg+1],"xy") == 0) pcouple = XY;
else if (strcmp(arg[iarg+1],"yz") == 0) pcouple = YZ;
else if (strcmp(arg[iarg+1],"xz") == 0) pcouple = XZ;
else if (strcmp(arg[iarg+1],"none") == 0) pcouple = NONE;
else error->all("Illegal fix press/berendsen command");
iarg += 2;
} else if (strcmp(arg[iarg],"modulus") == 0) {
if (iarg+2 > narg) error->all("Illegal fix press/berendsen command");
bulkmodulus = atof(arg[iarg+1]);
if (bulkmodulus <= 0.0)
@ -134,21 +144,18 @@ FixPressBerendsen::FixPressBerendsen(LAMMPS *lmp, int narg, char **arg) :
// error checks
if (press_couple == XY && (p_flag[0] == 0 || p_flag[1] == 0))
error->all("Invalid fix press/berendsen command pressure settings");
if (press_couple == YZ && (p_flag[1] == 0 || p_flag[2] == 0))
error->all("Invalid fix press/berendsen command pressure settings");
if (press_couple == XZ && (p_flag[0] == 0 || p_flag[2] == 0))
error->all("Invalid fix press/berendsen command pressure settings");
if (dimension == 2 && p_flag[2])
error->all("Invalid fix press/berendsen command for a 2d simulation");
if (dimension == 2 && (pcouple == YZ || pcouple == XZ))
error->all("Invalid fix press/berendsen command for a 2d simulation");
if (press_couple == XY &&
(p_start[0] != p_start[1] || p_stop[0] != p_stop[1]))
if (pcouple == XYZ && (p_flag[0] == 0 || p_flag[1] == 0 || p_flag[2] == 0))
error->all("Invalid fix press/berendsen command pressure settings");
if (press_couple == YZ &&
(p_start[1] != p_start[2] || p_stop[1] != p_stop[2]))
if (pcouple == XY && (p_flag[0] == 0 || p_flag[1] == 0))
error->all("Invalid fix press/berendsen command pressure settings");
if (press_couple == XZ &&
(p_start[0] != p_start[2] || p_stop[0] != p_stop[2]))
if (pcouple == YZ && (p_flag[1] == 0 || p_flag[2] == 0))
error->all("Invalid fix press/berendsen command pressure settings");
if (pcouple == XZ && (p_flag[0] == 0 || p_flag[2] == 0))
error->all("Invalid fix press/berendsen command pressure settings");
if (p_flag[0] && domain->xperiodic == 0)
@ -158,12 +165,34 @@ FixPressBerendsen::FixPressBerendsen(LAMMPS *lmp, int narg, char **arg) :
if (p_flag[2] && domain->zperiodic == 0)
error->all("Cannot use fix press/berendsen on a non-periodic dimension");
if (p_flag[0] && p_period[0] <= 0.0)
error->all("Fix press/berendsen period must be > 0.0");
if (p_flag[1] && p_period[1] <= 0.0)
error->all("Fix press/berendsen period must be > 0.0");
if (p_flag[2] && p_period[2] <= 0.0)
error->all("Fix press/berendsen period must be > 0.0");
if (pcouple == XYZ &&
(p_start[0] != p_start[1] || p_start[0] != p_start[2] ||
p_stop[0] != p_stop[1] || p_stop[0] != p_stop[2] ||
p_period[0] != p_period[1] || p_period[0] != p_period[2]))
error->all("Invalid fix press/berendsen pressure settings");
if (pcouple == XY &&
(p_start[0] != p_start[1] || p_stop[0] != p_stop[1] ||
p_period[0] != p_period[1]))
error->all("Invalid fix press/berendsen pressure settings");
if (pcouple == YZ &&
(p_start[1] != p_start[2] || p_stop[1] != p_stop[2] ||
p_period[1] != p_period[2]))
error->all("Invalid fix press/berendsen pressure settings");
if (pcouple == XZ &&
(p_start[0] != p_start[2] || p_stop[0] != p_stop[2] ||
p_period[0] != p_period[2]))
error->all("Invalid fix press/berendsen pressure settings");
if ((p_flag[0] && p_period[0] <= 0.0) ||
(p_flag[1] && p_period[1] <= 0.0) ||
(p_flag[2] && p_period[2] <= 0.0))
error->all("Fix press/berendsen damping parameters must be > 0.0");
// pstyle = ISO if XYZ coupling or XY coupling in 2d -> 1 dof
// else pstyle = ANISO -> 3 dof
if (pcouple == XYZ || (dimension == 2 && pcouple == XY)) pstyle = ISO;
else pstyle = ANISO;
// create a new compute temp style
// id = fix-ID + temp
@ -235,13 +264,15 @@ void FixPressBerendsen::init()
if (domain->triclinic)
error->all("Cannot use fix press/berendsen with triclinic box");
// insure no conflict with fix deform
for (int i = 0; i < modify->nfix; i++)
if (strcmp(modify->fix[i]->style,"deform") == 0) {
int *dimflag = ((FixDeform *) modify->fix[i])->dimflag;
if ((p_flag[0] && dimflag[0]) || (p_flag[1] && dimflag[1]) ||
(p_flag[2] && dimflag[2]))
error->all("Cannot use fix press/berendsen and "
"fix deform on same dimension");
"fix deform on same component of stress tensor");
}
// set temperature and pressure ptrs
@ -298,7 +329,7 @@ void FixPressBerendsen::end_of_step()
{
// compute new T,P
if (press_couple == XYZ) {
if (pstyle == ISO) {
double tmp = temperature->compute_scalar();
tmp = pressure->compute_scalar();
} else {
@ -336,21 +367,24 @@ void FixPressBerendsen::couple()
{
double *tensor = pressure->vector;
if (press_couple == XYZ)
if (pstyle == ISO)
p_current[0] = p_current[1] = p_current[2] = pressure->scalar;
else if (press_couple == XY) {
else if (pcouple == XYZ) {
double ave = 1.0/3.0 * (tensor[0] + tensor[1] + tensor[2]);
p_current[0] = p_current[1] = p_current[2] = ave;
} else if (pcouple == XY) {
double ave = 0.5 * (tensor[0] + tensor[1]);
p_current[0] = p_current[1] = ave;
p_current[2] = tensor[2];
} else if (press_couple == YZ) {
} else if (pcouple == YZ) {
double ave = 0.5 * (tensor[1] + tensor[2]);
p_current[1] = p_current[2] = ave;
p_current[0] = tensor[0];
} else if (press_couple == XZ) {
} else if (pcouple == XZ) {
double ave = 0.5 * (tensor[0] + tensor[2]);
p_current[0] = p_current[2] = ave;
p_current[1] = tensor[1];
} if (press_couple == ANISO) {
} else {
p_current[0] = tensor[0];
p_current[1] = tensor[1];
p_current[2] = tensor[2];

View File

@ -38,7 +38,7 @@ class FixPressBerendsen : public Fix {
int dimension,which;
double bulkmodulus;
int press_couple,allremap;
int pstyle,pcouple,allremap;
int p_flag[3]; // 1 if control P on this dim, 0 if not
double p_start[3],p_stop[3];
double p_period[3],p_target[3];

View File

@ -44,6 +44,9 @@ namespace MathExtra {
inline void transpose_times3(const double mat1[3][3],
const double mat2[3][3],
double ans[3][3]);
inline void times3_transpose(const double mat1[3][3],
const double mat2[3][3],
double ans[3][3]);
inline void invert3(const double mat[3][3], double ans[3][3]);
inline void times_column3(const double mat[3][3], const double*vec,
double *ans);
@ -53,6 +56,7 @@ namespace MathExtra {
double ans[3][3]);
inline void row_times3(const double *v, const double m[3][3],
double *ans);
inline void scalar_times3(const double f, double m[3][3]);
inline void mldivide3(const double mat[3][3], const double *vec,
double *ans, LAMMPS_NS::Error *error);
inline void write3(const double mat[3][3]);
@ -209,6 +213,24 @@ void MathExtra::transpose_times3(const double m[3][3], const double m2[3][3],
ans[2][2] = m[0][2]*m2[0][2]+m[1][2]*m2[1][2]+m[2][2]*m2[2][2];
}
/* ----------------------------------------------------------------------
multiply mat1 times transpose of mat2
------------------------------------------------------------------------- */
void MathExtra::times3_transpose(const double m[3][3], const double m2[3][3],
double ans[3][3])
{
ans[0][0] = m[0][0]*m2[0][0]+m[0][1]*m2[0][1]+m[0][2]*m2[0][2];
ans[0][1] = m[0][0]*m2[1][0]+m[0][1]*m2[1][1]+m[0][2]*m2[1][2];
ans[0][2] = m[0][0]*m2[2][0]+m[0][1]*m2[2][1]+m[0][2]*m2[2][2];
ans[1][0] = m[1][0]*m2[0][0]+m[1][1]*m2[0][1]+m[1][2]*m2[0][2];
ans[1][1] = m[1][0]*m2[1][0]+m[1][1]*m2[1][1]+m[1][2]*m2[1][2];
ans[1][2] = m[1][0]*m2[2][0]+m[1][1]*m2[2][1]+m[1][2]*m2[2][2];
ans[2][0] = m[2][0]*m2[0][0]+m[2][1]*m2[0][1]+m[2][2]*m2[0][2];
ans[2][1] = m[2][0]*m2[1][0]+m[2][1]*m2[1][1]+m[2][2]*m2[1][2];
ans[2][2] = m[2][0]*m2[2][0]+m[2][1]*m2[2][1]+m[2][2]*m2[2][2];
}
/* ----------------------------------------------------------------------
invert a matrix
does NOT checks for singular or badly scaled matrix
@ -285,6 +307,23 @@ void MathExtra::row_times3(const double *v, const double m[3][3],
ans[2] = v[0]*m[0][2]+v[1]*m[1][2]+m[2][2]*v[2];
}
/* ----------------------------------------------------------------------
matrix times scalar, in place
------------------------------------------------------------------------- */
inline void MathExtra::scalar_times3(const double f, double m[3][3])
{
m[0][0] *= f;
m[0][1] *= f;
m[0][2] *= f;
m[1][0] *= f;
m[1][1] *= f;
m[1][2] *= f;
m[2][0] *= f;
m[2][1] *= f;
m[2][2] *= f;
}
/* ----------------------------------------------------------------------
solve Ax = b or M ans = v
use gaussian elimination & partial pivoting on matrix

View File

@ -45,8 +45,8 @@ using namespace LAMMPS_NS;
#define ALPHA_MAX 1.0
#define ALPHA_REDUCE 0.5
#define BACKTRACK_SLOPE 0.4
#define QUADRATIC_TOL 0.1
#define IDEAL_TOL 1.0e-8
#define QUADRATIC_TOL 0.1
#define EPS_QUAD 1.0e-28
// same as in other min classes
@ -245,6 +245,15 @@ int MinLineSearch::linemin_backtrack(double eoriginal, double &alpha,
}
if (nextra_global) modify->min_store();
// Important diagnostic: test the gradient against energy
// double etmp;
// double alphatmp = alphamax*1.0e-4;
// etmp = alpha_step(alphatmp,1,nfunc);
// printf("alpha = %g dele = %g dele_force = %g err = %g\n",
// alphatmp,etmp-eoriginal,-alphatmp*fdothall,
// etmp-eoriginal+alphatmp*fdothall);
// alpha_step(0.0,1,nfunc);
// backtrack with alpha until energy decrease is sufficient
while (1) {
@ -254,7 +263,13 @@ int MinLineSearch::linemin_backtrack(double eoriginal, double &alpha,
de_ideal = -BACKTRACK_SLOPE*alpha*fdothall;
de = ecurrent - eoriginal;
if (de <= de_ideal) return 0;
if (de <= de_ideal) {
if (nextra_global) {
int itmp = modify->min_reset_ref();
if (itmp) ecurrent = energy_force(1);
}
return 0;
}
// reduce alpha
@ -317,6 +332,7 @@ int MinLineSearch::linemin_quadratic(double eoriginal, double &alpha,
double delfh,engprev,relerr,alphaprev,fhprev,ff,fh,alpha0,fh0,ff0;
double dot[2],dotall[2];
double *xatom,*x0atom,*fatom,*hatom;
double alphamax;
// fdothall = projection of search dir along downhill gradient
// if search direction is not downhill, exit with error
@ -336,18 +352,18 @@ int MinLineSearch::linemin_quadratic(double eoriginal, double &alpha,
if (output->thermo->normflag) fdothall /= atom->natoms;
if (fdothall <= 0.0) return DOWNHILL;
// set alpha so no dof is changed by more than max allowed amount
// set alphamax so no dof is changed by more than max allowed amount
// for atom coords, max amount = dmax
// for extra per-atom dof, max amount = extra_max[]
// for extra global dof, max amount is set by fix
// also insure alpha <= ALPHA_MAX
// also insure alphamax <= ALPHA_MAX
// else will have to backtrack from huge value when forces are tiny
// if all search dir components are already 0.0, exit with error
hme = 0.0;
for (i = 0; i < n3; i++) hme = MAX(hme,fabs(h[i]));
MPI_Allreduce(&hme,&hmaxall,1,MPI_DOUBLE,MPI_MAX,world);
alpha = MIN(ALPHA_MAX,dmax/hmaxall);
alphamax = MIN(ALPHA_MAX,dmax/hmaxall);
if (nextra_atom)
for (m = 0; m < nextra_atom; m++) {
hme = 0.0;
@ -355,15 +371,16 @@ int MinLineSearch::linemin_quadratic(double eoriginal, double &alpha,
n = extra_nlen[m];
for (i = 0; i < n; i++) hme = MAX(hme,fabs(hatom[i]));
MPI_Allreduce(&hme,&hmax,1,MPI_DOUBLE,MPI_MAX,world);
alpha = MIN(alpha,extra_max[m]/hmax);
alphamax = MIN(alphamax,extra_max[m]/hmax);
hmaxall = MAX(hmaxall,hmax);
}
if (nextra_global) {
double alpha_extra = modify->max_alpha(hextra);
alpha = MIN(alpha,alpha_extra);
alphamax = MIN(alphamax,alpha_extra);
for (i = 0; i < nextra_global; i++)
hmaxall = MAX(hmaxall,fabs(hextra[i]));
}
if (hmaxall == 0.0) return ZEROFORCE;
// store box and values of all dof at start of linesearch
@ -382,10 +399,20 @@ int MinLineSearch::linemin_quadratic(double eoriginal, double &alpha,
// backtrack with alpha until energy decrease is sufficient
// or until get to small energy change, then perform quadratic projection
alpha = alphamax;
fhprev = fdothall;
engprev = eoriginal;
alphaprev = 0.0;
// Important diagnostic: test the gradient against energy
// double etmp;
// double alphatmp = alphamax*1.0e-4;
// etmp = alpha_step(alphatmp,1,nfunc);
// printf("alpha = %g dele = %g dele_force = %g err = %g\n",
// alphatmp,etmp-eoriginal,-alphatmp*fdothall,
// etmp-eoriginal+alphatmp*fdothall);
// alpha_step(0.0,1,nfunc);
while (1) {
ecurrent = alpha_step(alpha,1,nfunc);
@ -437,6 +464,10 @@ int MinLineSearch::linemin_quadratic(double eoriginal, double &alpha,
if (relerr <= QUADRATIC_TOL && alpha0 > 0.0) {
ecurrent = alpha_step(alpha0,1,nfunc);
if (nextra_global) {
int itmp = modify->min_reset_ref();
if (itmp) ecurrent = energy_force(1);
}
return 0;
}
@ -444,7 +475,14 @@ int MinLineSearch::linemin_quadratic(double eoriginal, double &alpha,
de_ideal = -BACKTRACK_SLOPE*alpha*fdothall;
de = ecurrent - eoriginal;
if (de <= de_ideal) return 0;
if (de <= de_ideal) {
if (nextra_global) {
int itmp = modify->min_reset_ref();
if (itmp) ecurrent = energy_force(1);
}
return 0;
}
// save previous state

View File

@ -513,6 +513,21 @@ int Modify::min_dof()
return ndof;
}
/* ----------------------------------------------------------------------
reset reference state of fix, only for relevant fixes
------------------------------------------------------------------------- */
int Modify::min_reset_ref()
{
int itmp,itmpall;
itmpall = 0;
for (int i = 0; i < n_min_energy; i++) {
itmp = fix[list_min_energy[i]]->min_reset_ref();
if (itmp) itmpall = 1;
}
return itmpall;
}
/* ----------------------------------------------------------------------
add a new fix or replace one with same ID
------------------------------------------------------------------------- */

View File

@ -68,6 +68,7 @@ class Modify : protected Pointers {
void min_clearstore();
void min_pushstore();
void min_popstore();
int min_reset_ref();
double max_alpha(double *);
int min_dof();