diff -Naur lammps-25Aug09/doc/fix_nvt.html lammps-27Aug09/doc/fix_nvt.html --- lammps-25Aug09/doc/fix_nvt.html 2009-05-12 07:33:47.000000000 -0600 +++ lammps-27Aug09/doc/fix_nvt.html 2009-08-27 12:51:09.000000000 -0600 @@ -25,16 +25,17 @@
  • zero or more keyword/value pairs may be appended -
  • keyword = drag +
  • keyword = drag or chain -
      drag value = drag factor added to thermostat (0.0 = no drag) 
    +
      drag value = drag factor added to thermostat (0.0 = no drag)
    +  chain value = yes or no 
     

    Examples:

    fix 1 all nvt 300.0 300.0 100.0
    -fix 1 all nvt 300.0 300.0 100.0 drag 0.2 
    +fix 1 all nvt 300.0 300.0 100.0 drag 0.2 chain no 
     

    Description:

    @@ -55,15 +56,29 @@ of (roughly) 100 time units (tau or fmsec or psec - see the units command).

    +

    The chain keyword determines whether Nose/Hoover chains are used or +not. If chain is specified as no, then the original Nose/Hoover +formulation is used. If chain is specified as yes, which is the +default, then chains as described in (Martyna) are used +which include extra non-physical variables which couple to the +thermostat. Nose/Hoover chains provide a more robust NVT integrator, +overcoming non-ergodic sampling issues and energy oscillations found +with ordinary Nose/Hoover dynamics. Our implementation uses one chain +and integrates the equations of motion via a Trotter expansion good to +2nd order accuracy in the timestep size. +

    In some cases (e.g. for solids) the temperature of the system can -oscillate undesirably when a Nose/Hoover thermostat is applied. The -optional drag keyword will damp these oscillations, although it -alters the Nose/Hoover equations. A value of 0.0 (no drag) leaves the -Nose/Hoover formalism unchanged. A non-zero value adds a drag term; -the larger the value specified, the greater the damping effect. -Performing a short run and monitoring the temperature is the best way -to determine if the drag term is working. Typically a value between -0.2 to 2.0 is sufficient to damp oscillations after a few periods. +oscillate undesirably when a Nose/Hoover thermostat is applied, though +this should be less of a problem if Nose/Hoover chains are used. The +optional drag keyword will damp these oscillations in an ad-hoc +fashion, by altering the Nose/Hoover equations so that they no longer +exactly sample the canonical ensemble. A value of 0.0 (no drag) +leaves the Nose/Hoover formalism unchanged. A non-zero value adds a +drag term; the larger the value specified, the greater the damping +effect. Performing a short run and monitoring the temperature is the +best way to determine if the drag term is working. Typically a value +between 0.2 to 2.0 is sufficient to damp oscillations after a few +periods.

    IMPORTANT NOTE: Unlike the fix temp/berendsen command which performs thermostatting but NO time integration, this @@ -159,7 +174,7 @@

    Default:

    -

    The keyword defaults are drag = 0.0. +

    The keyword defaults are drag = 0.0 and chain = yes.


    @@ -167,4 +182,9 @@

    (Hoover) Hoover, Phys Rev A, 31, 1695 (1985).

    + + +

    (Martyna) Martyna, Klein, Tuckerman, J Chem Phys, 97, 2635 (1992); +Martyna, Tuckerman, Tobias, Klein, Mol Phys, 87, 1117. +

    diff -Naur lammps-25Aug09/doc/fix_nvt.txt lammps-27Aug09/doc/fix_nvt.txt --- lammps-25Aug09/doc/fix_nvt.txt 2009-05-12 07:33:47.000000000 -0600 +++ lammps-27Aug09/doc/fix_nvt.txt 2009-08-27 12:51:09.000000000 -0600 @@ -18,14 +18,15 @@ Tdamp = temperature damping parameter (time units) :l zero or more keyword/value pairs may be appended :l -keyword = {drag} :l - {drag} value = drag factor added to thermostat (0.0 = no drag) :pre +keyword = {drag} or {chain} :l + {drag} value = drag factor added to thermostat (0.0 = no drag) + {chain} value = {yes} or {no} :pre :ule [Examples:] fix 1 all nvt 300.0 300.0 100.0 -fix 1 all nvt 300.0 300.0 100.0 drag 0.2 :pre +fix 1 all nvt 300.0 300.0 100.0 drag 0.2 chain no :pre [Description:] @@ -46,15 +47,29 @@ of (roughly) 100 time units (tau or fmsec or psec - see the "units"_units.html command). +The {chain} keyword determines whether Nose/Hoover chains are used or +not. If {chain} is specified as {no}, then the original Nose/Hoover +formulation is used. If {chain} is specified as {yes}, which is the +default, then chains as described in "(Martyna)"_#Martyna are used +which include extra non-physical variables which couple to the +thermostat. Nose/Hoover chains provide a more robust NVT integrator, +overcoming non-ergodic sampling issues and energy oscillations found +with ordinary Nose/Hoover dynamics. Our implementation uses one chain +and integrates the equations of motion via a Trotter expansion good to +2nd order accuracy in the timestep size. + In some cases (e.g. for solids) the temperature of the system can -oscillate undesirably when a Nose/Hoover thermostat is applied. The -optional {drag} keyword will damp these oscillations, although it -alters the Nose/Hoover equations. A value of 0.0 (no drag) leaves the -Nose/Hoover formalism unchanged. A non-zero value adds a drag term; -the larger the value specified, the greater the damping effect. -Performing a short run and monitoring the temperature is the best way -to determine if the drag term is working. Typically a value between -0.2 to 2.0 is sufficient to damp oscillations after a few periods. +oscillate undesirably when a Nose/Hoover thermostat is applied, though +this should be less of a problem if Nose/Hoover chains are used. The +optional {drag} keyword will damp these oscillations in an ad-hoc +fashion, by altering the Nose/Hoover equations so that they no longer +exactly sample the canonical ensemble. A value of 0.0 (no drag) +leaves the Nose/Hoover formalism unchanged. A non-zero value adds a +drag term; the larger the value specified, the greater the damping +effect. Performing a short run and monitoring the temperature is the +best way to determine if the drag term is working. Typically a value +between 0.2 to 2.0 is sufficient to damp oscillations after a few +periods. IMPORTANT NOTE: Unlike the "fix temp/berendsen"_fix_berendsen.html command which performs thermostatting but NO time integration, this @@ -150,9 +165,13 @@ [Default:] -The keyword defaults are drag = 0.0. +The keyword defaults are drag = 0.0 and chain = yes. :line :link(Hoover) [(Hoover)] Hoover, Phys Rev A, 31, 1695 (1985). + +:link(Martyna) +[(Martyna)] Martyna, Klein, Tuckerman, J Chem Phys, 97, 2635 (1992); +Martyna, Tuckerman, Tobias, Klein, Mol Phys, 87, 1117. diff -Naur lammps-25Aug09/doc/minimize.html lammps-27Aug09/doc/minimize.html --- lammps-25Aug09/doc/minimize.html 2008-06-27 11:40:03.000000000 -0600 +++ lammps-27Aug09/doc/minimize.html 2009-08-27 12:51:09.000000000 -0600 @@ -18,7 +18,7 @@

    Examples:

    diff -Naur lammps-25Aug09/doc/minimize.txt lammps-27Aug09/doc/minimize.txt --- lammps-25Aug09/doc/minimize.txt 2008-06-27 11:40:03.000000000 -0600 +++ lammps-27Aug09/doc/minimize.txt 2009-08-27 12:51:09.000000000 -0600 @@ -15,7 +15,7 @@ etol = stopping tolerance for energy (unitless) ftol = stopping tolerance for force (force units) maxiter = max iterations of minimizer -maxeval = max number of total force/energy evaluations :ul +maxeval = max number of force/energy evaluations :ul [Examples:] diff -Naur lammps-25Aug09/doc/reset_timestep.html lammps-27Aug09/doc/reset_timestep.html --- lammps-25Aug09/doc/reset_timestep.html 2009-08-18 12:16:59.000000000 -0600 +++ lammps-27Aug09/doc/reset_timestep.html 2009-08-27 12:51:09.000000000 -0600 @@ -45,8 +45,8 @@ if necessary. New specifications for dump and restart files can be given after the reset_timestep command is used.

    -

    This command cannot be used when any fixes are defined that keeps -track of elapsed time to perform time-dependent operations. Examples +

    This command cannot be used when any fixes are defined that keep track +of elapsed time to perform time-dependent operations. Examples include the "ave" fixes such as fix ave/spatial. Also fix dt/reset and fix deposit. diff -Naur lammps-25Aug09/doc/reset_timestep.txt lammps-27Aug09/doc/reset_timestep.txt --- lammps-25Aug09/doc/reset_timestep.txt 2009-08-18 12:16:59.000000000 -0600 +++ lammps-27Aug09/doc/reset_timestep.txt 2009-08-27 12:51:09.000000000 -0600 @@ -42,8 +42,8 @@ if necessary. New specifications for dump and restart files can be given after the reset_timestep command is used. -This command cannot be used when any fixes are defined that keeps -track of elapsed time to perform time-dependent operations. Examples +This command cannot be used when any fixes are defined that keep track +of elapsed time to perform time-dependent operations. Examples include the "ave" fixes such as "fix ave/spatial"_fix_ave_spatial.html. Also "fix dt/reset"_fix_dt_reset.html and "fix deposit"_fix_deposity.html. diff -Naur lammps-25Aug09/src/fix_nvt.cpp lammps-27Aug09/src/fix_nvt.cpp --- lammps-25Aug09/src/fix_nvt.cpp 2009-07-02 12:01:55.000000000 -0600 +++ lammps-27Aug09/src/fix_nvt.cpp 2009-08-27 12:56:19.000000000 -0600 @@ -12,7 +12,8 @@ ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- - Contributing author: Mark Stevens (SNL) + Contributing authors: Mark Stevens (SNL) + Andy Ballard (U Maryland) for Nose/Hoover chains ------------------------------------------------------------------------- */ #include "string.h" @@ -50,9 +51,24 @@ t_stop = atof(arg[4]); double t_period = atof(arg[5]); - if (narg == 6) drag = 0.0; - else if (narg == 8 && strcmp(arg[6],"drag") == 0) drag = atof(arg[7]); - else error->all("Illegal fix nvt command"); + 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 @@ -88,6 +104,7 @@ // Nose/Hoover temp init eta = eta_dot = 0.0; + eta2 = eta2_dot = 0.0; } /* ---------------------------------------------------------------------- */ @@ -129,6 +146,9 @@ 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) { @@ -155,12 +175,29 @@ delta /= update->endstep - update->beginstep; t_target = t_start + delta * (t_stop-t_start); - // update eta_dot + // 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; + } - 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 @@ -172,8 +209,6 @@ 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) { @@ -188,7 +223,6 @@ x[i][2] += dtv * v[i][2]; } } - } else if (which == BIAS) { for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { @@ -218,7 +252,6 @@ x[i][2] += dtv * v[i][2]; } } - } else if (which == BIAS) { for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { @@ -235,6 +268,14 @@ } } } + + 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; + } } /* ---------------------------------------------------------------------- */ @@ -254,6 +295,8 @@ 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++) { @@ -264,7 +307,6 @@ v[i][2] = v[i][2]*factor + dtfm*f[i][2]; } } - } else if (which == BIAS) { for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { @@ -288,7 +330,6 @@ v[i][2] = v[i][2]*factor + dtfm*f[i][2]; } } - } else if (which == BIAS) { for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { @@ -307,11 +348,82 @@ t_current = temperature->compute_scalar(); - // update eta_dot + // update eta, eta_dot, eta2, eta2_dot + // chains require additional velocity update and recompute of current T - f_eta = t_freq*t_freq * (t_current/t_target - 1.0); - eta_dot += f_eta*dthalf; - eta_dot *= drag_factor; + 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] = v[i][0] * factor; + v[i][1] = v[i][1] * factor; + v[i][2] = v[i][2] * factor; + } + } + } else if (which == BIAS) { + 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; + v[i][1] = v[i][1] * factor; + v[i][2] = 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] = v[i][0] * factor; + v[i][1] = v[i][1] * factor; + v[i][2] = v[i][2] * factor; + } + } + } else if (which == BIAS) { + 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; + v[i][1] = v[i][1] * factor; + v[i][2] = 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; + } } /* ---------------------------------------------------------------------- */ @@ -348,13 +460,26 @@ delta /= update->endstep - update->beginstep; t_target = t_start + delta * (t_stop-t_start); - // update eta_dot + 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; + } - 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) { @@ -367,7 +492,6 @@ v[i][2] = v[i][2]*factor + dtfm*f[i][2]; } } - } else if (which == BIAS) { for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { @@ -415,6 +539,14 @@ } } } + + 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; + } } /* ---------------------------------------------------------------------- */ @@ -471,9 +603,11 @@ void FixNVT::write_restart(FILE *fp) { int n = 0; - double list[2]; + 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); @@ -492,6 +626,8 @@ double *list = (double *) buf; eta = list[n++]; eta_dot = list[n++]; + eta2 = list[n++]; + eta2_dot = list[n++]; } /* ---------------------------------------------------------------------- */ @@ -519,6 +655,7 @@ error->warning("Group for fix_modify temp != fix group"); return 2; } + return 0; } @@ -536,6 +673,9 @@ 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); } diff -Naur lammps-25Aug09/src/fix_nvt.h lammps-27Aug09/src/fix_nvt.h --- lammps-25Aug09/src/fix_nvt.h 2008-04-08 16:55:40.000000000 -0600 +++ lammps-27Aug09/src/fix_nvt.h 2009-08-27 12:51:03.000000000 -0600 @@ -37,12 +37,12 @@ void reset_dt(); protected: - int which; + 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,factor; - double dtv,dtf,dthalf; + double f_eta,eta_dot,eta,eta2_dot,eta2,factor,factor2; + double dtv,dtf,dthalf,dt4,dt8; int nlevels_respa; double *step_respa;