diff --git a/doc/Section_howto.html b/doc/Section_howto.html
index 3bac6be12..4ee014bda 100644
--- a/doc/Section_howto.html
+++ b/doc/Section_howto.html
@@ -1,2035 +1,2035 @@
 <HTML>
 <CENTER><A HREF = "Section_accelerate.html">Previous Section</A> - <A HREF = "http://lammps.sandia.gov">LAMMPS WWW Site</A> - <A HREF = "Manual.html">LAMMPS Documentation</A> - <A HREF = "Section_commands.html#comm">LAMMPS Commands</A> - <A HREF = "Section_example.html">Next Section</A> 
 </CENTER>
 
 
 
 
 
 
 <HR>
 
 <H3>6. How-to discussions 
 </H3>
 <P>This section describes how to perform common tasks using LAMMPS.
 </P>
 6.1 <A HREF = "#howto_1">Restarting a simulation</A><BR>
 6.2 <A HREF = "#howto_2">2d simulations</A><BR>
 6.3 <A HREF = "#howto_3">CHARMM, AMBER, and DREIDING force fields</A><BR>
 6.4 <A HREF = "#howto_4">Running multiple simulations from one input script</A><BR>
 6.5 <A HREF = "#howto_5">Multi-replica simulations</A><BR>
 6.6 <A HREF = "#howto_6">Granular models</A><BR>
 6.7 <A HREF = "#howto_7">TIP3P water model</A><BR>
 6.8 <A HREF = "#howto_8">TIP4P water model</A><BR>
 6.9 <A HREF = "#howto_9">SPC water model</A><BR>
 6.10 <A HREF = "#howto_10">Coupling LAMMPS to other codes</A><BR>
 6.11 <A HREF = "#howto_11">Visualizing LAMMPS snapshots</A><BR>
 6.12 <A HREF = "#howto_12">Triclinic (non-orthogonal) simulation boxes</A><BR>
 6.13 <A HREF = "#howto_13">NEMD simulations</A><BR>
 6.14 <A HREF = "#howto_14">Extended spherical and aspherical particles</A><BR>
 6.15 <A HREF = "#howto_15">Output from LAMMPS (thermo, dumps, computes, fixes, variables)</A><BR>
 6.16 <A HREF = "#howto_16">Thermostatting, barostatting and computing temperature</A><BR>
 6.17 <A HREF = "#howto_17">Walls</A><BR>
 6.18 <A HREF = "#howto_18">Elastic constants</A><BR>
 6.19 <A HREF = "#howto_19">Library interface to LAMMPS</A><BR>
 6.20 <A HREF = "#howto_20">Calculating thermal conductivity</A><BR>
 6.21 <A HREF = "#howto_21">Calculating viscosity</A> <BR>
 
 <P>The example input scripts included in the LAMMPS distribution and
 highlighted in <A HREF = "Section_example.html">Section_example</A> also show how to
 setup and run various kinds of simulations.
 </P>
 <HR>
 
 <HR>
 
 <A NAME = "howto_1"></A><H4>6.1 Restarting a simulation 
 </H4>
 <P>There are 3 ways to continue a long LAMMPS simulation.  Multiple
 <A HREF = "run.html">run</A> commands can be used in the same input script.  Each
 run will continue from where the previous run left off.  Or binary
 restart files can be saved to disk using the <A HREF = "restart.html">restart</A>
 command.  At a later time, these binary files can be read via a
 <A HREF = "read_restart.html">read_restart</A> command in a new script.  Or they can
 be converted to text data files and read by a
 <A HREF = "read_data.html">read_data</A> command in a new script.  <A HREF = "Section_tools.html">This
 section</A> discusses the <I>restart2data</I> tool that is
 used to perform the conversion.
 </P>
 <P>Here we give examples of 2 scripts that read either a binary restart
 file or a converted data file and then issue a new run command to
 continue where the previous run left off.  They illustrate what
 settings must be made in the new script.  Details are discussed in the
 documentation for the <A HREF = "read_restart.html">read_restart</A> and
 <A HREF = "read_data.html">read_data</A> commands.
 </P>
 <P>Look at the <I>in.chain</I> input script provided in the <I>bench</I> directory
 of the LAMMPS distribution to see the original script that these 2
 scripts are based on.  If that script had the line
 </P>
 <PRE>restart	        50 tmp.restart 
 </PRE>
 <P>added to it, it would produce 2 binary restart files (tmp.restart.50
 and tmp.restart.100) as it ran.
 </P>
 <P>This script could be used to read the 1st restart file and re-run the
 last 50 timesteps:
 </P>
 <PRE>read_restart	tmp.restart.50 
 </PRE>
 <PRE>neighbor	0.4 bin
 neigh_modify	every 1 delay 1 
 </PRE>
 <PRE>fix		1 all nve
 fix		2 all langevin 1.0 1.0 10.0 904297 
 </PRE>
 <PRE>timestep	0.012 
 </PRE>
 <PRE>run		50 
 </PRE>
 <P>Note that the following commands do not need to be repeated because
 their settings are included in the restart file: <I>units, atom_style,
 special_bonds, pair_style, bond_style</I>.  However these commands do
 need to be used, since their settings are not in the restart file:
 <I>neighbor, fix, timestep</I>.
 </P>
 <P>If you actually use this script to perform a restarted run, you will
 notice that the thermodynamic data match at step 50 (if you also put a
 "thermo 50" command in the original script), but do not match at step
 100.  This is because the <A HREF = "fix_langevin.html">fix langevin</A> command
 uses random numbers in a way that does not allow for perfect restarts.
 </P>
 <P>As an alternate approach, the restart file could be converted to a data
 file using this tool:
 </P>
 <PRE>restart2data tmp.restart.50 tmp.restart.data 
 </PRE>
 <P>Then, this script could be used to re-run the last 50 steps:
 </P>
 <PRE>units		lj
 atom_style	bond
 pair_style	lj/cut 1.12
 pair_modify	shift yes
 bond_style	fene
 special_bonds   0.0 1.0 1.0 
 </PRE>
 <PRE>read_data	tmp.restart.data 
 </PRE>
 <PRE>neighbor	0.4 bin
 neigh_modify	every 1 delay 1 
 </PRE>
 <PRE>fix		1 all nve
 fix		2 all langevin 1.0 1.0 10.0 904297 
 </PRE>
 <PRE>timestep	0.012 
 </PRE>
 <PRE>reset_timestep	50
 run		50 
 </PRE>
 <P>Note that nearly all the settings specified in the original <I>in.chain</I>
 script must be repeated, except the <I>pair_coeff</I> and <I>bond_coeff</I>
 commands since the new data file lists the force field coefficients.
 Also, the <A HREF = "reset_timestep.html">reset_timestep</A> command is used to tell
 LAMMPS the current timestep.  This value is stored in restart files,
 but not in data files.
 </P>
 <HR>
 
 <A NAME = "howto_2"></A><H4>6.2 2d simulations 
 </H4>
 <P>Use the <A HREF = "dimension.html">dimension</A> command to specify a 2d simulation.
 </P>
 <P>Make the simulation box periodic in z via the <A HREF = "boundary.html">boundary</A>
 command.  This is the default.
 </P>
 <P>If using the <A HREF = "create_box.html">create box</A> command to define a
 simulation box, set the z dimensions narrow, but finite, so that the
 create_atoms command will tile the 3d simulation box with a single z
 plane of atoms - e.g.
 </P>
 <PRE><A HREF = "create_box.html">create box</A> 1 -10 10 -10 10 -0.25 0.25 
 </PRE>
 <P>If using the <A HREF = "read_data.html">read data</A> command to read in a file of
 atom coordinates, set the "zlo zhi" values to be finite but narrow,
 similar to the create_box command settings just described.  For each
 atom in the file, assign a z coordinate so it falls inside the
 z-boundaries of the box - e.g. 0.0.
 </P>
 <P>Use the <A HREF = "fix_enforce2d.html">fix enforce2d</A> command as the last
 defined fix to insure that the z-components of velocities and forces
 are zeroed out every timestep.  The reason to make it the last fix is
 so that any forces induced by other fixes will be zeroed out.
 </P>
 <P>Many of the example input scripts included in the LAMMPS distribution
 are for 2d models.
 </P>
 <P>IMPORTANT NOTE: Some models in LAMMPS treat particles as extended
 spheres, as opposed to point particles.  In 2d, the particles will
 still be spheres, not disks, meaning their moment of inertia will be
 the same as in 3d.
 </P>
 <HR>
 
 <A NAME = "howto_3"></A><H4>6.3 CHARMM, AMBER, and DREIDING force fields 
 </H4>
 <P>A force field has 2 parts: the formulas that define it and the
 coefficients used for a particular system.  Here we only discuss
 formulas implemented in LAMMPS that correspond to formulas commonly
 used in the CHARMM, AMBER, and DREIDING force fields.  Setting
 coefficients is done in the input data file via the
 <A HREF = "read_data.html">read_data</A> command or in the input script with
 commands like <A HREF = "pair_coeff.html">pair_coeff</A> or
 <A HREF = "bond_coeff.html">bond_coeff</A>.  See <A HREF = "Section_tools.html">Section_tools</A>
 for additional tools that can use CHARMM or AMBER to assign force
 field coefficients and convert their output into LAMMPS input.
 </P>
 <P>See <A HREF = "#MacKerell">(MacKerell)</A> for a description of the CHARMM force
 field.  See <A HREF = "#Cornell">(Cornell)</A> for a description of the AMBER force
 field.
 </P>
 
 
 
 
 <P>These style choices compute force field formulas that are consistent
 with common options in CHARMM or AMBER.  See each command's
 documentation for the formula it computes.
 </P>
 <UL><LI><A HREF = "bond_harmonic.html">bond_style</A> harmonic
 <LI><A HREF = "angle_charmm.html">angle_style</A> charmm
 <LI><A HREF = "dihedral_charmm.html">dihedral_style</A> charmm
 <LI><A HREF = "pair_charmm.html">pair_style</A> lj/charmm/coul/charmm
 <LI><A HREF = "pair_charmm.html">pair_style</A> lj/charmm/coul/charmm/implicit
 <LI><A HREF = "pair_charmm.html">pair_style</A> lj/charmm/coul/long 
 </UL>
 <UL><LI><A HREF = "special_bonds.html">special_bonds</A> charmm
 <LI><A HREF = "special_bonds.html">special_bonds</A> amber 
 </UL>
 <P>DREIDING is a generic force field developed by the <A HREF = "http://www.wag.caltech.edu">Goddard
 group</A> at Caltech and is useful for
 predicting structures and dynamics of organic, biological and
 main-group inorganic molecules. The philosophy in DREIDING is to use
 general force constants and geometry parameters based on simple
 hybridization considerations, rather than individual force constants
 and geometric parameters that depend on the particular combinations of
 atoms involved in the bond, angle, or torsion terms. DREIDING has an
 <A HREF = "pair_hbond_dreiding.html">explicit hydrogen bond term</A> to describe
 interactions involving a hydrogen atom on very electronegative atoms
 (N, O, F).
 </P>
 <P>See <A HREF = "#Mayo">(Mayo)</A> for a description of the DREIDING force field
 </P>
 <P>These style choices compute force field formulas that are consistent
 with the DREIDING force field.  See each command's
 documentation for the formula it computes.
 </P>
 <UL><LI><A HREF = "bond_harmonic.html">bond_style</A> harmonic
 <LI><A HREF = "bond_morse.html">bond_style</A> morse 
 </UL>
 <UL><LI><A HREF = "angle_harmonic.html">angle_style</A> harmonic
 <LI><A HREF = "angle_cosine.html">angle_style</A> cosine
 <LI><A HREF = "angle_cosine_periodic.html">angle_style</A> cosine/periodic 
 </UL>
 <UL><LI><A HREF = "dihedral_charmm.html">dihedral_style</A> charmm
 <LI><A HREF = "improper_umbrella.html">improper_style</A> umbrella 
 </UL>
 <UL><LI><A HREF = "pair_buck.html">pair_style</A> buck
 <LI><A HREF = "pair_buck.html">pair_style</A> buck/coul/cut
 <LI><A HREF = "pair_buck.html">pair_style</A> buck/coul/long
 <LI><A HREF = "pair_lj.html">pair_style</A> lj/cut
 <LI><A HREF = "pair_lj.html">pair_style</A> lj/cut/coul/cut
 <LI><A HREF = "pair_lj.html">pair_style</A> lj/cut/coul/long 
 </UL>
 <UL><LI><A HREF = "pair_hbond_dreiding.html">pair_style</A> hbond/dreiding/lj
 <LI><A HREF = "pair_hbond_dreiding.html">pair_style</A> hbond/dreiding/morse 
 </UL>
 <UL><LI><A HREF = "special_bonds.html">special_bonds</A> dreiding 
 </UL>
 <HR>
 
 <A NAME = "howto_4"></A><H4>6.4 Running multiple simulations from one input script 
 </H4>
 <P>This can be done in several ways.  See the documentation for
 individual commands for more details on how these examples work.
 </P>
 <P>If "multiple simulations" means continue a previous simulation for
 more timesteps, then you simply use the <A HREF = "run.html">run</A> command
 multiple times.  For example, this script
 </P>
 <PRE>units lj
 atom_style atomic
 read_data data.lj
 run 10000
 run 10000
 run 10000
 run 10000
 run 10000 
 </PRE>
 <P>would run 5 successive simulations of the same system for a total of
 50,000 timesteps.
 </P>
 <P>If you wish to run totally different simulations, one after the other,
 the <A HREF = "clear.html">clear</A> command can be used in between them to
 re-initialize LAMMPS.  For example, this script
 </P>
 <PRE>units lj
 atom_style atomic
 read_data data.lj
 run 10000
 clear
 units lj
 atom_style atomic
 read_data data.lj.new
 run 10000 
 </PRE>
 <P>would run 2 independent simulations, one after the other.
 </P>
 <P>For large numbers of independent simulations, you can use
 <A HREF = "variable.html">variables</A> and the <A HREF = "next.html">next</A> and
 <A HREF = "jump.html">jump</A> commands to loop over the same input script
 multiple times with different settings.  For example, this
 script, named in.polymer
 </P>
 <PRE>variable d index run1 run2 run3 run4 run5 run6 run7 run8
 shell cd $d
 read_data data.polymer
 run 10000
 shell cd ..
 clear
 next d
 jump in.polymer 
 </PRE>
 <P>would run 8 simulations in different directories, using a data.polymer
 file in each directory.  The same concept could be used to run the
 same system at 8 different temperatures, using a temperature variable
 and storing the output in different log and dump files, for example
 </P>
 <PRE>variable a loop 8
 variable t index 0.8 0.85 0.9 0.95 1.0 1.05 1.1 1.15
 log log.$a
 read data.polymer
 velocity all create $t 352839
 fix 1 all nvt $t $t 100.0
 dump 1 all atom 1000 dump.$a
 run 100000
 next t
 next a
 jump in.polymer 
 </PRE>
 <P>All of the above examples work whether you are running on 1 or
 multiple processors, but assumed you are running LAMMPS on a single
 partition of processors.  LAMMPS can be run on multiple partitions via
 the "-partition" command-line switch as described in <A HREF = "Section_start.html#start_7">this
 section</A> of the manual.
 </P>
 <P>In the last 2 examples, if LAMMPS were run on 3 partitions, the same
 scripts could be used if the "index" and "loop" variables were
 replaced with <I>universe</I>-style variables, as described in the
 <A HREF = "variable.html">variable</A> command.  Also, the "next t" and "next a"
 commands would need to be replaced with a single "next a t" command.
 With these modifications, the 8 simulations of each script would run
 on the 3 partitions one after the other until all were finished.
 Initially, 3 simulations would be started simultaneously, one on each
 partition.  When one finished, that partition would then start
 the 4th simulation, and so forth, until all 8 were completed.
 </P>
 <HR>
 
 <A NAME = "howto_5"></A><H4>6.5 Multi-replica simulations 
 </H4>
 <P>Several commands in LAMMPS run mutli-replica simulations, meaning
 that multiple instances (replicas) of your simulation are run
 simultaneously, with small amounts of data exchanged between replicas
 periodically.
 </P>
 <P>These are the relevant commands:
 </P>
 <UL><LI><A HREF = "neb.html">neb</A> for nudged elastic band calculations
 <LI><A HREF = "prd.html">prd</A> for parallel replica dynamics
 <LI><A HREF = "tad.html">tad</A> for temperature accelerated dynamics
 <LI><A HREF = "temper.html">temper</A> for parallel tempering 
 </UL>
 <P>NEB is a method for finding transition states and barrier energies.
 PRD and TAD are methods for performing accelerated dynamics to find
 and perform infrequent events.  Parallel tempering or replica exchange
 runs different replicas at a series of temperature to facilitate
 rare-event sampling.
 </P>
 <P>These command can only be used if LAMMPS was built with the "replica"
 package.  See the <A HREF = "Section_start.html#start_3">Making LAMMPS</A> section
 for more info on packages.
 </P>
 <P>In all these cases, you must run with one or more processors per
 replica.  The processors assigned to each replica are determined at
 run-time by using the <A HREF = "Section_start.html#start_7">-partition command-line
 switch</A> to launch LAMMPS on multiple
 partitions, which in this context are the same as replicas.  E.g.
 these commands:
 </P>
 <PRE>mpirun -np 16 lmp_linux -partition 8x2 -in in.temper
 mpirun -np 8 lmp_linux -partition 8x1 -in in.neb 
 </PRE>
 <P>would each run 8 replicas, on either 16 or 8 processors.  Note the use
 of the <A HREF = "Section_start.html#start_7">-in command-line switch</A> to specify
 the input script which is required when running in multi-replica mode.
 </P>
 <P>Also note that with MPI installed on a machine (e.g. your desktop),
 you can run on more (virtual) processors than you have physical
 processors.  Thus the above commands could be run on a
 single-processor (or few-processor) desktop so that you can run
 a multi-replica simulation on more replicas than you have
 physical processors.
 </P>
 <HR>
 
 <A NAME = "howto_6"></A><H4>6.6 Granular models 
 </H4>
 <P>Granular system are composed of spherical particles with a diameter,
 as opposed to point particles.  This means they have an angular
 velocity and torque can be imparted to them to cause them to rotate.
 </P>
 <P>To run a simulation of a granular model, you will want to use
 the following commands:
 </P>
 <UL><LI><A HREF = "atom_style.html">atom_style sphere</A>
 <LI><A HREF = "fix_nve_sphere.html">fix nve/sphere</A>
 <LI><A HREF = "fix_gravity.html">fix gravity</A> 
 </UL>
 <P>This compute
 </P>
 <UL><LI><A HREF = "compute_erotate_sphere.html">compute erotate/sphere</A> 
 </UL>
 <P>calculates rotational kinetic energy which can be <A HREF = "Section_howto.html#howto_15">output with
 thermodynamic info</A>.
 </P>
 <P>Use one of these 3 pair potentials, which compute forces and torques
 between interacting pairs of particles:
 </P>
 <UL><LI><A HREF = "pair_style.html">pair_style</A> gran/history
 <LI><A HREF = "pair_style.html">pair_style</A> gran/no_history
 <LI><A HREF = "pair_style.html">pair_style</A> gran/hertzian 
 </UL>
 <P>These commands implement fix options specific to granular systems:
 </P>
 <UL><LI><A HREF = "fix_freeze.html">fix freeze</A>
 <LI><A HREF = "fix_pour.html">fix pour</A>
 <LI><A HREF = "fix_viscous.html">fix viscous</A>
 <LI><A HREF = "fix_wall_gran.html">fix wall/gran</A> 
 </UL>
 <P>The fix style <I>freeze</I> zeroes both the force and torque of frozen
 atoms, and should be used for granular system instead of the fix style
 <I>setforce</I>.
 </P>
 <P>For computational efficiency, you can eliminate needless pairwise
 computations between frozen atoms by using this command:
 </P>
 <UL><LI><A HREF = "neigh_modify.html">neigh_modify</A> exclude 
 </UL>
 <HR>
 
 <A NAME = "howto_7"></A><H4>6.7 TIP3P water model 
 </H4>
 <P>The TIP3P water model as implemented in CHARMM
 <A HREF = "#MacKerell">(MacKerell)</A> specifies a 3-site rigid water molecule with
 charges and Lennard-Jones parameters assigned to each of the 3 atoms.
 In LAMMPS the <A HREF = "fix_shake.html">fix shake</A> command can be used to hold
 the two O-H bonds and the H-O-H angle rigid.  A bond style of
 <I>harmonic</I> and an angle style of <I>harmonic</I> or <I>charmm</I> should also be
 used.
 </P>
 <P>These are the additional parameters (in real units) to set for O and H
 atoms and the water molecule to run a rigid TIP3P-CHARMM model with a
 cutoff.  The K values can be used if a flexible TIP3P model (without
 fix shake) is desired.  If the LJ epsilon and sigma for HH and OH are
 set to 0.0, it corresponds to the original 1983 TIP3P model
 <A HREF = "#Jorgensen">(Jorgensen)</A>.
 </P>
 <P>O mass = 15.9994<BR>
 H mass = 1.008 <BR>
 </P>
 <P>O charge = -0.834<BR>
 H charge = 0.417 <BR>
 </P>
 <P>LJ epsilon of OO = 0.1521<BR>
 LJ sigma of OO = 3.1507<BR>
 LJ epsilon of HH = 0.0460<BR>
 LJ sigma of HH = 0.4000<BR>
 LJ epsilon of OH = 0.0836<BR>
 LJ sigma of OH = 1.7753 <BR>
 </P>
 <P>K of OH bond = 450<BR>
 r0 of OH bond = 0.9572 <BR>
 </P>
 <P>K of HOH angle = 55<BR>
 theta of HOH angle = 104.52 <BR>
 </P>
 <P>These are the parameters to use for TIP3P with a long-range Coulombic
 solver (Ewald or PPPM in LAMMPS), see <A HREF = "#Price">(Price)</A> for details:
 </P>
 <P>O mass = 15.9994<BR>
 H mass = 1.008 <BR>
 </P>
 <P>O charge = -0.830<BR>
 H charge = 0.415 <BR>
 </P>
 <P>LJ epsilon of OO = 0.102<BR>
 LJ sigma of OO = 3.188<BR>
 LJ epsilon, sigma of OH, HH = 0.0 <BR>
 </P>
 <P>K of OH bond = 450<BR>
 r0 of OH bond = 0.9572 <BR>
 </P>
 <P>K of HOH angle = 55<BR>
 theta of HOH angle = 104.52 <BR>
 </P>
 <P>Wikipedia also has a nice article on <A HREF = "http://en.wikipedia.org/wiki/Water_model">water
 models</A>.
 </P>
 <HR>
 
 <A NAME = "howto_8"></A><H4>6.8 TIP4P water model 
 </H4>
 <P>The four-point TIP4P rigid water model extends the traditional
 three-point TIP3P model by adding an additional site, usually
 massless, where the charge associated with the oxygen atom is placed.
 This site M is located at a fixed distance away from the oxygen along
 the bisector of the HOH bond angle.  A bond style of <I>harmonic</I> and an
 angle style of <I>harmonic</I> or <I>charmm</I> should also be used.
 </P>
 <P>A TIP4P model is run with LAMMPS using two commands:
 </P>
 <UL><LI><A HREF = "pair_lj.html">pair_style lj/cut/coul/long/tip4p</A>
 <LI><A HREF = "kspace_style.html">kspace_style pppm/tip4p</A> 
 </UL>
 <P>Note that only a TIP4P model with long-range Coulombics is currently
 implemented.  A cutoff version may be added in the future.  for both
 models, the bond lengths and bond angles should be held fixed using
 the <A HREF = "fix_shake.html">fix shake</A> command.
 </P>
 <P>These are the additional parameters (in real units) to set for O and H
 atoms and the water molecule to run a rigid TIP4P model with a cutoff
 <A HREF = "#Jorgensen">(Jorgensen)</A>.  Note that the OM distance is specified in
 the <A HREF = "pair_style.html">pair_style</A> command, not as part of the pair
 coefficients.
 </P>
 <P>O mass = 15.9994<BR>
 H mass = 1.008 <BR>
 </P>
 <P>O charge = -1.040<BR>
 H charge = 0.520 <BR>
 </P>
 <P>r0 of OH bond = 0.9572<BR>
 theta of HOH angle = 104.52 <BR>
 </P>
 <P>OM distance = 0.15 <BR>
 </P>
 <P>LJ epsilon of O-O = 0.1550<BR>
 LJ sigma of O-O = 3.1536<BR>
 LJ epsilon, sigma of OH, HH = 0.0 <BR>
 </P>
 <P>These are the parameters to use for TIP4P with a long-range Coulombic
 solver (Ewald or PPPM in LAMMPS):
 </P>
 <P>O mass = 15.9994<BR>
 H mass = 1.008 <BR>
 </P>
 <P>O charge = -1.0484<BR>
 H charge = 0.5242 <BR>
 </P>
 <P>r0 of OH bond = 0.9572<BR>
 theta of HOH angle = 104.52 <BR>
 </P>
 <P>OM distance = 0.1250 <BR>
 </P>
 <P>LJ epsilon of O-O = 0.16275<BR>
 LJ sigma of O-O = 3.16435<BR>
 LJ epsilon, sigma of OH, HH = 0.0 <BR>
 </P>
 <P>Note that the when using the TIP4P pair style, the neighobr list
 cutoff for Coulomb interactions is effectively extended by a distance
 2 * (OM distance), to account for the offset distance of the
 fictitious charges on O atoms in water molecules.  Thus it is
 typically best in an efficiency sense to use a LJ cutoff >= Coulomb
 cutoff + 2*(OM distance), to shrink the size of the neighbor list.
 This leads to slightly larger cost for the long-range calculation, so
 you can test the trade-off for your model.  The OM distance and the LJ
 and Coulombic cutoffs are set in the <A HREF = "pair_lj.html">pair_style
 lj/cut/coul/long/tip4p</A> command.
 </P>
 <P>Wikipedia also has a nice article on <A HREF = "http://en.wikipedia.org/wiki/Water_model">water
 models</A>.
 </P>
 <HR>
 
 <A NAME = "howto_9"></A><H4>6.9 SPC water model 
 </H4>
 <P>The SPC water model specifies a 3-site rigid water molecule with
 charges and Lennard-Jones parameters assigned to each of the 3 atoms.
 In LAMMPS the <A HREF = "fix_shake.html">fix shake</A> command can be used to hold
 the two O-H bonds and the H-O-H angle rigid.  A bond style of
 <I>harmonic</I> and an angle style of <I>harmonic</I> or <I>charmm</I> should also be
 used.
 </P>
 <P>These are the additional parameters (in real units) to set for O and H
 atoms and the water molecule to run a rigid SPC model.
 </P>
 <P>O mass = 15.9994<BR>
 H mass = 1.008 <BR>
 </P>
 <P>O charge = -0.820<BR>
 H charge = 0.410 <BR>
 </P>
 <P>LJ epsilon of OO = 0.1553<BR>
 LJ sigma of OO = 3.166<BR>
 LJ epsilon, sigma of OH, HH = 0.0 <BR>
 </P>
 <P>r0 of OH bond = 1.0<BR>
 theta of HOH angle = 109.47 <BR>
 </P>
 <P>Note that as originally proposed, the SPC model was run with a 9
 Angstrom cutoff for both LJ and Coulommbic terms.  It can also be used
 with long-range Coulombics (Ewald or PPPM in LAMMPS), without changing
 any of the parameters above, though it becomes a different model in
 that mode of usage.
 </P>
 <P>The SPC/E (extended) water model is the same, except
 the partial charge assignemnts change:
 </P>
 <P>O charge = -0.8476<BR>
 H charge = 0.4238 <BR>
 </P>
 <P>See the <A HREF = "#Berendsen">(Berendsen)</A> reference for more details on both
 the SPC and SPC/E models.
 </P>
 <P>Wikipedia also has a nice article on <A HREF = "http://en.wikipedia.org/wiki/Water_model">water
 models</A>.
 </P>
 <HR>
 
 <A NAME = "howto_10"></A><H4>6.10 Coupling LAMMPS to other codes 
 </H4>
 <P>LAMMPS is designed to allow it to be coupled to other codes.  For
 example, a quantum mechanics code might compute forces on a subset of
 atoms and pass those forces to LAMMPS.  Or a continuum finite element
 (FE) simulation might use atom positions as boundary conditions on FE
 nodal points, compute a FE solution, and return interpolated forces on
 MD atoms.
 </P>
 <P>LAMMPS can be coupled to other codes in at least 3 ways.  Each has
 advantages and disadvantages, which you'll have to think about in the
 context of your application.
 </P>
 <P>(1) Define a new <A HREF = "fix.html">fix</A> command that calls the other code.  In
 this scenario, LAMMPS is the driver code.  During its timestepping,
 the fix is invoked, and can make library calls to the other code,
 which has been linked to LAMMPS as a library.  This is the way the
 <A HREF = "http://www.rpi.edu/~anderk5/lab">POEMS</A> package that performs constrained rigid-body motion on
 groups of atoms is hooked to LAMMPS.  See the
 <A HREF = "fix_poems.html">fix_poems</A> command for more details.  See <A HREF = "Section_modify.html">this
 section</A> of the documentation for info on how to add
 a new fix to LAMMPS.
 </P>
 
 
 <P>(2) Define a new LAMMPS command that calls the other code.  This is
 conceptually similar to method (1), but in this case LAMMPS and the
 other code are on a more equal footing.  Note that now the other code
 is not called during the timestepping of a LAMMPS run, but between
 runs.  The LAMMPS input script can be used to alternate LAMMPS runs
 with calls to the other code, invoked via the new command.  The
 <A HREF = "run.html">run</A> command facilitates this with its <I>every</I> option, which
 makes it easy to run a few steps, invoke the command, run a few steps,
 invoke the command, etc.
 </P>
 <P>In this scenario, the other code can be called as a library, as in
 (1), or it could be a stand-alone code, invoked by a system() call
 made by the command (assuming your parallel machine allows one or more
 processors to start up another program).  In the latter case the
 stand-alone code could communicate with LAMMPS thru files that the
 command writes and reads.
 </P>
 <P>See <A HREF = "Section_modify.html">Section_modify</A> of the documentation for how
 to add a new command to LAMMPS.
 </P>
 <P>(3) Use LAMMPS as a library called by another code.  In this case the
 other code is the driver and calls LAMMPS as needed.  Or a wrapper
 code could link and call both LAMMPS and another code as libraries.
 Again, the <A HREF = "run.html">run</A> command has options that allow it to be
 invoked with minimal overhead (no setup or clean-up) if you wish to do
 multiple short runs, driven by another program.
 </P>
 <P>Examples of driver codes that call LAMMPS as a library are included in
 the "couple" directory of the LAMMPS distribution; see couple/README
 for more details:
 </P>
 <UL><LI>simple: simple driver programs in C++ and C which invoke LAMMPS as a
 library 
 
 <LI>lammps_quest: coupling of LAMMPS and <A HREF = "http://dft.sandia.gov/Quest">Quest</A>, to run classical
 MD with quantum forces calculated by a density functional code 
 
 <LI>lammps_spparks: coupling of LAMMPS and <A HREF = "http://www.sandia.gov/~sjplimp/spparks.html">SPPARKS</A>, to couple
 a kinetic Monte Carlo model for grain growth using MD to calculate
 strain induced across grain boundaries 
 </UL>
 
 
 
 
 <P><A HREF = "Section_start.html#start_5">This section</A> of the documentation
 describes how to build LAMMPS as a library.  Once this is done, you
 can interface with LAMMPS either via C++, C, Fortran, or Python (or
 any other language that supports a vanilla C-like interface).  For
 example, from C++ you could create one (or more) "instances" of
 LAMMPS, pass it an input script to process, or execute individual
 commands, all by invoking the correct class methods in LAMMPS.  From C
 or Fortran you can make function calls to do the same things.  See
 <A HREF = "Section_python.html">Section_python</A> of the manual for a description
 of the Python wrapper provided with LAMMPS that operates through the
 LAMMPS library interface.
 </P>
 <P>The files src/library.cpp and library.h contain the C-style interface
 to LAMMPS.  See <A HREF = "Section_howto.html#howto_19">Section_howto 19</A> of the
 manual for a description of the interface and how to extend it for
 your needs.
 </P>
 <P>Note that the lammps_open() function that creates an instance of
 LAMMPS takes an MPI communicator as an argument.  This means that
 instance of LAMMPS will run on the set of processors in the
 communicator.  Thus the calling code can run LAMMPS on all or a subset
 of processors.  For example, a wrapper script might decide to
 alternate between LAMMPS and another code, allowing them both to run
 on all the processors.  Or it might allocate half the processors to
 LAMMPS and half to the other code and run both codes simultaneously
 before syncing them up periodically.  Or it might instantiate multiple
 instances of LAMMPS to perform different calculations.
 </P>
 <HR>
 
 <A NAME = "howto_11"></A><H4>6.11 Visualizing LAMMPS snapshots 
 </H4>
 <P>LAMMPS itself does not do visualization, but snapshots from LAMMPS
 simulations can be visualized (and analyzed) in a variety of ways.
 </P>
 <P>LAMMPS snapshots are created by the <A HREF = "dump.html">dump</A> command which can
 create files in several formats.  The native LAMMPS dump format is a
 text file (see "dump atom" or "dump custom") which can be visualized
 by the <A HREF = "Section_tools.html#xmovie">xmovie</A> program, included with the
 LAMMPS package.  This produces simple, fast 2d projections of 3d
 systems, and can be useful for rapid debugging of simulation geometry
 and atom trajectories.
 </P>
 <P>Several programs included with LAMMPS as auxiliary tools can convert
 native LAMMPS dump files to other formats.  See the
 <A HREF = "Section_tools.html">Section_tools</A> doc page for details.  The first is
 the <A HREF = "Section_tools.html#charmm">ch2lmp tool</A>, which contains a
 lammps2pdb Perl script which converts LAMMPS dump files into PDB
 files.  The second is the <A HREF = "Section_tools.html#arc">lmp2arc tool</A> which
 converts LAMMPS dump files into Accelrys' Insight MD program files.
 The third is the <A HREF = "Section_tools.html#cfg">lmp2cfg tool</A> which converts
 LAMMPS dump files into CFG files which can be read into the
 <A HREF = "http://mt.seas.upenn.edu/Archive/Graphics/A">AtomEye</A> visualizer.
 </P>
 <P>A Python-based toolkit distributed by our group can read native LAMMPS
 dump files, including custom dump files with additional columns of
 user-specified atom information, and convert them to various formats
 or pipe them into visualization software directly.  See the <A HREF = "http://www.sandia.gov/~sjplimp/pizza.html">Pizza.py
 WWW site</A> for details.  Specifically, Pizza.py can convert
 LAMMPS dump files into PDB, XYZ, <A HREF = "http://www.ensight.com">Ensight</A>, and VTK formats.
 Pizza.py can pipe LAMMPS dump files directly into the Raster3d and
 RasMol visualization programs.  Pizza.py has tools that do interactive
 3d OpenGL visualization and one that creates SVG images of dump file
 snapshots.
 </P>
 <P>LAMMPS can create XYZ files directly (via "dump xyz") which is a
 simple text-based file format used by many visualization programs
 including <A HREF = "http://www.ks.uiuc.edu/Research/vmd">VMD</A>.
 </P>
 <P>LAMMPS can create DCD files directly (via "dump dcd") which can be
 read by <A HREF = "http://www.ks.uiuc.edu/Research/vmd">VMD</A> in conjunction with a CHARMM PSF file.  Using this
 form of output avoids the need to convert LAMMPS snapshots to PDB
 files.  See the <A HREF = "dump.html">dump</A> command for more information on DCD
 files.
 </P>
 <P>LAMMPS can create XTC files directly (via "dump xtc") which is GROMACS
 file format which can also be read by <A HREF = "http://www.ks.uiuc.edu/Research/vmd">VMD</A> for visualization.
 See the <A HREF = "dump.html">dump</A> command for more information on XTC files.
 </P>
 
 
 
 
 
 
 
 
 <HR>
 
 <A NAME = "howto_12"></A><H4>6.12 Triclinic (non-orthogonal) simulation boxes 
 </H4>
 <P>By default, LAMMPS uses an orthogonal simulation box to encompass the
 particles.  The <A HREF = "boundary.html">boundary</A> command sets the boundary
 conditions of the box (periodic, non-periodic, etc).  The orthogonal
 box has its "origin" at (xlo,ylo,zlo) and is defined by 3 edge vectors
 starting from the origin given by <B>a</B> = (xhi-xlo,0,0); <B>b</B> =
 (0,yhi-ylo,0); <B>c</B> = (0,0,zhi-zlo).  The 6 parameters
 (xlo,xhi,ylo,yhi,zlo,zhi) are defined at the time the simulation box
 is created, e.g. by the <A HREF = "create_box.html">create_box</A> or
 <A HREF = "read_data.html">read_data</A> or <A HREF = "read_restart.html">read_restart</A>
 commands.  Additionally, LAMMPS defines box size parameters lx,ly,lz
 where lx = xhi-xlo, and similarly in the y and z dimensions.  The 6
 parameters, as well as lx,ly,lz, can be output via the <A HREF = "thermo_style.html">thermo_style
 custom</A> command.
 </P>
 <P>LAMMPS also allows simulations to be performed in triclinic
 (non-orthogonal) simulation boxes shaped as a parallelepiped with
 triclinic symmetry.  The parallelepiped has its "origin" at
 (xlo,ylo,zlo) and is defined by 3 edge vectors starting from the
 origin given by <B>a</B> = (xhi-xlo,0,0); <B>b</B> = (xy,yhi-ylo,0); <B>c</B> =
 (xz,yz,zhi-zlo).  <I>xy,xz,yz</I> can be 0.0 or positive or negative values
 and are called "tilt factors" because they are the amount of
 displacement applied to faces of an originally orthogonal box to
 transform it into the parallelepiped.  In LAMMPS the
 triclinic simulation box edge vectors <B>a</B>, <B>b</B>, and <B>c</B> cannot be
 arbitrary vectors.  As indicated, <B>a</B> must lie on the positive x axis.
 <B>b</B> must lie in the xy plane, with strictly positive y component. <B>c</B> may 
 have any orientation with strictly positive z component.
 The requirement that <B>a</B>, <B>b</B>, and <B>c</B> have strictly positive x, y,
 and z components, respectively, ensures
 that <B>a</B>, <B>b</B>, and <B>c</B> form a complete right-handed basis.
 These restrictions impose
 no loss of generality, since it is possible to rotate/invert 
 any set of 3 crystal basis vectors so that they conform to the restrictions.
 </P>
 <P>For example, assume that the 3 vectors <B>A</B>,<B>B</B>,<B>C</B> are the edge
 vectors of a general parallelepiped, where there is no restriction
 on <B>A</B>,<B>B</B>,<B>C</B> other than they form a complete right-handed basis i.e.
 <B>A</B> x <B>B</B> . <B>C</B> > 0.
 The equivalent LAMMPS <B>a</B>,<B>b</B>,<B>c</B> are a linear rotation of <B>A</B>, <B>B</B>, and
 <B>C</B> and can be computed as follows:
 </P>
 <CENTER><IMG SRC = "Eqs/transform.jpg">
 </CENTER>
 <P>where A = |<B>A</B>| indicates the scalar length of <B>A</B>. The ^ hat symbol
 indicates the corresponding unit vector. <I>beta</I> and <I>gamma</I> are angles
 between the vectors described below. Note that by construction, 
 <B>a</B>, <B>b</B>, and <B>c</B> have strictly positive x, y, and z components, respectively.
 If it should happen that
 <B>A</B>, <B>B</B>, and <B>C</B> form a left-handed basis, then the above equations
 are not valid for <B>c</B>. In this case, it is necessary
 to first apply an inversion. This can be achieved
 by interchanging two basis vectors or by changing the sign of one of them.
 </P>
-<P>For consistency, the same rotation/inversion appied to the basis vectors
+<P>For consistency, the same rotation/inversion applied to the basis vectors
 must also be applied to atom positions, velocities, 
 and any other vector quantities.
 This can be conveniently achieved by first converting to 
 fractional coordinates in the
 old basis and then converting to distance coordinates in the new basis.
 The transformation is given by the following equation:
 </P>
 <CENTER><IMG SRC = "Eqs/rotate.jpg">
 </CENTER>
 <P>where <I>V</I> is the volume of the box, <B>X</B> is the original vector quantity and 
 <B>x</B> is the vector in the LAMMPS basis. 
 </P>
 <P>There is no requirement that a triclinic box be periodic in any
 dimension, though it typically should be in at least the 2nd dimension
 of the tilt (y in xy) if you want to enforce a shift in periodic
 boundary conditions across that boundary.  Some commands that work
 with triclinic boxes, e.g. the <A HREF = "fix_deform.html">fix deform</A> and <A HREF = "fix_nh.html">fix
 npt</A> commands, require periodicity or non-shrink-wrap
 boundary conditions in specific dimensions.  See the command doc pages
 for details.
 </P>
 <P>The 9 parameters (xlo,xhi,ylo,yhi,zlo,zhi,xy,xz,yz) are defined at the
 time the simluation box is created.  This happens in one of 3 ways.
 If the <A HREF = "create_box.html">create_box</A> command is used with a region of
 style <I>prism</I>, then a triclinic box is setup.  See the
 <A HREF = "region.html">region</A> command for details.  If the
 <A HREF = "read_data.html">read_data</A> command is used to define the simulation
 box, and the header of the data file contains a line with the "xy xz
 yz" keyword, then a triclinic box is setup.  See the
 <A HREF = "read_data.html">read_data</A> command for details.  Finally, if the
 <A HREF = "read_restart.html">read_restart</A> command reads a restart file which
 was written from a simulation using a triclinic box, then a triclinic
 box will be setup for the restarted simulation.
 </P>
 <P>Note that you can define a triclinic box with all 3 tilt factors =
 0.0, so that it is initially orthogonal.  This is necessary if the box
 will become non-orthogonal, e.g. due to the <A HREF = "fix_nh.html">fix npt</A> or
 <A HREF = "fix_deform.html">fix deform</A> commands.  Alternatively, you can use the
 <A HREF = "change_box.html">change_box</A> command to convert a simulation box from
 orthogonal to triclinic and vice versa.
 </P>
 <P>As with orthogonal boxes, LAMMPS defines triclinic box size parameters
 lx,ly,lz where lx = xhi-xlo, and similarly in the y and z dimensions.
 The 9 parameters, as well as lx,ly,lz, can be output via the
 <A HREF = "thermo_style.html">thermo_style custom</A> command.
 </P>
 <P>To avoid extremely tilted boxes (which would be computationally
 inefficient), no tilt factor can skew the box more than half the
 distance of the parallel box length, which is the 1st dimension in the
 tilt factor (x for xz).  For example, if xlo = 2 and xhi = 12, then
 the x box length is 10 and the xy tilt factor must be between -5 and
 5.  Similarly, both xz and yz must be between -(xhi-xlo)/2 and
 +(yhi-ylo)/2.  Note that this is not a limitation, since if the
 maximum tilt factor is 5 (as in this example), then configurations
 with tilt = ..., -15, -5, 5, 15, 25, ... are geometrically all
 equivalent.  If the box tilt exceeds this limit during a dynamics run
 (e.g. via the <A HREF = "fix_deform.html">fix deform</A> command), then the box is
 "flipped" to an equivalent shape with a tilt factor within the bounds,
 so the run can continue.  See the <A HREF = "fix_deform.html">fix deform</A> doc
 page for further details.
 </P>
 <P>The one exception to this rule is if the 1st dimension in the tilt
 factor (x for xy) is non-periodic.  In that case, the limits on the
 tilt factor are not enforced, since flipping the box in that dimension
 does not change the atom positions due to non-periodicity.  In this
 mode, if you tilt the system to extreme angles, the simulation will
 simply become inefficient, due to the highly skewed simulation box.
 </P>
 <P>Triclinic crystal structures are often defined using three lattice
 constants <I>a</I>, <I>b</I>, and <I>c</I>, and three angles <I>alpha</I>, <I>beta</I> and
 <I>gamma</I>. Note that in this nomenclature, the a, b, and c lattice
 constants are the scalar lengths of the edge vectors <B>a</B>, <B>b</B>, and <B>c</B>
 defined above.  The relationship between these 6 quantities
 (a,b,c,alpha,beta,gamma) and the LAMMPS box sizes (lx,ly,lz) =
 (xhi-xlo,yhi-ylo,zhi-zlo) and tilt factors (xy,xz,yz) is as follows:
 </P>
 <CENTER><IMG SRC = "Eqs/box.jpg">
 </CENTER>
 <P>The inverse relationship can be written as follows:
 </P>
 <CENTER><IMG SRC = "Eqs/box_inverse.jpg">
 </CENTER>
 <P>The values of <I>a</I>, <I>b</I>, <I>c</I> , <I>alpha</I>, <I>beta</I> , and <I>gamma</I> can be printed 
 out or accessed by computes using the 
 <A HREF = "thermo_style.html">thermo_style custom</A> keywords 
 <I>cella</I>, <I>cellb</I>, <I>cellc</I>, <I>cellalpha</I>, <I>cellbeta</I>, <I>cellgamma</I>,
 respectively. 
 </P>
 <P>As discussed on the <A HREF = "dump.html">dump</A> command doc page, when the BOX
 BOUNDS for a snapshot is written to a dump file for a triclinic box,
 an orthogonal bounding box which encloses the triclinic simulation box
 is output, along with the 3 tilt factors (xy, xz, yz) of the triclinic
 box, formatted as follows:
 </P>
 <PRE>ITEM: BOX BOUNDS xy xz yz
 xlo_bound xhi_bound xy
 ylo_bound yhi_bound xz
 zlo_bound zhi_bound yz 
 </PRE>
 <P>This bounding box is convenient for many visualization programs and is
 calculated from the 9 triclinic box parameters
 (xlo,xhi,ylo,yhi,zlo,zhi,xy,xz,yz) as follows:
 </P>
 <PRE>xlo_bound = xlo + MIN(0.0,xy,xz,xy+xz)
 xhi_bound = xhi + MAX(0.0,xy,xz,xy+xz)
 ylo_bound = ylo + MIN(0.0,yz)
 yhi_bound = yhi + MAX(0.0,yz)
 zlo_bound = zlo
 zhi_bound = zhi 
 </PRE>
 <P>These formulas can be inverted if you need to convert the bounding box
 back into the triclinic box parameters, e.g. xlo = xlo_bound -
 MIN(0.0,xy,xz,xy+xz).
 </P>
 <P>One use of triclinic simulation boxes is to model solid-state crystals
 with triclinic symmetry.  The <A HREF = "lattice.html">lattice</A> command can be
 used with non-orthogonal basis vectors to define a lattice that will
 tile a triclinic simulation box via the
 <A HREF = "create_atoms.html">create_atoms</A> command.
 </P>
 <P>A second use is to run Parinello-Rahman dyanamics via the <A HREF = "fix_nh.html">fix
 npt</A> command, which will adjust the xy, xz, yz tilt
 factors to compensate for off-diagonal components of the pressure
 tensor.  The analalog for an <A HREF = "minimize.html">energy minimization</A> is
 the <A HREF = "fix_box_relax.html">fix box/relax</A> command.
 </P>
 <P>A third use is to shear a bulk solid to study the response of the
 material.  The <A HREF = "fix_deform.html">fix deform</A> command can be used for
 this purpose.  It allows dynamic control of the xy, xz, yz tilt
 factors as a simulation runs.  This is discussed in the next section
 on non-equilibrium MD (NEMD) simulations.
 </P>
 <HR>
 
 <A NAME = "howto_13"></A><H4>6.13 NEMD simulations 
 </H4>
 <P>Non-equilibrium molecular dynamics or NEMD simulations are typically
 used to measure a fluid's rheological properties such as viscosity.
 In LAMMPS, such simulations can be performed by first setting up a
 non-orthogonal simulation box (see the preceding Howto section).
 </P>
 <P>A shear strain can be applied to the simulation box at a desired
 strain rate by using the <A HREF = "fix_deform.html">fix deform</A> command.  The
 <A HREF = "fix_nvt_sllod.html">fix nvt/sllod</A> command can be used to thermostat
 the sheared fluid and integrate the SLLOD equations of motion for the
 system.  Fix nvt/sllod uses <A HREF = "compute_temp_deform.html">compute
 temp/deform</A> to compute a thermal temperature
 by subtracting out the streaming velocity of the shearing atoms.  The
 velocity profile or other properties of the fluid can be monitored via
 the <A HREF = "fix_ave_spatial.html">fix ave/spatial</A> command.
 </P>
 <P>As discussed in the previous section on non-orthogonal simulation
 boxes, the amount of tilt or skew that can be applied is limited by
 LAMMPS for computational efficiency to be 1/2 of the parallel box
 length.  However, <A HREF = "fix_deform.html">fix deform</A> can continuously strain
 a box by an arbitrary amount.  As discussed in the <A HREF = "fix_deform.html">fix
 deform</A> command, when the tilt value reaches a limit,
 the box is flipped to the opposite limit which is an equivalent tiling
 of periodic space.  The strain rate can then continue to change as
 before.  In a long NEMD simulation these box re-shaping events may
 occur many times.
 </P>
 <P>In a NEMD simulation, the "remap" option of <A HREF = "fix_deform.html">fix
 deform</A> should be set to "remap v", since that is what
 <A HREF = "fix_nvt_sllod.html">fix nvt/sllod</A> assumes to generate a velocity
 profile consistent with the applied shear strain rate.
 </P>
 <P>An alternative method for calculating viscosities is provided via the
 <A HREF = "fix_viscosity.html">fix viscosity</A> command.
 </P>
 <HR>
 
 <A NAME = "howto_14"></A><H4>6.14 Extended spherical and aspherical particles 
 </H4>
 <P>Typical MD models treat atoms or particles as point masses.
 Sometimes, however, it is desirable to have a model with finite-size
 particles such as spheres or aspherical ellipsoids.  The difference is
 that such particles have a moment of inertia, rotational energy, and
 angular momentum.  Rotation is induced by torque from interactions
 with other particles.
 </P>
 <P>LAMMPS has several options for running simulations with these kinds of
 particles.  The following aspects are discussed in turn:
 </P>
 <UL><LI>atom styles
 <LI>pair potentials
 <LI>time integration
 <LI>computes, thermodynamics, and dump output
 <LI>rigid bodies composed of extended particles 
 </UL>
 <H5>Atom styles 
 </H5>
 <P>There are 2 <A HREF = "atom_style.html">atom styles</A> that allow for definition of
 finite-size particles: sphere and ellipsoid.  The peri atom style also
 treats particles as having a volume, but that is internal to the
 <A HREF = "pair_peri.html">pair_style peri</A> potentials.  The dipole atom style is
 most often used in conjunction with finite-size particles.
 </P>
 <P>The sphere style defines particles that are spheriods and each
 particle can have a unique diameter and mass (or density).  These
 particles store an angular velocity (omega) and can be acted upon by
 torque.  The "set" command can be used to modify the diameter and mass
 of individual particles, after then are created.
 </P>
 <P>The ellipsoid style defines particles that are ellipsoids and thus can
 be aspherical.  Each particle has a shape, specified by 3 diameters,
 and mass (or density).  These particles store an angular momentum and
 their orientation (quaternion), and can be acted upon by torque.  They
 do not store an angular velocity (omega), which can be in a different
 direction than angular momentum, rather they compute it as needed.
 The "set" command can be used to modify the diameter, orientation, and
 mass of individual particles, after then are created.  It also has a
 brief explanation of what quaternions are.
 </P>
 <P>The dipole style does not define extended particles, but is often
 used in conjunction with spherical particles, via a command like
 </P>
 <PRE>atom_style hybrid sphere dipole 
 </PRE>
 <P>This is because when dipoles interact with each other, they induce
 torques, and a particle must be extended (i.e. have a moment of
 inertia) in order to respond and rotate.  See the <A HREF = "atom_style.html">atom_style
 dipole</A> command for details.  The "set" command can be
 used to modify the orientation and length of the dipole moment of
 individual particles, after then are created.
 </P>
 <P>Note that if one of these atom styles is used (or multiple styles via
 the <A HREF = "atom_style.html">atom_style hybrid</A> command), not all particles in
 the system are required to be finite-size or aspherical.  For example,
 if the 3 shape parameters are set to the same value, the particle will
 be a sphere rather than an ellipsoid.  If the 3 shape parameters are
 all set to 0.0 or if the diameter is set to 0.0, it will be a point
 particle.  If the length of the dipole moment is set to zero, the
 particle will not have a point dipole associated with it.  The pair
 styles used to compute pairwise interactions will typically compute
 the correct interaction in these simplified (cheaper) cases.
 <A HREF = "pair_hybrid.html">Pair_style hybrid</A> can be used to insure the correct
 interactions are computed for the appropriate style of interactions.
 Likewise, using groups to partition particles (ellipsoids versus
 spheres versus point particles) will allow you to use the appropriate
 time integrators and temperature computations for each class of
 particles.  See the doc pages for various commands for details.
 </P>
 <P>Also note that for <A HREF = "dimension.html">2d simulations</A>, finite-size
 spheres and ellipsoids are still treated as 3d particles, rather than
 as circular disks or ellipses.  This means they have the same moment
 of inertia for a 3d extended object.  When their temperature is
 coomputed, the correct degrees of freedom are used for rotation in a
 2d versus 3d system.
 </P>
 <H5>Pair potentials 
 </H5>
 <P>When a system with extended particles is defined, the particles will
 only rotate and experience torque if the force field computes such
 interactions.  These are the various <A HREF = "pair_style.html">pair styles</A>
 that generate torque:
 </P>
 <UL><LI><A HREF = "pair_gran.html">pair_style gran/history</A>
 <LI><A HREF = "pair_gran.html">pair_style gran/hertzian</A>
 <LI><A HREF = "pair_gran.html">pair_style gran/no_history</A>
 <LI><A HREF = "pair_dipole.html">pair_style dipole/cut</A>
 <LI><A HREF = "pair_gayberne.html">pair_style gayberne</A>
 <LI><A HREF = "pair_resquared.html">pair_style resquared</A>
 <LI><A HREF = "pair_lubricate.html">pair_style lubricate</A> 
 </UL>
 <P>The <A HREF = "pair_gran.html">granular pair styles</A> are used with spherical
 particles.  The <A HREF = "pair_dipole.html">dipole pair style</A> is used with
 <A HREF = "atom_style.html">atom_style dipole</A>, which could be applied to
 spherical or ellipsoidal particles.  The <A HREF = "pair_gayberne.html">GayBerne</A>
 and <A HREF = "pair_resquared.html">REsquared</A> potentials require ellipsoidal
 particles, though they will also work if the 3 shape parameters are
 the same (a sphere).  The <A HREF = "pair_lubricate.html">lubrication potential</A>
 works with spherical particles.
 </P>
 <H5>Time integration 
 </H5>
 <P>There are 3 fixes that perform time integration on extended spherical
 particles, meaning the integrators update the rotational orientation
 and angular velocity or angular momentum of the particles:
 </P>
 <UL><LI><A HREF = "fix_nve_sphere.html">fix nve/sphere</A>
 <LI><A HREF = "fix_nvt_sphere.html">fix nvt/sphere</A>
 <LI><A HREF = "fix_npt_sphere.html">fix npt/sphere</A> 
 </UL>
 <P>Likewise, there are 3 fixes that perform time integration on
 ellipsoids as extended aspherical particles:
 </P>
 <UL><LI><A HREF = "fix_nve_asphere.html">fix nve/asphere</A>
 <LI><A HREF = "fix_nvt_asphere.html">fix nvt/asphere</A>
 <LI><A HREF = "fix_npt_asphere.html">fix npt/asphere</A> 
 </UL>
 <P>The advantage of these fixes is that those which thermostat the
 particles include the rotational degrees of freedom in the temperature
 calculation and thermostatting.  Other thermostats can be used with
 fix nve/sphere or fix nve/asphere, such as fix langevin or fix
 temp/berendsen, but those thermostats only operate on the
 translational kinetic energy of the extended particles.
 </P>
 <P>Note that for mixtures of point and extended particles, you should
 only use these integration fixes on <A HREF = "group.html">groups</A> which contain
 extended particles.
 </P>
 <H5>Computes, thermodynamics, and dump output 
 </H5>
 <P>There are 4 computes that calculate the temperature or rotational energy
 of extended spherical or aspherical particles (ellipsoids):
 </P>
 <UL><LI><A HREF = "compute_temp_sphere.html">compute temp/sphere</A>
 <LI><A HREF = "compute_temp_asphere.html">compute temp/asphere</A>
 <LI><A HREF = "compute_erotate_sphere.html">compute erotate/sphere</A>
 <LI><A HREF = "compute_erotate_asphere.html">compute erotate/asphere</A> 
 </UL>
 <P>These include rotational degrees of freedom in their computation.  If
 you wish the thermodynamic output of temperature or pressure to use
 one of these computes (e.g. for a system entirely composed of extended
 particles), then the compute can be defined and the
 <A HREF = "thermo_modify.html">thermo_modify</A> command used.  Note that by
 default thermodynamic quantities will be calculated with a temperature
 that only includes translational degrees of freedom.  See the
 <A HREF = "thermo_style.html">thermo_style</A> command for details.
 </P>
 <P>The <A HREF = "dump.html">dump custom</A> command can output various attributes of
 extended particles, including the dipole moment (mu), the angular
 velocity (omega), the angular momentum (angmom), the quaternion
 (quat), and the torque (tq) on the particle.
 </P>
 <H5>Rigid bodies composed of extended particles 
 </H5>
 <P>The <A HREF = "fix_rigid.html">fix rigid</A> command treats a collection of
 particles as a rigid body, computes its inertia tensor, sums the total
 force and torque on the rigid body each timestep due to forces on its
 constituent particles, and integrates the motion of the rigid body.
 </P>
 <P>If any of the constituent particles of a rigid body are extended
 particles (spheres or ellipsoids), then their contribution to the
 inertia tensor of the body is different than if they were point
 particles.  This means the rotational dynamics of the rigid body will
 be different.  Thus a model of a dimer is different if the dimer
 consists of two point masses versus two extended sphereoids, even if
 the two particles have the same mass.  Extended particles that
 experience torque due to their interaction with other particles will
 also impart that torque to a rigid body they are part of.
 </P>
 <P>See the "fix rigid" command for example of complex rigid-body models
 it is possible to define in LAMMPS.
 </P>
 <P>Note that the <A HREF = "fix_shake.html">fix shake</A> command can also be used to
 treat 2, 3, or 4 particles as a rigid body, but it always assumes the
 particles are point masses.
 </P>
 <HR>
 
 <A NAME = "howto_15"></A><H4>6.15 Output from LAMMPS (thermo, dumps, computes, fixes, variables) 
 </H4>
 <P>There are four basic kinds of LAMMPS output:
 </P>
 <UL><LI><A HREF = "thermo_style.html">Thermodynamic output</A>, which is a list
 of quantities printed every few timesteps to the screen and logfile. 
 
 <LI><A HREF = "dump.html">Dump files</A>, which contain snapshots of atoms and various
 per-atom values and are written at a specified frequency. 
 
 <LI>Certain fixes can output user-specified quantities to files: <A HREF = "fix_ave_time.html">fix
 ave/time</A> for time averaging, <A HREF = "fix_ave_spatial.html">fix
 ave/spatial</A> for spatial averaging, and <A HREF = "fix_print.html">fix
 print</A> for single-line output of
 <A HREF = "variable.html">variables</A>.  Fix print can also output to the
 screen. 
 
 <LI><A HREF = "restart.html">Restart files</A>. 
 </UL>
 <P>A simulation prints one set of thermodynamic output and (optionally)
 restart files.  It can generate any number of dump files and fix
 output files, depending on what <A HREF = "dump.html">dump</A> and <A HREF = "fix.html">fix</A>
 commands you specify.
 </P>
 <P>As discussed below, LAMMPS gives you a variety of ways to determine
 what quantities are computed and printed when the thermodynamics,
 dump, or fix commands listed above perform output.  Throughout this
 discussion, note that users can also <A HREF = "Section_modify.html">add their own computes and fixes
 to LAMMPS</A> which can then generate values that can
 then be output with these commands.
 </P>
 <P>The following sub-sections discuss different LAMMPS command related
 to output and the kind of data they operate on and produce:
 </P>
 <UL><LI><A HREF = "#global">Global/per-atom/local data</A>
 <LI><A HREF = "#scalar">Scalar/vector/array data</A>
 <LI><A HREF = "#thermo">Thermodynamic output</A>
 <LI><A HREF = "#dump">Dump file output</A>
 <LI><A HREF = "#fixoutput">Fixes that write output files</A>
 <LI><A HREF = "#computeoutput">Computes that process output quantities</A>
 <LI><A HREF = "#fixoutput">Fixes that process output quantities</A>
 <LI><A HREF = "#compute">Computes that generate values to output</A>
 <LI><A HREF = "#fix">Fixes that generate values to output</A>
 <LI><A HREF = "#variable">Variables that generate values to output</A>
 <LI><A HREF = "#table">Summary table of output options and data flow between commands</A> 
 </UL>
 <H5><A NAME = "global"></A>Global/per-atom/local data 
 </H5>
 <P>Various output-related commands work with three different styles of
 data: global, per-atom, or local.  A global datum is one or more
 system-wide values, e.g. the temperature of the system.  A per-atom
 datum is one or more values per atom, e.g. the kinetic energy of each
 atom.  Local datums are calculated by each processor based on the
 atoms it owns, but there may be zero or more per atom, e.g. a list of
 bond distances.
 </P>
 <H5><A NAME = "scalar"></A>Scalar/vector/array data 
 </H5>
 <P>Global, per-atom, and local datums can each come in three kinds: a
 single scalar value, a vector of values, or a 2d array of values.  The
 doc page for a "compute" or "fix" or "variable" that generates data
 will specify both the style and kind of data it produces, e.g. a
 per-atom vector.
 </P>
 <P>When a quantity is accessed, as in many of the output commands
 discussed below, it can be referenced via the following bracket
 notation, where ID in this case is the ID of a compute.  The leading
 "c_" would be replaced by "f_" for a fix, or "v_" for a variable:
 </P>
-<DIV ALIGN=center><TABLE  WIDTH="0%"  BORDER=1 >
+<DIV ALIGN=center><TABLE  BORDER=1 >
 <TR><TD >c_ID </TD><TD > entire scalar, vector, or array</TD></TR>
 <TR><TD >c_ID[I] </TD><TD > one element of vector, one column of array</TD></TR>
 <TR><TD >c_ID[I][J] </TD><TD > one element of array 
 </TD></TR></TABLE></DIV>
 
 <P>In other words, using one bracket reduces the dimension of the data
 once (vector -> scalar, array -> vector).  Using two brackets reduces
 the dimension twice (array -> scalar).  Thus a command that uses
 scalar values as input can typically also process elements of a vector
 or array.
 </P>
 <H5><A NAME = "thermo"></A>Thermodynamic output 
 </H5>
 <P>The frequency and format of thermodynamic output is set by the
 <A HREF = "thermo.html">thermo</A>, <A HREF = "thermo_style.html">thermo_style</A>, and
 <A HREF = "thermo_modify.html">thermo_modify</A> commands.  The
 <A HREF = "thermo_style.html">thermo_style</A> command also specifies what values
 are calculated and written out.  Pre-defined keywords can be specified
 (e.g. press, etotal, etc).  Three additional kinds of keywords can
 also be specified (c_ID, f_ID, v_name), where a <A HREF = "compute.html">compute</A>
 or <A HREF = "fix.html">fix</A> or <A HREF = "variable.html">variable</A> provides the value to be
 output.  In each case, the compute, fix, or variable must generate
 global values for input to the <A HREF = "dump.html">thermo_style custom</A>
 command.
 </P>
 <H5><A NAME = "dump"></A>Dump file output 
 </H5>
 <P>Dump file output is specified by the <A HREF = "dump.html">dump</A> and
 <A HREF = "dump_modify.html">dump_modify</A> commands.  There are several
 pre-defined formats (dump atom, dump xtc, etc).
 </P>
 <P>There is also a <A HREF = "dump.html">dump custom</A> format where the user
 specifies what values are output with each atom.  Pre-defined atom
 attributes can be specified (id, x, fx, etc).  Three additional kinds
 of keywords can also be specified (c_ID, f_ID, v_name), where a
 <A HREF = "compute.html">compute</A> or <A HREF = "fix.html">fix</A> or <A HREF = "variable.html">variable</A>
 provides the values to be output.  In each case, the compute, fix, or
 variable must generate per-atom values for input to the <A HREF = "dump.html">dump
 custom</A> command.
 </P>
 <P>There is also a <A HREF = "dump.html">dump local</A> format where the user specifies
 what local values to output.  A pre-defined index keyword can be
 specified to enumuerate the local values.  Two additional kinds of
 keywords can also be specified (c_ID, f_ID), where a
 <A HREF = "compute.html">compute</A> or <A HREF = "fix.html">fix</A> or <A HREF = "variable.html">variable</A>
 provides the values to be output.  In each case, the compute or fix
 must generate local values for input to the <A HREF = "dump.html">dump local</A>
 command.
 </P>
 <H5><A NAME = "fixoutput"></A>Fixes that write output files 
 </H5>
 <P>Sevarl fixes take various quantities as input and can write output
 files: <A HREF = "fix_ave_time.html">fix ave/time</A>, <A HREF = "fix_ave_spatial.html">fix
 ave/spatial</A>, <A HREF = "fix_ave_histo.html">fix ave/histo</A>,
 <A HREF = "fix_ave_correlate.html">fix ave/correlate</A>, and <A HREF = "fix_print.html">fix
 print</A>.
 </P>
 <P>The <A HREF = "fix_ave_time.html">fix ave/time</A> command enables direct output to
 a file and/or time-averaging of global scalars or vectors.  The user
 specifies one or more quantities as input.  These can be global
 <A HREF = "compute.html">compute</A> values, global <A HREF = "fix.html">fix</A> values, or
 <A HREF = "variable.html">variables</A> of any style except the atom style which
 produces per-atom values.  Since a variable can refer to keywords used
 by the <A HREF = "thermo_style.html">thermo_style custom</A> command (like temp or
 press) and individual per-atom values, a wide variety of quantities
 can be time averaged and/or output in this way.  If the inputs are one
 or more scalar values, then the fix generate a global scalar or vector
 of output.  If the inputs are one or more vector values, then the fix
 generates a global vector or array of output.  The time-averaged
 output of this fix can also be used as input to other output commands.
 </P>
 <P>The <A HREF = "fix_ave_spatial.html">fix ave/spatial</A> command enables direct
 output to a file of spatial-averaged per-atom quantities like those
 output in dump files, within 1d layers of the simulation box.  The
 per-atom quantities can be atom density (mass or number) or atom
 attributes such as position, velocity, force.  They can also be
 per-atom quantities calculated by a <A HREF = "compute.html">compute</A>, by a
 <A HREF = "fix.html">fix</A>, or by an atom-style <A HREF = "variable.html">variable</A>.  The
 spatial-averaged output of this fix can also be used as input to other
 output commands.
 </P>
 <P>The <A HREF = "fix_ave_histo.html">fix ave/histo</A> command enables direct output
 to a file of histogrammed quantities, which can be global or per-atom
 or local quantities.  The histogram output of this fix can also be
 used as input to other output commands.
 </P>
 <P>The <A HREF = "fix_ave_histo.html">fix ave/correlate</A> command enables direct
 output to a file of time-correlated quantities, which can be global
 scalars.  The correlation matrix output of this fix can also be used
 as input to other output commands.
 </P>
 <P>The <A HREF = "fix_print.html">fix print</A> command can generate a line of output
 written to the screen and log file or to a separate file, periodically
 during a running simulation.  The line can contain one or more
 <A HREF = "variable.html">variable</A> values for any style variable except the atom
 style).  As explained above, variables themselves can contain
 references to global values generated by <A HREF = "thermo_style.html">thermodynamic
 keywords</A>, <A HREF = "compute.html">computes</A>,
 <A HREF = "fix.html">fixes</A>, or other <A HREF = "variable.html">variables</A>, or to per-atom
 values for a specific atom.  Thus the <A HREF = "fix_print.html">fix print</A>
 command is a means to output a wide variety of quantities separate
 from normal thermodynamic or dump file output.
 </P>
 <H5><A NAME = "computeoutput"></A>Computes that process output quantities 
 </H5>
 <P>The <A HREF = "compute_reduce.html">compute reduce</A> and <A HREF = "compute_reduce.html">compute
 reduce/region</A> commands take one or more per-atom
 or local vector quantities as inputs and "reduce" them (sum, min, max,
 ave) to scalar quantities.  These are produced as output values which
 can be used as input to other output commands.
 </P>
 <P>The <A HREF = "compute_slice.html">compute slice</A> command take one or more global
 vector or array quantities as inputs and extracts a subset of their
 values to create a new vector or array.  These are produced as output
 values which can be used as input to other output commands.
 </P>
 <P>The <A HREF = "compute_property_atom.html">compute property/atom</A> command takes a
 list of one or more pre-defined atom attributes (id, x, fx, etc) and
 stores the values in a per-atom vector or array.  These are produced
 as output values which can be used as input to other output commands.
 The list of atom attributes is the same as for the <A HREF = "dump.html">dump
 custom</A> command.
 </P>
 <P>The <A HREF = "compute_property_local.html">compute property/local</A> command takes
 a list of one or more pre-defined local attributes (bond info, angle
 info, etc) and stores the values in a local vector or array.  These
 are produced as output values which can be used as input to other
 output commands.
 </P>
 <P>The <A HREF = "compute_atom_molecule.html">compute atom/molecule</A> command takes a
 list of one or more per-atom quantities (from a compute, fix, per-atom
 variable) and sums the quantities on a per-molecule basis.  It
 produces a global vector or array as output values which can be used
 as input to other output commands.
 </P>
 <H5><A NAME = "fixoutput"></A>Fixes that process output quantities 
 </H5>
 <P>The <A HREF = "fix_ave_atom.html">fix ave/atom</A> command performs time-averaging
 of per-atom vectors.  The per-atom quantities can be atom attributes
 such as position, velocity, force.  They can also be per-atom
 quantities calculated by a <A HREF = "compute.html">compute</A>, by a
 <A HREF = "fix.html">fix</A>, or by an atom-style <A HREF = "variable.html">variable</A>.  The
 time-averaged per-atom output of this fix can be used as input to
 other output commands.
 </P>
 <P>The <A HREF = "fix_store_state.html">fix store/state</A> command can archive one or
 more per-atom attributes at a particular time, so that the old values
 can be used in a future calculation or output.  The list of atom
 attributes is the same as for the <A HREF = "dump.html">dump custom</A> command,
 including per-atom quantities calculated by a <A HREF = "compute.html">compute</A>,
 by a <A HREF = "fix.html">fix</A>, or by an atom-style <A HREF = "variable.html">variable</A>.
 The output of this fix can be used as input to other output commands.
 </P>
 <H5><A NAME = "compute"></A>Computes that generate values to output 
 </H5>
 <P>Every <A HREF = "compute.html">compute</A> in LAMMPS produces either global or
 per-atom or local values.  The values can be scalars or vectors or
 arrays of data.  These values can be output using the other commands
 described in this section.  The doc page for each compute command
 describes what it produces.  Computes that produce per-atom or local
 values have the word "atom" or "local" in their style name.  Computes
 without the word "atom" or "local" produce global values.
 </P>
 <H5><A NAME = "fix"></A>Fixes that generate values to output 
 </H5>
 <P>Some <A HREF = "fix.html">fixes</A> in LAMMPS produces either global or per-atom or
 local values which can be accessed by other commands.  The values can
 be scalars or vectors or arrays of data.  These values can be output
 using the other commands described in this section.  The doc page for
 each fix command tells whether it produces any output quantities and
 describes them.
 </P>
 <H5><A NAME = "variable"></A>Variables that generate values to output 
 </H5>
 <P>Every <A HREF = "variable.html">variables</A> defined in an input script generates
 either a global scalar value or a per-atom vector (only atom-style
 variables) when it is accessed.  The formulas used to define equal-
 and atom-style variables can contain references to the thermodynamic
 keywords and to global and per-atom data generated by computes, fixes,
 and other variables.  The values generated by variables can be output
 using the other commands described in this section.
 </P>
 <H5><A NAME = "table"></A>Summary table of output options and data flow between commands 
 </H5>
 <P>This table summarizes the various commands that can be used for
 generating output from LAMMPS.  Each command produces output data of
 some kind and/or writes data to a file.  Most of the commands can take
 data from other commands as input.  Thus you can link many of these
 commands together in pipeline form, where data produced by one command
 is used as input to another command and eventually written to the
 screen or to a file.  Note that to hook two commands together the
 output and input data types must match, e.g. global/per-atom/local
 data and scalar/vector/array data.
 </P>
 <P>Also note that, as described above, when a command takes a scalar as
 input, that could be an element of a vector or array.  Likewise a
 vector input could be a column of an array.
 </P>
-<DIV ALIGN=center><TABLE  WIDTH="0%"  BORDER=1 >
+<DIV ALIGN=center><TABLE  BORDER=1 >
 <TR><TD >Command</TD><TD > Input</TD><TD > Output</TD><TD ></TD></TR>
 <TR><TD ><A HREF = "thermo_style.html">thermo_style custom</A></TD><TD > global scalars</TD><TD > screen, log file</TD><TD ></TD></TR>
 <TR><TD ><A HREF = "dump.html">dump custom</A></TD><TD > per-atom vectors</TD><TD > dump file</TD><TD ></TD></TR>
 <TR><TD ><A HREF = "dump.html">dump local</A></TD><TD > local vectors</TD><TD > dump file</TD><TD ></TD></TR>
 <TR><TD ><A HREF = "fix_print.html">fix print</A></TD><TD > global scalar from variable</TD><TD > screen, file</TD><TD ></TD></TR>
 <TR><TD ><A HREF = "print.html">print</A></TD><TD > global scalar from variable</TD><TD > screen</TD><TD ></TD></TR>
 <TR><TD ><A HREF = "compute.html">computes</A></TD><TD > N/A</TD><TD > global/per-atom/local scalar/vector/array</TD><TD ></TD></TR>
 <TR><TD ><A HREF = "fix.html">fixes</A></TD><TD > N/A</TD><TD > global/per-atom/local scalar/vector/array</TD><TD ></TD></TR>
 <TR><TD ><A HREF = "variable.html">variables</A></TD><TD > global scalars, per-atom vectors</TD><TD > global scalar, per-atom vector</TD><TD ></TD></TR>
 <TR><TD ><A HREF = "compute_reduce.html">compute reduce</A></TD><TD > per-atom/local vectors</TD><TD > global scalar/vector</TD><TD ></TD></TR>
 <TR><TD ><A HREF = "compute_slice.html">compute slice</A></TD><TD > global vectors/arrays</TD><TD > global vector/array</TD><TD ></TD></TR>
 <TR><TD ><A HREF = "compute_property_atom.html">compute property/atom</A></TD><TD > per-atom vectors</TD><TD > per-atom vector/array</TD><TD ></TD></TR>
 <TR><TD ><A HREF = "compute_property_local.html">compute property/local</A></TD><TD > local vectors</TD><TD > local vector/array</TD><TD ></TD></TR>
 <TR><TD ><A HREF = "compute_atom_molecule.html">compute atom/molecule</A></TD><TD > per-atom vectors</TD><TD > global vector/array</TD><TD ></TD></TR>
 <TR><TD ><A HREF = "fix_ave_atom.html">fix ave/atom</A></TD><TD > per-atom vectors</TD><TD > per-atom vector/array</TD><TD ></TD></TR>
 <TR><TD ><A HREF = "fix_ave_time.html">fix ave/time</A></TD><TD > global scalars/vectors</TD><TD > global scalar/vector/array, file</TD><TD ></TD></TR>
 <TR><TD ><A HREF = "fix_ave_spatial.html">fix ave/spatial</A></TD><TD > per-atom vectors</TD><TD > global array, file</TD><TD ></TD></TR>
 <TR><TD ><A HREF = "fix_ave_histo.html">fix ave/histo</A></TD><TD > global/per-atom/local scalars and vectors</TD><TD > global array, file</TD><TD ></TD></TR>
 <TR><TD ><A HREF = "fix_ave_correlate.html">fix ave/correlate</A></TD><TD > global scalars</TD><TD > global array, file</TD><TD ></TD></TR>
 <TR><TD ><A HREF = "fix_store_state.html">fix store/state</A></TD><TD > per-atom vectors</TD><TD > per-atom vector/array</TD><TD ></TD></TR>
 <TR><TD >
 </TD></TR></TABLE></DIV>
 
 <HR>
 
 <A NAME = "howto_16"></A><H4>6.16 Thermostatting, barostatting, and computing temperature 
 </H4>
 <P>Thermostatting means controlling the temperature of particles in an MD
 simulation.  Barostatting means controlling the pressure.  Since the
 pressure includes a kinetic component due to particle velocities, both
 these operations require calculation of the temperature.  Typically a
 target temperature (T) and/or pressure (P) is specified by the user,
 and the thermostat or barostat attempts to equilibrate the system to
 the requested T and/or P.
 </P>
 <P>Temperature is computed as kinetic energy divided by some number of
 degrees of freedom (and the Boltzmann constant).  Since kinetic energy
 is a function of particle velocity, there is often a need to
 distinguish between a particle's advection velocity (due to some
 aggregate motiion of particles) and its thermal velocity.  The sum of
 the two is the particle's total velocity, but the latter is often what
 is wanted to compute a temperature.
 </P>
 <P>LAMMPS has several options for computing temperatures, any of which
 can be used in thermostatting and barostatting.  These <A HREF = "compute.html">compute
 commands</A> calculate temperature, and the <A HREF = "compute_pressure.html">compute
 pressure</A> command calculates pressure.
 </P>
 <UL><LI><A HREF = "compute_temp.html">compute temp</A>
 <LI><A HREF = "compute_temp_sphere.html">compute temp/sphere</A>
 <LI><A HREF = "compute_temp_asphere.html">compute temp/asphere</A>
 <LI><A HREF = "compute_temp_com.html">compute temp/com</A>
 <LI><A HREF = "compute_temp_deform.html">compute temp/deform</A>
 <LI><A HREF = "compute_temp_partial.html">compute temp/partial</A>
 <LI><A HREF = "compute_temp_profile.html">compute temp/profile</A>
 <LI><A HREF = "compute_temp_ramp.html">compute temp/ramp</A>
 <LI><A HREF = "compute_temp_region.html">compute temp/region</A> 
 </UL>
 <P>All but the first 3 calculate velocity biases (i.e. advection
 velocities) that are removed when computing the thermal temperature.
 <A HREF = "compute_temp_sphere.html">Compute temp/sphere</A> and <A HREF = "compute_temp_asphere.html">compute
 temp/asphere</A> compute kinetic energy for
 extended particles that includes rotational degrees of freedom.  They
 both allow, as an extra argument, which is another temperature compute
 that subtracts a velocity bias.  This allows the translational
 velocity of extended spherical or aspherical particles to be adjusted
 in prescribed ways.
 </P>
 <P>Thermostatting in LAMMPS is performed by <A HREF = "fix.html">fixes</A>, or in one
 case by a pair style.  Four thermostatting fixes are currently
 available: Nose-Hoover (nvt), Berendsen, Langevin, and direct
 rescaling (temp/rescale).  Dissipative particle dynamics (DPD)
 thermostatting can be invoked via the <I>dpd/tstat</I> pair style:
 </P>
 <UL><LI><A HREF = "fix_nh.html">fix nvt</A>
 <LI><A HREF = "fix_nvt_sphere.html">fix nvt/sphere</A>
 <LI><A HREF = "fix_nvt_asphere.html">fix nvt/asphere</A>
 <LI><A HREF = "fix_nvt_sllod.html">fix nvt/sllod</A>
 <LI><A HREF = "fix_temp_berendsen.html">fix temp/berendsen</A>
 <LI><A HREF = "fix_langevin.html">fix langevin</A>
 <LI><A HREF = "fix_temp_rescale.html">fix temp/rescale</A>
 <LI><A HREF = "pair_dpd.html">pair_style dpd/tstat</A> 
 </UL>
 <P><A HREF = "fix_nh.html">Fix nvt</A> only thermostats the translational velocity of
 particles.  <A HREF = "fix_nvt_sllod.html">Fix nvt/sllod</A> also does this, except
 that it subtracts out a velocity bias due to a deforming box and
 integrates the SLLOD equations of motion.  See the <A HREF = "#howto_13">NEMD
 simulations</A> section of this page for further details.  <A HREF = "fix_nvt_sphere.html">Fix
 nvt/sphere</A> and <A HREF = "fix_nvt_asphere.html">fix
 nvt/asphere</A> thermostat not only translation
 velocities but also rotational velocities for spherical and aspherical
 particles.
 </P>
 <P>DPD thermostatting alters pairwise interactions in a manner analagous
 to the per-particle thermostatting of <A HREF = "fix_langevin.html">fix
 langevin</A>.
 </P>
 <P>Any of the thermostatting fixes can use temperature computes that
 remove bias for two purposes: (a) computing the current temperature to
 compare to the requested target temperature, and (b) adjusting only
 the thermal temperature component of the particle's velocities.  See
 the doc pages for the individual fixes and for the
 <A HREF = "fix_modify.html">fix_modify</A> command for instructions on how to assign
 a temperature compute to a thermostatting fix.  For example, you can
 apply a thermostat to only the x and z components of velocity by using
 it in conjunction with <A HREF = "compute_temp_partial.html">compute
 temp/partial</A>.
 </P>
 <P>IMPORTANT NOTE: Only the nvt fixes perform time integration, meaning
 they update the velocities and positions of particles due to forces
 and velocities respectively.  The other thermostat fixes only adjust
 velocities; they do NOT perform time integration updates.  Thus they
 should be used in conjunction with a constant NVE integration fix such
 as these:
 </P>
 <UL><LI><A HREF = "fix_nve.html">fix nve</A>
 <LI><A HREF = "fix_nve_sphere.html">fix nve/sphere</A>
 <LI><A HREF = "fix_nve_asphere.html">fix nve/asphere</A> 
 </UL>
 <P>Barostatting in LAMMPS is also performed by <A HREF = "fix.html">fixes</A>.  Two
 barosttating methods are currently available: Nose-Hoover (npt and
 nph) and Berendsen:
 </P>
 <UL><LI><A HREF = "fix_nh.html">fix npt</A>
 <LI><A HREF = "fix_npt_sphere.html">fix npt/sphere</A>
 <LI><A HREF = "fix_npt_asphere.html">fix npt/asphere</A>
 <LI><A HREF = "fix_nh.html">fix nph</A>
 <LI><A HREF = "fix_press_berendsen.html">fix press/berendsen</A> 
 </UL>
 <P>The <A HREF = "fix_nh.html">fix npt</A> commands include a Nose-Hoover thermostat
 and barostat.  <A HREF = "fix_nh.html">Fix nph</A> is just a Nose/Hoover barostat;
 it does no thermostatting.  Both <A HREF = "fix_nh.html">fix nph</A> and <A HREF = "fix_press_berendsen.html">fix
 press/bernendsen</A> can be used in conjunction
 with any of the thermostatting fixes.
 </P>
 <P>As with the thermostats, <A HREF = "fix_nh.html">fix npt</A> and <A HREF = "fix_nh.html">fix
 nph</A> only use translational motion of the particles in
 computing T and P and performing thermo/barostatting.  <A HREF = "fix_npt_sphere.html">Fix
 npt/sphere</A> and <A HREF = "fix_npt_asphere.html">fix
 npt/asphere</A> thermo/barostat using not only
 translation velocities but also rotational velocities for spherical
 and aspherical particles.
 </P>
 <P>All of the barostatting fixes use the <A HREF = "compute_pressure.html">compute
 pressure</A> compute to calculate a current
 pressure.  By default, this compute is created with a simple <A HREF = "compute_temp.html">compute
 temp</A> (see the last argument of the <A HREF = "compute_pressure.html">compute
 pressure</A> command), which is used to calculated
 the kinetic componenet of the pressure.  The barostatting fixes can
 also use temperature computes that remove bias for the purpose of
 computing the kinetic componenet which contributes to the current
 pressure.  See the doc pages for the individual fixes and for the
 <A HREF = "fix_modify.html">fix_modify</A> command for instructions on how to assign
 a temperature or pressure compute to a barostatting fix.
 </P>
 <P>IMPORTANT NOTE: As with the thermostats, the Nose/Hoover methods (<A HREF = "fix_nh.html">fix
 npt</A> and <A HREF = "fix_nh.html">fix nph</A>) perform time
 integration.  <A HREF = "fix_press_berendsen.html">Fix press/berendsen</A> does NOT,
 so it should be used with one of the constant NVE fixes or with one of
 the NVT fixes.
 </P>
 <P>Finally, thermodynamic output, which can be setup via the
 <A HREF = "thermo_style.html">thermo_style</A> command, often includes temperature
 and pressure values.  As explained on the doc page for the
 <A HREF = "thermo_style.html">thermo_style</A> command, the default T and P are
 setup by the thermo command itself.  They are NOT the ones associated
 with any thermostatting or barostatting fix you have defined or with
 any compute that calculates a temperature or pressure.  Thus if you
 want to view these values of T and P, you need to specify them
 explicitly via a <A HREF = "thermo_style.html">thermo_style custom</A> command.  Or
 you can use the <A HREF = "thermo_modify.html">thermo_modify</A> command to
 re-define what temperature or pressure compute is used for default
 thermodynamic output.
 </P>
 <HR>
 
 <A NAME = "howto_17"></A><H4>6.17 Walls 
 </H4>
 <P>Walls in an MD simulation are typically used to bound particle motion,
 i.e. to serve as a boundary condition.
 </P>
 <P>Walls in LAMMPS can be of rough (made of particles) or idealized
 surfaces.  Ideal walls can be smooth, generating forces only in the
 normal direction, or frictional, generating forces also in the
 tangential direction.
 </P>
 <P>Rough walls, built of particles, can be created in various ways.  The
 particles themselves can be generated like any other particle, via the
 <A HREF = "lattice.html">lattice</A> and <A HREF = "create_atoms.html">create_atoms</A> commands,
 or read in via the <A HREF = "read_data.html">read_data</A> command.
 </P>
 <P>Their motion can be constrained by many different commands, so that
 they do not move at all, move together as a group at constant velocity
 or in response to a net force acting on them, move in a prescribed
 fashion (e.g. rotate around a point), etc.  Note that if a time
 integration fix like <A HREF = "fix_nve.html">fix nve</A> or <A HREF = "fix_nh.html">fix nvt</A>
 is not used with the group that contains wall particles, their
 positions and velocities will not be updated.
 </P>
 <UL><LI><A HREF = "fix_aveforce.html">fix aveforce</A> - set force on particles to average value, so they move together
 <LI><A HREF = "fix_setforce.html">fix setforce</A> - set force on particles to a value, e.g. 0.0
 <LI><A HREF = "fix_freeze.html">fix freeze</A> - freeze particles for use as granular walls
 <LI><A HREF = "fix_nve_noforce.html">fix nve/noforce</A> - advect particles by their velocity, but without force
 <LI><A HREF = "fix_move.html">fix move</A> - prescribe motion of particles by a linear velocity, oscillation, rotation, variable 
 </UL>
 <P>The <A HREF = "fix_move.html">fix move</A> command offers the most generality, since
 the motion of individual particles can be specified with
 <A HREF = "variable.html">variable</A> formula which depends on time and/or the
 particle position.
 </P>
 <P>For rough walls, it may be useful to turn off pairwise interactions
 between wall particles via the <A HREF = "neigh_modify.html">neigh_modify
 exclude</A> command.
 </P>
 <P>Rough walls can also be created by specifying frozen particles that do
 not move and do not interact with mobile particles, and then tethering
 other particles to the fixed particles, via a <A HREF = "bond_style.html">bond</A>.
 The bonded particles do interact with other mobile particles.
 </P>
 <P>Idealized walls can be specified via several fix commands.  <A HREF = "fix_wall_gran.html">Fix
 wall/gran</A> creates frictional walls for use with
 granular particles; all the other commands create smooth walls.
 </P>
 <UL><LI><A HREF = "fix_wall_reflect.html">fix wall/reflect</A> - reflective flat walls
 <LI><A HREF = "fix_wall.html">fix wall/lj93</A> - flat walls, with Lennard-Jones 9/3 potential
 <LI><A HREF = "fix_wall.html">fix wall/lj126</A> - flat walls, with Lennard-Jones 12/6 potential
 <LI><A HREF = "fix_wall.html">fix wall/colloid</A> - flat walls, with <A HREF = "pair_colloid.html">pair_style colloid</A> potential
 <LI><A HREF = "fix_wall.html">fix wall/harmonic</A> - flat walls, with repulsive harmonic spring potential
 <LI><A HREF = "fix_wall_region.html">fix wall/region</A> - use region surface as wall
 <LI><A HREF = "fix_wall_gran.html">fix wall/gran</A> - flat or curved walls with <A HREF = "pair_gran.html">pair_style granular</A> potential 
 </UL>
 <P>The <I>lj93</I>, <I>lj126</I>, <I>colloid</I>, and <I>harmonic</I> styles all allow the
 flat walls to move with a constant velocity, or oscillate in time.
 The <A HREF = "fix_wall_region.html">fix wall/region</A> command offers the most
 generality, since the region surface is treated as a wall, and the
 geometry of the region can be a simple primitive volume (e.g. a
 sphere, or cube, or plane), or a complex volume made from the union
 and intersection of primitive volumes.  <A HREF = "region.html">Regions</A> can also
 specify a volume "interior" or "exterior" to the specified primitive
 shape or <I>union</I> or <I>intersection</I>.  <A HREF = "region.html">Regions</A> can also be
 "dynamic" meaning they move with constant velocity, oscillate, or
 rotate.
 </P>
 <P>The only frictional idealized walls currently in LAMMPS are flat or
 curved surfaces specified by the <A HREF = "fix_wall_gran.html">fix wall/gran</A>
 command.  At some point we plan to allow regoin surfaces to be used as
 frictional walls, as well as triangulated surfaces.
 </P>
 <HR>
 
 <A NAME = "howto_18"></A><H4>6.18 Elastic constants 
 </H4>
 <P>Elastic constants characterize the stiffness of a material. The formal
 definition is provided by the linear relation that holds between the
 stress and strain tensors in the limit of infinitesimal deformation.
 In tensor notation, this is expressed as s_ij = C_ijkl * e_kl, where
 the repeated indices imply summation. s_ij are the elements of the
 symmetric stress tensor. e_kl are the elements of the symmetric strain
 tensor. C_ijkl are the elements of the fourth rank tensor of elastic
 constants. In three dimensions, this tensor has 3^4=81 elements. Using
 Voigt notation, the tensor can be written as a 6x6 matrix, where C_ij
 is now the derivative of s_i w.r.t. e_j. Because s_i is itself a
 derivative w.r.t. e_i, it follows that C_ij is also symmetric, with at
 most 7*6/2 = 21 distinct elements.
 </P>
 <P>At zero temperature, it is easy to estimate these derivatives by
 deforming the simulation box in one of the six directions using the
 <A HREF = "change_box.html">change_box</A> command and measuring the change in the
 stress tensor. A general-purpose script that does this is given in the
 examples/elastic directory described in <A HREF = "Section_example.html">this
 section</A>.
 </P>
 <P>Calculating elastic constants at finite temperature is more
 challenging, because it is necessary to run a simulation that perfoms
 time averages of differential properties. One way to do this is to
 measure the change in average stress tensor in an NVT simulations when
 the cell volume undergoes a finite deformation. In order to balance
 the systematic and statistical errors in this method, the magnitude of
 the deformation must be chosen judiciously, and care must be taken to
 fully equilibrate the deformed cell before sampling the stress
 tensor. Another approach is to sample the triclinic cell fluctuations
 that occur in an NPT simulation. This method can also be slow to
 converge and requires careful post-processing <A HREF = "#Shinoda">(Shinoda)</A>
 </P>
 <HR>
 
 <A NAME = "howto_19"></A><H4>6.19 Library interface to LAMMPS 
 </H4>
 <P>As described in <A HREF = "Section_start.html#start_5">Section_start 4</A>, LAMMPS
 can be built as a library, so that it can be called by another code,
 used in a <A HREF = "Section_howto.html#howto_10">coupled manner</A> with other
 codes, or driven through a <A HREF = "Section_python.html">Python interface</A>.
 </P>
 <P>All of these methodologies use a C-style interface to LAMMPS that is
 provided in the files src/library.cpp and src/library.h.  The
 functions therein have a C-style argument list, but contain C++ code
 you could write yourself in a C++ application that was invoking LAMMPS
 directly.  The C++ code in the functions illustrates how to invoke
 internal LAMMPS operations.  Note that LAMMPS classes are defined
 within a LAMMPS namespace (LAMMPS_NS) if you use them from another C++
 application.
 </P>
 <P>Library.cpp contains these 4 functions:
 </P>
 <PRE>void lammps_open(int, char **, MPI_Comm, void **);
 void lammps_close(void *);
 void lammps_file(void *, char *);
 char *lammps_command(void *, char *); 
 </PRE>
 <P>The lammps_open() function is used to initialize LAMMPS, passing in a
 list of strings as if they were <A HREF = "Section_start.html#start_7">command-line
 arguments</A> when LAMMPS is run in
 stand-alone mode from the command line, and a MPI communicator for
 LAMMPS to run under.  It returns a ptr to the LAMMPS object that is
 created, and which is used in subsequent library calls.  The
 lammps_open() function can be called multiple times, to create
 multiple instances of LAMMPS.
 </P>
 <P>LAMMPS will run on the set of processors in the communicator.  This
 means the calling code can run LAMMPS on all or a subset of
 processors.  For example, a wrapper script might decide to alternate
 between LAMMPS and another code, allowing them both to run on all the
 processors.  Or it might allocate half the processors to LAMMPS and
 half to the other code and run both codes simultaneously before
 syncing them up periodically.  Or it might instantiate multiple
 instances of LAMMPS to perform different calculations.
 </P>
 <P>The lammps_close() function is used to shut down an instance of LAMMPS
 and free all its memory.
 </P>
 <P>The lammps_file() and lammps_command() functions are used to pass a
 file or string to LAMMPS as if it were an input script or single
 command in an input script.  Thus the calling code can read or
 generate a series of LAMMPS commands one line at a time and pass it
 thru the library interface to setup a problem and then run it,
 interleaving the lammps_command() calls with other calls to extract
 information from LAMMPS, perform its own operations, or call another
 code's library.
 </P>
 <P>Other useful functions are also included in library.cpp.  For example:
 </P>
 <PRE>void *lammps_extract_global(void *, char *)
 void *lammps_extract_atom(void *, char *)
 void *lammps_extract_compute(void *, char *, int, int)
 void *lammps_extract_fix(void *, char *, int, int, int, int)
 void *lammps_extract_variable(void *, char *, char *)
 int lammps_get_natoms(void *)
 void lammps_get_coords(void *, double *)
 void lammps_put_coords(void *, double *) 
 </PRE>
 <P>These can extract various global or per-atom quantities from LAMMPS as
 well as values calculated by a compute, fix, or variable.  The "get"
 and "put" operations can retrieve and reset atom coordinates.
 See the library.cpp file and its associated header file library.h for
 details.
 </P>
 <P>The key idea of the library interface is that you can write any
 functions you wish to define how your code talks to LAMMPS and add
 them to src/library.cpp and src/library.h, as well as to the <A HREF = "Section_python.html">Python
 interface</A>.  The routines you add can access
 or change any LAMMPS data you wish.  The couple and python directories
 have example C++ and C and Python codes which show how a driver code
 can link to LAMMPS as a library, run LAMMPS on a subset of processors,
 grab data from LAMMPS, change it, and put it back into LAMMPS.
 </P>
 <HR>
 
 <A NAME = "howto_20"></A><H4>6.20 Calculating thermal conductivity 
 </H4>
 <P>The thermal conductivity kappa of a material can be measured in at
 least 3 ways using various options in LAMMPS.  (See <A HREF = "Section_howto.html#howto_21">this
 section</A> of the manual for an analogous
 discussion for viscosity).  The thermal conducitivity tensor kappa is
 a measure of the propensity of a material to transmit heat energy in a
 diffusive manner as given by Fourier's law
 </P>
 <P>J = -kappa grad(T)
 </P>
 <P>where J is the heat flux in units of energy per area per time and
 grad(T) is the spatial gradient of temperature.  The thermal
 conductivity thus has units of energy per distance per time per degree
 K and is often approximated as an isotropic quantity, i.e. as a
 scalar.
 </P>
 <P>The first method is to setup two thermostatted regions at opposite
 ends of a simulation box, or one in the middle and one at the end of a
 periodic box.  By holding the two regions at different temperatures
 with a <A HREF = "Section_howto.html#howto_13">thermostatting fix</A>, the energy added
 to the hot region should equal the energy subtracted from the cold
 region and be proportional to the heat flux moving between the
 regions.  See the paper by <A HREF = "#Ikeshoji">Ikeshoji and Hafskjold</A> for
 details of this idea.  Note that thermostatting fixes such as <A HREF = "fix_nh.html">fix
 nvt</A>, <A HREF = "fix_langevin.html">fix langevin</A>, and <A HREF = "fix_temp_rescale.html">fix
 temp/rescale</A> store the cumulative energy they
 add/subtract.  Alternatively, the <A HREF = "fix_heat.html">fix heat</A> command can
 used in place of thermostats on each of two regions, and the resulting
 temperatures of the two regions monitored with the "compute
 temp/region" command or the temperature profile of the intermediate
 region monitored with the <A HREF = "fix_ave_spatial.html">fix ave/spatial</A> and
 <A HREF = "compute_ke_atom.html">compute ke/atom</A> commands.
 </P>
 <P>The second method is to perform a reverse non-equilibrium MD
 simulation using the <A HREF = "fix_thermal_conductivity.html">fix
 thermal/conductivity</A> command which
 implements the rNEMD algorithm of Muller-Plathe.  Kinetic energy is
 swapped between atoms in two different layers of the simulation box.
 This induces a temperature gradient between the two layers which can
 be monitored with the <A HREF = "fix_ave_spatial.html">fix ave/spatial</A> and
 <A HREF = "compute_ke_atom.html">compute ke/atom</A> commands.  The fix tallies the
 cumulative energy transfer that it performs.  See the <A HREF = "fix_thermal_conductivity.html">fix
 thermal/conductivity</A> command for
 details.
 </P>
 <P>The third method is based on the Green-Kubo (GK) formula which relates
 the ensemble average of the auto-correlation of the heat flux to
 kappa.  The heat flux can be calculated from the fluctuations of
 per-atom potential and kinetic energies and per-atom stress tensor in
 a steady-state equilibrated simulation.  This is in contrast to the
 two preceding non-equilibrium methods, where energy flows continuously
 between hot and cold regions of the simulation box.
 </P>
 <P>The <A HREF = "compute_heat_flux.html">compute heat/flux</A> command can calculate
 the needed heat flux and describes how to implement the Green_Kubo
 formalism using additional LAMMPS commands, such as the <A HREF = "fix_ave_correlate.html">fix
 ave/correlate</A> command to calculate the needed
 auto-correlation.  See the doc page for the <A HREF = "compute_heat_flux.html">compute
 heat/flux</A> command for an example input script
 that calculates the thermal conductivity of solid Ar via the GK
 formalism.
 </P>
 <HR>
 
 <A NAME = "howto_21"></A><H4>6.21 Calculating viscosity 
 </H4>
 <P>The shear viscosity eta of a fluid can be measured in at least 3 ways
 using various options in LAMMPS.  (See <A HREF = "Section_howto.html#howto_20">this
 section</A> of the manual for an analogous
 discussion for thermal conductivity).  Eta is a measure of the
 propensity of a fluid to transmit momentum in a direction
 perpendicular to the direction of velocity or momentum flow.
 Alternatively it is the resistance the fluid has to being sheared.  It
 is given by
 </P>
 <P>J = -eta grad(Vstream)
 </P>
 <P>where J is the momentum flux in units of momentum per area per time.
 and grad(Vstream) is the spatial gradient of the velocity of the fluid
 moving in another direction, normal to the area through which the
 momentum flows.  Viscosity thus has units of pressure-time.
 </P>
 <P>The first method is to perform a non-equlibrium MD (NEMD) simulation
 by shearing the simulation box via the <A HREF = "fix_deform.html">fix deform</A>
 command, and using the <A HREF = "fix_nvt_sllod.html">fix nvt/sllod</A> command to
 thermostat the fluid via the SLLOD equations of motion.  The velocity
 profile setup in the fluid by this procedure can be monitored by the
 <A HREF = "fix_ave_spatial.html">fix ave/spatial</A> command, which determines
 grad(Vstream) in the equation above.  E.g. the derivative in the
 y-direction of the Vx component of fluid motion or grad(Vstream) =
 dVx/dy.  In this case, the Pxy off-diagonal component of the pressure
 or stress tensor, as calculated by the <A HREF = "compute_pressure.html">compute
 pressure</A> command, can also be monitored, which
 is the J term in the equation above.  See <A HREF = "Section_howto.html#howto_13">this
 section</A> of the manual for details on NEMD
 simulations.
 </P>
 <P>The second method is to perform a reverse non-equilibrium MD
 simulation using the <A HREF = "fix_viscosity.html">fix viscosity</A> command which
 implements the rNEMD algorithm of Muller-Plathe.  Momentum in one
 dimension is swapped between atoms in two different layers of the
 simulation box in a different dimension.  This induces a velocity
 gradient which can be monitored with the <A HREF = "fix_ave_spatial.html">fix
 ave/spatial</A> command.  The fix tallies the
 cummulative momentum transfer that it performs.  See the <A HREF = "fix_viscosity.html">fix
 viscosity</A> command for details.
 </P>
 <P>The third method is based on the Green-Kubo (GK) formula which relates
 the ensemble average of the auto-correlation of the stress/pressure
 tensor to eta.  This can be done in a steady-state equilibrated
 simulation which is in contrast to the two preceding non-equilibrium
 methods, where momentum flows continuously through the simulation box.
 </P>
 <P>Here is an example input script that calculates the viscosity of
 liquid Ar via the GK formalism:
 </P>
 <PRE># Sample LAMMPS input script for viscosity of liquid Ar 
 </PRE>
 <PRE>units       real
 variable    T equal 86.4956
 variable    V equal vol
 variable    dt equal 4.0
 variable    p equal 400     # correlation length
 variable    s equal 5       # sample interval
 variable    d equal $p*$s   # dump interval 
 </PRE>
 <PRE># convert from LAMMPS real units to SI 
 </PRE>
 <PRE>variable    kB equal 1.3806504e-23    # [J/K/</B> Boltzmann
 variable    atm2Pa equal 101325.0
 variable    A2m equal 1.0e-10
 variable    fs2s equal 1.0e-15
 variable    convert equal ${atm2Pa}*${atm2Pa}*${fs2s}*${A2m}*${A2m}*${A2m} 
 </PRE>
 <PRE># setup problem 
 </PRE>
 <PRE>dimension    3
 boundary     p p p
 lattice      fcc 5.376 orient x 1 0 0 orient y 0 1 0 orient z 0 0 1
 region       box block 0 4 0 4 0 4
 create_box   1 box
 create_atoms 1 box
 mass	     1 39.948
 pair_style   lj/cut 13.0
 pair_coeff   * * 0.2381 3.405
 timestep     ${dt}
 thermo	     $d 
 </PRE>
 <PRE># equilibration and thermalization 
 </PRE>
 <PRE>velocity     all create $T 102486 mom yes rot yes dist gaussian
 fix          NVT all nvt temp $T $T 10 drag 0.2
 run          8000 
 </PRE>
 <PRE># viscosity calculation, switch to NVE if desired 
 </PRE>
 <PRE>#unfix       NVT
 #fix         NVE all nve 
 </PRE>
 <PRE>reset_timestep 0
 variable     pxy equal pxy
 variable     pxz equal pxz
 variable     pyz equal pyz
 fix          SS all ave/correlate $s $p $d &
              v_pxy v_pxz v_pyz type auto file S0St.dat ave running
 variable     scale equal ${convert}/(${kB}*$T)*$V*$s*${dt}
 variable     v11 equal trap(f_SS[3/</B>)*${scale}
 variable     v22 equal trap(f_SS[4/</B>)*${scale}
 variable     v33 equal trap(f_SS[5/</B>)*${scale}
 thermo_style custom step temp press v_pxy v_pxz v_pyz v_v11 v_v22 v_v33
 run          100000
 variable     v equal (v_v11+v_v22+v_v33)/3.0
 variable     ndens equal count(all)/vol
 print        "average viscosity: $v [Pa.s/</B> @ $T K, ${ndens} /A^3" 
 </PRE>
 <HR>
 
 <HR>
 
 <A NAME = "Berendsen"></A>
 
 <P><B>(Berendsen)</B> Berendsen, Grigera, Straatsma, J Phys Chem, 91,
 6269-6271 (1987).
 </P>
 <A NAME = "Cornell"></A>
 
 <P><B>(Cornell)</B> Cornell, Cieplak, Bayly, Gould, Merz, Ferguson,
 Spellmeyer, Fox, Caldwell, Kollman, JACS 117, 5179-5197 (1995).
 </P>
 <A NAME = "Horn"></A>
 
 <P><B>(Horn)</B> Horn, Swope, Pitera, Madura, Dick, Hura, and Head-Gordon,
 J Chem Phys, 120, 9665 (2004).
 </P>
 <A NAME = "Ikeshoji"></A>
 
 <P><B>(Ikeshoji)</B> Ikeshoji and Hafskjold, Molecular Physics, 81, 251-261
 (1994).
 </P>
 <A NAME = "MacKerell"></A>
 
 <P><B>(MacKerell)</B> MacKerell, Bashford, Bellott, Dunbrack, Evanseck, Field,
 Fischer, Gao, Guo, Ha, et al, J Phys Chem, 102, 3586 (1998).
 </P>
 <A NAME = "Mayo"></A>
 
 <P><B>(Mayo)</B> Mayo, Olfason, Goddard III, J Phys Chem, 94, 8897-8909
 (1990).
 </P>
 <A NAME = "Jorgensen"></A>
 
 <P><B>(Jorgensen)</B> Jorgensen, Chandrasekhar, Madura, Impey, Klein, J Chem
 Phys, 79, 926 (1983).
 </P>
 <A NAME = "Price"></A>
 
 <P><B>(Price)</B> Price and Brooks, J Chem Phys, 121, 10096 (2004).
 </P>
 <A NAME = "Shinoda"></A>
 
 <P><B>(Shinoda)</B> Shinoda, Shiga, and Mikami, Phys Rev B, 69, 134103 (2004).
 </P>
 </HTML>
diff --git a/doc/kspace_modify.html b/doc/kspace_modify.html
index 44ff5d864..266a54b48 100644
--- a/doc/kspace_modify.html
+++ b/doc/kspace_modify.html
@@ -1,121 +1,131 @@
 <HTML>
 <CENTER><A HREF = "http://lammps.sandia.gov">LAMMPS WWW Site</A> - <A HREF = "Manual.html">LAMMPS Documentation</A> - <A HREF = "Section_commands.html#comm">LAMMPS Commands</A> 
 </CENTER>
 
 
 
 
 
 
 <HR>
 
 <H3>kspace_modify command 
 </H3>
 <P><B>Syntax:</B>
 </P>
 <PRE>kspace_modify keyword value ... 
 </PRE>
 <UL><LI>one or more keyword/value pairs may be listed 
 
 <LI>keyword = <I>mesh</I> or <I>order</I> or <I>gewald</I> or <I>slab</I> 
 
 <PRE>  <I>mesh</I> value = x y z
     x,y,z = PPPM FFT grid size in each dimension
   <I>order</I> value = N
     N = grid extent of Gaussian for PPPM mapping of each charge
   <I>force</I> value = accuracy (force units)
   <I>gewald</I> value = rinv (1/distance units)
     rinv = PPPM G-ewald parameter
   <I>slab</I> value = volfactor
     volfactor = ratio of the total extended volume used in the
-      2d approximation compared with the volume of the simulation domain 
+      2d approximation compared with the volume of the simulation domain
+  <I>compute</I> value = <I>yes</I> or <I>no</I> 
 </PRE>
 
 </UL>
 <P><B>Examples:</B>
 </P>
 <PRE>kspace_modify mesh 24 24 30 order 6
 kspace_modify slab 3.0 
 </PRE>
 <P><B>Description:</B>
 </P>
 <P>Set parameters used by the kspace solvers defined by the
 <A HREF = "kspace_style.html">kspace_style</A> command.  Not all parameters are
 relevant to all kspace styles.
 </P>
 <P>The <I>mesh</I> keyword sets the 3d FFT grid size for kspace style pppm.
 Each dimension must be factorizable into powers of 2, 3, and 5.  When
 this option is not set, the PPPM solver chooses its own grid size,
 consistent with the user-specified accuracy and pairwise cutoff.
 Values for x,y,z of 0,0,0 unset the option.
 </P>
 <P>The <I>order</I> keyword determines how many grid spacings an atom's charge
 extends when it is mapped to the FFT grid in kspace style pppm.  The
 default for this parameter is 5, which means each charge spans 5 grid
 cells in each dimension.  The larger the value of this parameter, the
 smaller the FFT grid will need to be to achieve the requested
 precision.  Conversely, the smaller the order value, the larger the
 grid will be.  Note that there is an inherent trade-off involved: a
 small grid will lower the cost of FFTs, but a large order parameter
 will increase the cost of intepolating charge/fields to/from the grid.
 And vice versa.
 </P>
 <P>The order parameter may be reset by LAMMPS when it sets up the PPPM
 FFT grid if the implied grid stencil extends beyond the grid cells
 owned by neighboring processors.  Typically this will only occur when
 small problems are run on large numbers of processors.  A warning will
 be generated indicating the order parameter is being reduced to allow
 LAMMPS to run the problem.
 </P>
 <P>The <I>force</I> keyword overrides the relative accuracy parameter set by
 the <A HREF = "kspace_style.html">kspace_style</A> command with an absolute
 accuracy.  The accuracy determines the RMS error in per-atom forces
 calculated by the long-range solver and is thus specified in force
 units.  A negative value for the accuracy setting means to use the
 relative accuracy parameter.  The accuracy setting is used in
 conjunction with the pairwise cutoff to determine the number of
 K-space vectors for style <I>ewald</I> or the FFT grid size for style
 <I>pppm</I>.
 </P>
 <P>The <I>gewald</I> keyword sets the value of the Ewald or PPPM G-ewald
 parameter as <I>rinv</I> in reciprocal distance units.  Without this
 setting, LAMMPS chooses the parameter automatically as a function of
 cutoff, precision, grid spacing, etc.  This means it can vary from one
 simulation to the next which may not be desirable for matching a
 KSpace solver to a pre-tabulated pairwise potential.  This setting can
 also be useful if Ewald or PPPM fails to choose a good grid spacing
 and G-ewald parameter automatically.  If the value is set to 0.0,
 LAMMPS will choose the G-ewald parameter automatically.
 </P>
 <P>The <I>slab</I> keyword allows an Ewald or PPPM solver to be used for a
 systems that are periodic in x,y but non-periodic in z - a
 <A HREF = "boundary.html">boundary</A> setting of "boundary p p f".  This is done by
 treating the system as if it were periodic in z, but inserting empty
 volume between atom slabs and removing dipole inter-slab interactions
 so that slab-slab interactions are effectively turned off.  The
 volfactor value sets the ratio of the extended dimension in z divided
 by the actual dimension in z.  The recommended value is 3.0.  A larger
 value is inefficient; a smaller value introduces unwanted slab-slab
 interactions.  The use of fixed boundaries in z means that the user
 must prevent particle migration beyond the initial z-bounds, typically
 by providing a wall-style fix.  The methodology behind the <I>slab</I>
 option is explained in the paper by <A HREF = "#Yeh">(Yeh)</A>.
 </P>
+<P>The <I>compute</I> keyword allows Kspace computations to be turned off,
+even though a <A HREF = "kspace_style.html">kspace_style</A> is defined.  This is
+not useful for running a real simulation, but can be useful for
+debugging purposes or for computing only partial forces that do not
+include the Kspace contribution.  You can also do this by simply not
+defining a <A HREF = "kspace_style.html">kspace_style</A>, but a Kspace-compatible
+<A HREF = "pair_style.html">pair_style</A> requires a kspace_style to be defined.
+This keyword gives you that option.
+</P>
 <P><B>Restrictions:</B> none
 </P>
 <P><B>Related commands:</B>
 </P>
 <P><A HREF = "kspace_style.html">kspace_style</A>, <A HREF = "boundary.html">boundary</A>
 </P>
 <P><B>Default:</B>
 </P>
 <P>The option defaults are mesh = 0 0 0, order = 5, force = -1.0, gewald
-= 0.0, and slab = 1.0.
+= 0.0, slab = 1.0, and compute = yes.
 </P>
 <HR>
 
 <A NAME = "Yeh"></A>
 
 <P><B>(Yeh)</B> Yeh and Berkowitz, J Chem Phys, 111, 3155 (1999).
 </P>
 </HTML>
diff --git a/doc/kspace_modify.txt b/doc/kspace_modify.txt
index 6a4b54d93..b679c67e5 100644
--- a/doc/kspace_modify.txt
+++ b/doc/kspace_modify.txt
@@ -1,112 +1,122 @@
 "LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
 
 :link(lws,http://lammps.sandia.gov)
 :link(ld,Manual.html)
 :link(lc,Section_commands.html#comm)
 
 :line
 
 kspace_modify command :h3
 
 [Syntax:]
 
 kspace_modify keyword value ... :pre
 
 one or more keyword/value pairs may be listed :ulb,l
 keyword = {mesh} or {order} or {gewald} or {slab} :l
   {mesh} value = x y z
     x,y,z = PPPM FFT grid size in each dimension
   {order} value = N
     N = grid extent of Gaussian for PPPM mapping of each charge
   {force} value = accuracy (force units)
   {gewald} value = rinv (1/distance units)
     rinv = PPPM G-ewald parameter
   {slab} value = volfactor
     volfactor = ratio of the total extended volume used in the
-      2d approximation compared with the volume of the simulation domain :pre
+      2d approximation compared with the volume of the simulation domain
+  {compute} value = {yes} or {no} :pre
 :ule
 
 [Examples:]
 
 kspace_modify mesh 24 24 30 order 6
 kspace_modify slab 3.0 :pre
 
 [Description:]
 
 Set parameters used by the kspace solvers defined by the
 "kspace_style"_kspace_style.html command.  Not all parameters are
 relevant to all kspace styles.
 
 The {mesh} keyword sets the 3d FFT grid size for kspace style pppm.
 Each dimension must be factorizable into powers of 2, 3, and 5.  When
 this option is not set, the PPPM solver chooses its own grid size,
 consistent with the user-specified accuracy and pairwise cutoff.
 Values for x,y,z of 0,0,0 unset the option.
 
 The {order} keyword determines how many grid spacings an atom's charge
 extends when it is mapped to the FFT grid in kspace style pppm.  The
 default for this parameter is 5, which means each charge spans 5 grid
 cells in each dimension.  The larger the value of this parameter, the
 smaller the FFT grid will need to be to achieve the requested
 precision.  Conversely, the smaller the order value, the larger the
 grid will be.  Note that there is an inherent trade-off involved: a
 small grid will lower the cost of FFTs, but a large order parameter
 will increase the cost of intepolating charge/fields to/from the grid.
 And vice versa.
 
 The order parameter may be reset by LAMMPS when it sets up the PPPM
 FFT grid if the implied grid stencil extends beyond the grid cells
 owned by neighboring processors.  Typically this will only occur when
 small problems are run on large numbers of processors.  A warning will
 be generated indicating the order parameter is being reduced to allow
 LAMMPS to run the problem.
 
 The {force} keyword overrides the relative accuracy parameter set by
 the "kspace_style"_kspace_style.html command with an absolute
 accuracy.  The accuracy determines the RMS error in per-atom forces
 calculated by the long-range solver and is thus specified in force
 units.  A negative value for the accuracy setting means to use the
 relative accuracy parameter.  The accuracy setting is used in
 conjunction with the pairwise cutoff to determine the number of
 K-space vectors for style {ewald} or the FFT grid size for style
 {pppm}.
 
 The {gewald} keyword sets the value of the Ewald or PPPM G-ewald
 parameter as {rinv} in reciprocal distance units.  Without this
 setting, LAMMPS chooses the parameter automatically as a function of
 cutoff, precision, grid spacing, etc.  This means it can vary from one
 simulation to the next which may not be desirable for matching a
 KSpace solver to a pre-tabulated pairwise potential.  This setting can
 also be useful if Ewald or PPPM fails to choose a good grid spacing
 and G-ewald parameter automatically.  If the value is set to 0.0,
 LAMMPS will choose the G-ewald parameter automatically.
 
 The {slab} keyword allows an Ewald or PPPM solver to be used for a
 systems that are periodic in x,y but non-periodic in z - a
 "boundary"_boundary.html setting of "boundary p p f".  This is done by
 treating the system as if it were periodic in z, but inserting empty
 volume between atom slabs and removing dipole inter-slab interactions
 so that slab-slab interactions are effectively turned off.  The
 volfactor value sets the ratio of the extended dimension in z divided
 by the actual dimension in z.  The recommended value is 3.0.  A larger
 value is inefficient; a smaller value introduces unwanted slab-slab
 interactions.  The use of fixed boundaries in z means that the user
 must prevent particle migration beyond the initial z-bounds, typically
 by providing a wall-style fix.  The methodology behind the {slab}
 option is explained in the paper by "(Yeh)"_#Yeh.
 
+The {compute} keyword allows Kspace computations to be turned off,
+even though a "kspace_style"_kspace_style.html is defined.  This is
+not useful for running a real simulation, but can be useful for
+debugging purposes or for computing only partial forces that do not
+include the Kspace contribution.  You can also do this by simply not
+defining a "kspace_style"_kspace_style.html, but a Kspace-compatible
+"pair_style"_pair_style.html requires a kspace_style to be defined.
+This keyword gives you that option.
+
 [Restrictions:] none
 
 [Related commands:]
 
 "kspace_style"_kspace_style.html, "boundary"_boundary.html
 
 [Default:]
 
 The option defaults are mesh = 0 0 0, order = 5, force = -1.0, gewald
-= 0.0, and slab = 1.0.
+= 0.0, slab = 1.0, and compute = yes.
 
 :line
 
 :link(Yeh)
 [(Yeh)] Yeh and Berkowitz, J Chem Phys, 111, 3155 (1999).
diff --git a/doc/pair_modify.html b/doc/pair_modify.html
index 4aa2b2648..8e163f6aa 100644
--- a/doc/pair_modify.html
+++ b/doc/pair_modify.html
@@ -1,175 +1,185 @@
 <HTML>
 <CENTER><A HREF = "http://lammps.sandia.gov">LAMMPS WWW Site</A> - <A HREF = "Manual.html">LAMMPS Documentation</A> - <A HREF = "Section_commands.html#comm">LAMMPS Commands</A> 
 </CENTER>
 
 
 
 
 
 
 <HR>
 
 <H3>pair_modify command 
 </H3>
 <P><B>Syntax:</B>
 </P>
 <PRE>pair_modify keyword value ... 
 </PRE>
 <UL><LI>one or more keyword/value pairs may be listed 
 
-<LI>keyword = <I>shift</I> or <I>mix</I> or <I>table</I> or <I>tabinner</I> or <I>tail</I> 
+<LI>keyword = <I>shift</I> or <I>mix</I> or <I>table</I> or <I>tabinner</I> or <I>tail</I> or <I>compute</I> 
 
 <PRE>  <I>mix</I> value = <I>geometric</I> or <I>arithmetic</I> or <I>sixthpower</I>
   <I>shift</I> value = <I>yes</I> or <I>no</I>
   <I>table</I> value = N
     2^N = # of values in table
   <I>tabinner</I> value = cutoff
     cutoff = inner cutoff at which to begin table (distance units)
-  <I>tail</I> value = <I>yes</I> or <I>no</I> 
+  <I>tail</I> value = <I>yes</I> or <I>no</I>
+  <I>compute</I> value = <I>yes</I> or <I>no</I> 
 </PRE>
 
 </UL>
 <P><B>Examples:</B>
 </P>
 <PRE>pair_modify shift yes mix geometric
 pair_modify tail yes
 pair_modify table 12 
 </PRE>
 <P><B>Description:</B>
 </P>
 <P>Modify the parameters of the currently defined pair style.  Not all
 parameters are relevant to all pair styles.
 </P>
 <P>The <I>mix</I> keyword affects pair coefficients for interactions between
 atoms of type I and J, when I != J and the coefficients are not
 explicitly set in the input script.  Note that coefficients for I = J
 must be set explicitly, either in the input script via the
 "pair_coeff" command or in the "Pair Coeffs" section of the <A HREF = "read_data.html">data
 file</A>.  For some pair styles it is not necessary to
 specify coefficients when I != J, since a "mixing" rule will create
 them from the I,I and J,J settings.  The pair_modify <I>mix</I> value
 determines what formulas are used to compute the mixed coefficients.
 In each case, the cutoff distance is mixed the same way as sigma.
 </P>
 <P>Note that not all pair styles support mixing.  Also, some mix options
 are not available for certain pair styles.  See the doc page for
 individual pair styles for those restrictions.  Note also that the
 <A HREF = "pair_coeff.html">pair_coeff</A> command also can be to directly set
 coefficients for a specific I != J pairing, in which case no mixing is
 performed.
 </P>
 <P>mix <I>geometric</I>
 </P>
 <PRE>epsilon_ij = sqrt(epsilon_i * epsilon_j)
 sigma_ij = sqrt(sigma_i * sigma_j) 
 </PRE>
 <P>mix <I>arithmetic</I>
 </P>
 <PRE>epsilon_ij = sqrt(epsilon_i * epsilon_j)
 sigma_ij = (sigma_i + sigma_j) / 2 
 </PRE>
 <P>mix <I>sixthpower</I>
 </P>
 <PRE>epsilon_ij = (2 * sqrt(epsilon_i*epsilon_j) * sigma_i^3 * sigma_j^3) /
              (sigma_i^6 + sigma_j^6)
 sigma_ij = ((sigma_i**6 + sigma_j**6) / 2) ^ (1/6) 
 </PRE>
 <P>The <I>shift</I> keyword determines whether a Lennard-Jones potential is
 shifted at its cutoff to 0.0.  If so, this adds an energy term to each
 pairwise interaction which will be included in the thermodynamic
 output, but does not affect pair forces or atom trajectories.  See the
 doc page for individual pair styles to see which ones support this
 option.
 </P>
 <P>The <I>table</I> keyword applies to pair styles with a long-range Coulombic
 term; see the doc page for individual styles to see which potentials
 support this option.  If N is non-zero, a table of length 2^N is
 pre-computed for forces and energies, which can shrink their
 computational cost by up to a factor of 2.  The table is indexed via a
 bit-mapping technique <A HREF = "#Wolff">(Wolff)</A> and a linear interpolation is
 performed between adjacent table values.  In our experiments with
 different table styles (lookup, linear, spline), this method typically
 gave the best performance in terms of speed and accuracy.
 </P>
 <P>The choice of table length is a tradeoff in accuracy versus speed.  A
 larger N yields more accurate force computations, but requires more
 memory which can slow down the computation due to cache misses.  A
 reasonable value of N is between 8 and 16.  The default value of 12
 (table of length 4096) gives approximately the same accuracy as the
 no-table (N = 0) option.  For N = 0, forces and energies are computed
 directly, using a polynomial fit for the needed erfc() function
 evaluation, which is what earlier versions of LAMMPS did.  Values
 greater than 16 typically slow down the simulation and will not
 improve accuracy; values from 1 to 8 give unreliable results.
 </P>
 <P>The <I>tabinner</I> keyword sets an inner cutoff above which the pairwise
 computation is done by table lookup (if tables are invoked).  The
 smaller this value is set, the less accurate the table becomes (for a
 given number of table values), which can require use of larger tables.
 The default cutoff value is sqrt(2.0) distance units which means
 nearly all pairwise interactions are computed via table lookup for
 simulations with "real" units, but some close pairs may be computed
 directly (non-table) for simulations with "lj" units.
 </P>
 <P>When the <I>tail</I> keyword is set to <I>yes</I>, certain pair styles will add
 a long-range VanderWaals tail "correction" to the energy and pressure.
 See the doc page for individual styles to see which support this
 option.  These corrections are included in the calculation and
 printing of thermodynamic quantities (see the
 <A HREF = "thermo_style.html">thermo_style</A> command).  Their effect will also be
 included in constant NPT or NPH simulations where the pressure
 influences the simulation box dimensions (e.g. the <A HREF = "fix_nh.html">fix
 npt</A> and <A HREF = "fix_nh.html">fix nph</A> commands).  The formulas
 used for the long-range corrections come from equation 5 of
 <A HREF = "#Sun">(Sun)</A>.
 </P>
 <P>Several assumptions are inherent in using tail corrections, including
 the following:
 </P>
 <UL><LI>The simulated system is a 3d bulk homogeneous liquid. This option
 should not be used for systems that are non-liquid, 2d, have a slab
 geometry (only 2d periodic), or inhomogeneous. 
 
 <LI>G(r), the radial distribution function (rdf), is unity beyond the
 cutoff, so a fairly large cutoff should be used (i.e. 2.5 sigma for an
 LJ fluid), and it is probably a good idea to verify this assumption by
 checking the rdf.  The rdf is not exactly unity beyond the cutoff for
 each pair of interaction types, so the tail correction is necessarily
 an approximation. 
 
 <LI>Thermophysical properties obtained from calculations with this option
 enabled will not be thermodynamically consistent with the truncated
 force-field that was used.  In other words, atoms do not feel any LJ
 pair interactions beyond the cutoff, but the energy and pressure
 reported by the simulation include an estimated contribution from
 those interactions. 
 </UL>
+<P>The <I>compute</I> keyword allows pairwise computations to be turned off,
+even though a <A HREF = "pair_style.html">pair_style</A> is defined.  This is not
+useful for running a real simulation, but can be useful for debugging
+purposes or for computing only partial forces that do not include the
+pairwise contribution.  You can also do this by simply not defining a
+<A HREF = "pair_style.html">pair_style</A>, but a Kspace-compatible pair_style is
+required if you also want to define a
+<A HREF = "kspace_style.html">kspace_style</A>.  This keyword gives you that option.
+</P>
 <P><B>Restrictions:</B> none
 </P>
 <P>You cannot use <I>shift</I> yes with <I>tail</I> yes, since those are
 conflicting options.  You cannot use <I>tail</I> yes with 2d simulations.
 </P>
 <P><B>Related commands:</B>
 </P>
 <P><A HREF = "pair_style.html">pair_style</A>, <A HREF = "pair_coeff.html">pair_coeff</A>,
 <A HREF = "thermo_style.html">thermo_style</A>
 </P>
 <P><B>Default:</B>
 </P>
 <P>The option defaults are mix = geometric, shift = no, table = 12,
-tabinner = sqrt(2.0), tail = no.
+tabinner = sqrt(2.0), tail = no, and compute = yes.
 </P>
 <P>Note that some pair styles perform mixing, but only a certain style of
 mixing.  See the doc pages for individual pair styles for details.
 </P>
 <HR>
 
 <A NAME = "Wolff"></A>
 
 <P><B>(Wolff)</B> Wolff and Rudd, Comp Phys Comm, 120, 200-32 (1999).
 </P>
 <A NAME = "Sun"></A>
 
 <P><B>(Sun)</B> Sun, J Phys Chem B, 102, 7338-7364 (1998).
 </P>
 </HTML>
diff --git a/doc/pair_modify.txt b/doc/pair_modify.txt
index b09044548..2614e93db 100644
--- a/doc/pair_modify.txt
+++ b/doc/pair_modify.txt
@@ -1,165 +1,175 @@
 "LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
 
 :link(lws,http://lammps.sandia.gov)
 :link(ld,Manual.html)
 :link(lc,Section_commands.html#comm)
 
 :line
 
 pair_modify command :h3
 
 [Syntax:]
 
 pair_modify keyword value ... :pre
 
 one or more keyword/value pairs may be listed :ulb,l
-keyword = {shift} or {mix} or {table} or {tabinner} or {tail} :l
+keyword = {shift} or {mix} or {table} or {tabinner} or {tail} or {compute} :l
   {mix} value = {geometric} or {arithmetic} or {sixthpower}
   {shift} value = {yes} or {no}
   {table} value = N
     2^N = # of values in table
   {tabinner} value = cutoff
     cutoff = inner cutoff at which to begin table (distance units)
-  {tail} value = {yes} or {no} :pre
+  {tail} value = {yes} or {no}
+  {compute} value = {yes} or {no} :pre
 :ule
 
 [Examples:]
 
 pair_modify shift yes mix geometric
 pair_modify tail yes
 pair_modify table 12 :pre
 
 [Description:]
 
 Modify the parameters of the currently defined pair style.  Not all
 parameters are relevant to all pair styles.
 
 The {mix} keyword affects pair coefficients for interactions between
 atoms of type I and J, when I != J and the coefficients are not
 explicitly set in the input script.  Note that coefficients for I = J
 must be set explicitly, either in the input script via the
 "pair_coeff" command or in the "Pair Coeffs" section of the "data
 file"_read_data.html.  For some pair styles it is not necessary to
 specify coefficients when I != J, since a "mixing" rule will create
 them from the I,I and J,J settings.  The pair_modify {mix} value
 determines what formulas are used to compute the mixed coefficients.
 In each case, the cutoff distance is mixed the same way as sigma.
 
 Note that not all pair styles support mixing.  Also, some mix options
 are not available for certain pair styles.  See the doc page for
 individual pair styles for those restrictions.  Note also that the
 "pair_coeff"_pair_coeff.html command also can be to directly set
 coefficients for a specific I != J pairing, in which case no mixing is
 performed.
 
 mix {geometric}
 
 epsilon_ij = sqrt(epsilon_i * epsilon_j)
 sigma_ij = sqrt(sigma_i * sigma_j) :pre
 
 mix {arithmetic}
 
 epsilon_ij = sqrt(epsilon_i * epsilon_j)
 sigma_ij = (sigma_i + sigma_j) / 2 :pre
 
 mix {sixthpower}
 
 epsilon_ij = (2 * sqrt(epsilon_i*epsilon_j) * sigma_i^3 * sigma_j^3) /
              (sigma_i^6 + sigma_j^6)
 sigma_ij = ((sigma_i**6 + sigma_j**6) / 2) ^ (1/6) :pre
 
 The {shift} keyword determines whether a Lennard-Jones potential is
 shifted at its cutoff to 0.0.  If so, this adds an energy term to each
 pairwise interaction which will be included in the thermodynamic
 output, but does not affect pair forces or atom trajectories.  See the
 doc page for individual pair styles to see which ones support this
 option.
 
 The {table} keyword applies to pair styles with a long-range Coulombic
 term; see the doc page for individual styles to see which potentials
 support this option.  If N is non-zero, a table of length 2^N is
 pre-computed for forces and energies, which can shrink their
 computational cost by up to a factor of 2.  The table is indexed via a
 bit-mapping technique "(Wolff)"_#Wolff and a linear interpolation is
 performed between adjacent table values.  In our experiments with
 different table styles (lookup, linear, spline), this method typically
 gave the best performance in terms of speed and accuracy.
 
 The choice of table length is a tradeoff in accuracy versus speed.  A
 larger N yields more accurate force computations, but requires more
 memory which can slow down the computation due to cache misses.  A
 reasonable value of N is between 8 and 16.  The default value of 12
 (table of length 4096) gives approximately the same accuracy as the
 no-table (N = 0) option.  For N = 0, forces and energies are computed
 directly, using a polynomial fit for the needed erfc() function
 evaluation, which is what earlier versions of LAMMPS did.  Values
 greater than 16 typically slow down the simulation and will not
 improve accuracy; values from 1 to 8 give unreliable results.
 
 The {tabinner} keyword sets an inner cutoff above which the pairwise
 computation is done by table lookup (if tables are invoked).  The
 smaller this value is set, the less accurate the table becomes (for a
 given number of table values), which can require use of larger tables.
 The default cutoff value is sqrt(2.0) distance units which means
 nearly all pairwise interactions are computed via table lookup for
 simulations with "real" units, but some close pairs may be computed
 directly (non-table) for simulations with "lj" units.
 
 When the {tail} keyword is set to {yes}, certain pair styles will add
 a long-range VanderWaals tail "correction" to the energy and pressure.
 See the doc page for individual styles to see which support this
 option.  These corrections are included in the calculation and
 printing of thermodynamic quantities (see the
 "thermo_style"_thermo_style.html command).  Their effect will also be
 included in constant NPT or NPH simulations where the pressure
 influences the simulation box dimensions (e.g. the "fix
 npt"_fix_nh.html and "fix nph"_fix_nh.html commands).  The formulas
 used for the long-range corrections come from equation 5 of
 "(Sun)"_#Sun.
 
 Several assumptions are inherent in using tail corrections, including
 the following:
 
 The simulated system is a 3d bulk homogeneous liquid. This option
 should not be used for systems that are non-liquid, 2d, have a slab
 geometry (only 2d periodic), or inhomogeneous. :ulb,l
 
 G(r), the radial distribution function (rdf), is unity beyond the
 cutoff, so a fairly large cutoff should be used (i.e. 2.5 sigma for an
 LJ fluid), and it is probably a good idea to verify this assumption by
 checking the rdf.  The rdf is not exactly unity beyond the cutoff for
 each pair of interaction types, so the tail correction is necessarily
 an approximation. :l
 
 Thermophysical properties obtained from calculations with this option
 enabled will not be thermodynamically consistent with the truncated
 force-field that was used.  In other words, atoms do not feel any LJ
 pair interactions beyond the cutoff, but the energy and pressure
 reported by the simulation include an estimated contribution from
 those interactions. :l,ule
 
+The {compute} keyword allows pairwise computations to be turned off,
+even though a "pair_style"_pair_style.html is defined.  This is not
+useful for running a real simulation, but can be useful for debugging
+purposes or for computing only partial forces that do not include the
+pairwise contribution.  You can also do this by simply not defining a
+"pair_style"_pair_style.html, but a Kspace-compatible pair_style is
+required if you also want to define a
+"kspace_style"_kspace_style.html.  This keyword gives you that option.
+
 [Restrictions:] none
 
 You cannot use {shift} yes with {tail} yes, since those are
 conflicting options.  You cannot use {tail} yes with 2d simulations.
 
 [Related commands:]
 
 "pair_style"_pair_style.html, "pair_coeff"_pair_coeff.html,
 "thermo_style"_thermo_style.html
 
 [Default:]
 
 The option defaults are mix = geometric, shift = no, table = 12,
-tabinner = sqrt(2.0), tail = no.
+tabinner = sqrt(2.0), tail = no, and compute = yes.
 
 Note that some pair styles perform mixing, but only a certain style of
 mixing.  See the doc pages for individual pair styles for details.
 
 :line
 
 :link(Wolff)
 [(Wolff)] Wolff and Rudd, Comp Phys Comm, 120, 200-32 (1999).
 
 :link(Sun)
 [(Sun)] Sun, J Phys Chem B, 102, 7338-7364 (1998).
diff --git a/src/integrate.cpp b/src/integrate.cpp
index 334333718..beef03c30 100644
--- a/src/integrate.cpp
+++ b/src/integrate.cpp
@@ -1,132 +1,147 @@
 /* ----------------------------------------------------------------------
    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 "stdlib.h"
 #include "integrate.h"
 #include "update.h"
+#include "force.h"
+#include "pair.h"
+#include "kspace.h"
 #include "modify.h"
 #include "compute.h"
 
 using namespace LAMMPS_NS;
 
 /* ---------------------------------------------------------------------- */
 
 Integrate::Integrate(LAMMPS *lmp, int narg, char **arg) : Pointers(lmp)
 {
   elist_global = elist_atom = NULL;
   vlist_global = vlist_atom = NULL;
   external_force_clear = 0;
 }
 
 /* ---------------------------------------------------------------------- */
 
 Integrate::~Integrate()
 {
   delete [] elist_global;
   delete [] elist_atom;
   delete [] vlist_global;
   delete [] vlist_atom;
 }
 
+/* ---------------------------------------------------------------------- */
+
+void Integrate::init()
+{
+  // allow pair and Kspace compute() to be turned off via modify flags
+
+  if (force->pair && force->pair->compute_flag) pair_compute_flag = 1;
+  else pair_compute_flag = 0;
+  if (force->kspace && force->kspace->compute_flag) kspace_compute_flag = 1;
+  else kspace_compute_flag = 0;
+}
+
 /* ----------------------------------------------------------------------
    setup lists of computes for global and per-atom PE and pressure
 ------------------------------------------------------------------------- */
 
 void Integrate::ev_setup()
 {
   delete [] elist_global;
   delete [] elist_atom;
   delete [] vlist_global;
   delete [] vlist_atom;
   elist_global = elist_atom = NULL;
   vlist_global = vlist_atom = NULL;
 
   nelist_global = nelist_atom = 0;
   nvlist_global = nvlist_atom = 0;
   for (int i = 0; i < modify->ncompute; i++) {
     if (modify->compute[i]->peflag) nelist_global++;
     if (modify->compute[i]->peatomflag) nelist_atom++;
     if (modify->compute[i]->pressflag) nvlist_global++;
     if (modify->compute[i]->pressatomflag) nvlist_atom++;
   }
 
   if (nelist_global) elist_global = new Compute*[nelist_global];
   if (nelist_atom) elist_atom = new Compute*[nelist_atom];
   if (nvlist_global) vlist_global = new Compute*[nvlist_global];
   if (nvlist_atom) vlist_atom = new Compute*[nvlist_atom];
 
   nelist_global = nelist_atom = 0;
   nvlist_global = nvlist_atom = 0;
   for (int i = 0; i < modify->ncompute; i++) {
     if (modify->compute[i]->peflag)
       elist_global[nelist_global++] = modify->compute[i];
     if (modify->compute[i]->peatomflag)
       elist_atom[nelist_atom++] = modify->compute[i];
     if (modify->compute[i]->pressflag)
       vlist_global[nvlist_global++] = modify->compute[i];
     if (modify->compute[i]->pressatomflag)
       vlist_atom[nvlist_atom++] = modify->compute[i];
   }
 }
 
 /* ----------------------------------------------------------------------
    set eflag,vflag for current iteration
    invoke matchstep() on all timestep-dependent computes to clear their arrays
    eflag/vflag based on computes that need info on this ntimestep
    eflag = 0 = no energy computation
    eflag = 1 = global energy only
    eflag = 2 = per-atom energy only
    eflag = 3 = both global and per-atom energy
    vflag = 0 = no virial computation (pressure)
    vflag = 1 = global virial with pair portion via sum of pairwise interactions
    vflag = 2 = global virial with pair portion via F dot r including ghosts
    vflag = 4 = per-atom virial only
    vflag = 5 or 6 = both global and per-atom virial
 ------------------------------------------------------------------------- */
 
 void Integrate::ev_set(bigint ntimestep)
 {
   int i,flag;
 
   flag = 0;
   int eflag_global = 0;
   for (i = 0; i < nelist_global; i++)
     if (elist_global[i]->matchstep(ntimestep)) flag = 1;
   if (flag) eflag_global = 1;
 
   flag = 0;
   int eflag_atom = 0;
   for (i = 0; i < nelist_atom; i++)
     if (elist_atom[i]->matchstep(ntimestep)) flag = 1;
   if (flag) eflag_atom = 2;
 
   if (eflag_global) update->eflag_global = ntimestep;
   if (eflag_atom) update->eflag_atom = ntimestep;
   eflag = eflag_global + eflag_atom;
 
   flag = 0;
   int vflag_global = 0;
   for (i = 0; i < nvlist_global; i++)
     if (vlist_global[i]->matchstep(ntimestep)) flag = 1;
   if (flag) vflag_global = virial_style;
 
   flag = 0;
   int vflag_atom = 0;
   for (i = 0; i < nvlist_atom; i++)
     if (vlist_atom[i]->matchstep(ntimestep)) flag = 1;
   if (flag) vflag_atom = 4;
 
   if (vflag_global) update->vflag_global = ntimestep;
   if (vflag_atom) update->vflag_atom = ntimestep;
   vflag = vflag_global + vflag_atom;
 }
diff --git a/src/integrate.h b/src/integrate.h
index 1a8e0124c..7195a677c 100644
--- a/src/integrate.h
+++ b/src/integrate.h
@@ -1,54 +1,57 @@
 /* -*- c++ -*- ----------------------------------------------------------
    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_INTEGRATE_H
 #define LMP_INTEGRATE_H
 
 #include "pointers.h"
 
 namespace LAMMPS_NS {
 
 class Integrate : protected Pointers {
  public:
   Integrate(class LAMMPS *, int, char **);
   virtual ~Integrate();
-  virtual void init() = 0;
+  virtual void init();
   virtual void setup() = 0;
   virtual void setup_minimal(int) = 0;
   virtual void run(int) = 0;
   virtual void cleanup() {}
   virtual void reset_dt() {}
   virtual bigint memory_usage() {return 0;}
 
  protected:
   int eflag,vflag;                  // flags for energy/virial computation
   int virial_style;                 // compute virial explicitly or implicitly
   int external_force_clear;         // clear forces locally or externally
 
   int nelist_global,nelist_atom;    // # of PE,virial computes to check
   int nvlist_global,nvlist_atom;
   class Compute **elist_global;     // lists of PE,virial Computes
   class Compute **elist_atom;
   class Compute **vlist_global;
   class Compute **vlist_atom;
 
+  int pair_compute_flag;            // 0 if pair->compute is skipped
+  int kspace_compute_flag;          // 0 if kspace->compute is skipped
+
   void ev_setup();
   void ev_set(bigint);
 };
 
 }
 
 #endif
 /* ERROR/WARNING messages:
 
 */
diff --git a/src/kspace.cpp b/src/kspace.cpp
index 9913b4480..4c527f887 100644
--- a/src/kspace.cpp
+++ b/src/kspace.cpp
@@ -1,162 +1,180 @@
 /* ----------------------------------------------------------------------
    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 "stdlib.h"
 #include "string.h"
 #include "kspace.h"
 #include "atom.h"
 #include "comm.h"
 #include "force.h"
 #include "memory.h"
 #include "error.h"
 #include "suffix.h"
 
 using namespace LAMMPS_NS;
 
 /* ---------------------------------------------------------------------- */
 
 KSpace::KSpace(LAMMPS *lmp, int narg, char **arg) : Pointers(lmp)
 {
   energy = 0.0;
+  virial[0] = virial[1] = virial[2] = virial[3] = virial[4] = virial[5] = 0.0;
+
+  compute_flag = 1;
   order = 5;
   gridflag = 0;
   gewaldflag = 0;
   slabflag = 0;
   slab_volfactor = 1;
   suffix_flag = Suffix::NONE;
 
   accuracy_absolute = -1.0;
   two_charge_force = force->qqr2e * 
     (force->qelectron * force->qelectron) / 
     (force->angstrom * force->angstrom);
 
   maxeatom = maxvatom = 0;
   eatom = NULL;
   vatom = NULL;
 }
 
 /* ---------------------------------------------------------------------- */
 
 KSpace::~KSpace()
 {
   memory->destroy(eatom);
   memory->destroy(vatom);
 }
 
+/* ---------------------------------------------------------------------- */
+
+void KSpace::compute_dummy(int eflag, int vflag)
+{
+  if (eflag || vflag) ev_setup(eflag,vflag);
+  else evflag = evflag_atom = eflag_global = vflag_global = 
+	 eflag_atom = vflag_atom = 0;
+}
+
 /* ----------------------------------------------------------------------
    setup for energy, virial computation
    see integrate::ev_set() for values of eflag (0-3) and vflag (0-6)
 ------------------------------------------------------------------------- */
 
 void KSpace::ev_setup(int eflag, int vflag)
 {
   int i,n;
 
   evflag = 1;
 
   eflag_either = eflag;
   eflag_global = eflag % 2;
   eflag_atom = eflag / 2;
 
   vflag_either = vflag;
   vflag_global = vflag % 4;
   vflag_atom = vflag / 4;
   
   if (eflag_atom || vflag_atom) evflag_atom = 1;
   else evflag_atom = 0;
 
   // reallocate per-atom arrays if necessary
 
   if (eflag_atom && atom->nlocal > maxeatom) {
     maxeatom = atom->nmax;
     memory->destroy(eatom);
     memory->create(eatom,maxeatom,"kspace:eatom");
   }
   if (vflag_atom && atom->nlocal > maxvatom) {
     maxvatom = atom->nmax;
     memory->destroy(vatom);
     memory->create(vatom,maxvatom,6,"kspace:vatom");
   }
 
   // zero accumulators
 
   if (eflag_global) energy = 0.0;
   if (vflag_global) for (i = 0; i < 6; i++) virial[i] = 0.0;
   if (eflag_atom) {
     n = atom->nlocal;
     for (i = 0; i < n; i++) eatom[i] = 0.0;
   }
   if (vflag_atom) {
     n = atom->nlocal;
     for (i = 0; i < n; i++) {
       vatom[i][0] = 0.0;
       vatom[i][1] = 0.0;
       vatom[i][2] = 0.0;
       vatom[i][3] = 0.0;
       vatom[i][4] = 0.0;
       vatom[i][5] = 0.0;
     }
   }
 }
 
 /* ----------------------------------------------------------------------
    modify parameters of the KSpace style 
 ------------------------------------------------------------------------- */
 
 void KSpace::modify_params(int narg, char **arg)
 {
   int iarg = 0;
   while (iarg < narg) {
     if (strcmp(arg[iarg],"mesh") == 0) {
       if (iarg+4 > narg) error->all(FLERR,"Illegal kspace_modify command");
       nx_pppm = atoi(arg[iarg+1]);
       ny_pppm = atoi(arg[iarg+2]);
       nz_pppm = atoi(arg[iarg+3]);
       if (nx_pppm == 0 && ny_pppm == 0 && nz_pppm == 0) gridflag = 0;
       else gridflag = 1;
       iarg += 4;
     } else if (strcmp(arg[iarg],"order") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal kspace_modify command");
       order = atoi(arg[iarg+1]);
       iarg += 2;
     } else if (strcmp(arg[iarg],"force") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal kspace_modify command");
       accuracy_absolute = atof(arg[iarg+1]);
       iarg += 2;
     } else if (strcmp(arg[iarg],"gewald") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal kspace_modify command");
       g_ewald = atof(arg[iarg+1]);
       if (g_ewald == 0.0) gewaldflag = 0;
       else gewaldflag = 1;
       iarg += 2;
     } else if (strcmp(arg[iarg],"slab") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal kspace_modify command");
       slab_volfactor = atof(arg[iarg+1]);
       iarg += 2;
       if (slab_volfactor <= 1.0)
 	error->all(FLERR,"Bad kspace_modify slab parameter");
       if (slab_volfactor < 2.0 && comm->me == 0) 
 	error->warning(FLERR,"Kspace_modify slab param < 2.0 may "
 		       "cause unphysical behavior");
       slabflag = 1;
+    } else if (strcmp(arg[iarg],"compute") == 0) {
+      if (iarg+2 > narg) error->all(FLERR,"Illegal kspace_modify command");
+      if (strcmp(arg[iarg+1],"yes") == 0) compute_flag = 1;
+      else if (strcmp(arg[iarg+1],"no") == 0) compute_flag = 0;
+      else error->all(FLERR,"Illegal kspace_modify command");
+      iarg += 2;
     } else error->all(FLERR,"Illegal kspace_modify command");
   }
 }
 
 /* ---------------------------------------------------------------------- */
 
 void *KSpace::extract(const char *str)
 {
   if (strcmp(str,"scale") == 0) return (void *) &scale;
   return NULL;
 }
diff --git a/src/kspace.h b/src/kspace.h
index 30605b419..78c8b477e 100644
--- a/src/kspace.h
+++ b/src/kspace.h
@@ -1,87 +1,92 @@
 /* -*- c++ -*- ----------------------------------------------------------
    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_KSPACE_H
 #define LMP_KSPACE_H
 
 #include "pointers.h"
 
 namespace LAMMPS_NS {
 
 class KSpace : protected Pointers {
   friend class ThrOMP;
   friend class FixOMP;
  public:
   double energy;                  // accumulated energy
   double virial[6];               // accumlated virial
   double *eatom,**vatom;          // accumulated per-atom energy/virial
 
   double g_ewald;
   int nx_pppm,ny_pppm,nz_pppm;
  
+  int compute_flag;               // 0 if skip compute()
+
   KSpace(class LAMMPS *, int, char **);
   virtual ~KSpace();
   void modify_params(int, char **);
   void *extract(const char *);
+  void compute_dummy(int, int);
+
+  // general child-class methods
 
   virtual void init() = 0;
   virtual void setup() = 0;
   virtual void compute(int, int) = 0;
   virtual void timing(int, double &, double &) {}
   virtual double memory_usage() {return 0.0;}
 
  protected:
   int gridflag,gewaldflag;
   int order;
   int slabflag;
   int suffix_flag;                  // suffix compatibility flag
   double scale;
   double slab_volfactor;
  
   double accuracy;                  // accuracy of KSpace solver (force units)
   double accuracy_absolute;         // user-specifed accuracy in force units
   double accuracy_relative;         // user-specified dimensionless accuracy
                                     // accurary = acc_rel * two_charge_force
   double two_charge_force;          // force in user units of two point
                                     // charges separated by 1 Angstrom
 
   int evflag,evflag_atom;
   int eflag_either,eflag_global,eflag_atom;
   int vflag_either,vflag_global,vflag_atom;
   int maxeatom,maxvatom;
 
   void ev_setup(int, int);
 };
 
 }
 
 #endif
 
 /* ERROR/WARNING messages:
 
 E: Illegal ... command
 
 Self-explanatory.  Check the input script syntax and compare to the
 documentation for the command.  You can use -echo screen as a
 command-line option when running LAMMPS to see the offending line.
 
 E: Bad kspace_modify slab parameter
 
 Kspace_modify value for the slab/volume keyword must be >= 2.0.
 
 W: Kspace_modify slab param < 2.0 may cause unphysical behavior
 
 The kspace_modify slab parameter should be larger to insure periodic
 grids padded with empty space do not overlap.
 
 */
diff --git a/src/min.cpp b/src/min.cpp
index 35c33b3c2..7c5d5a2cc 100644
--- a/src/min.cpp
+++ b/src/min.cpp
@@ -1,776 +1,783 @@
 /* ----------------------------------------------------------------------
    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: Aidan Thompson (SNL)
                         improved CG and backtrack ls, added quadratic ls
    Sources: Numerical Recipes frprmn routine
             "Conjugate Gradient Method Without the Agonizing Pain" by
             JR Shewchuk, http://www-2.cs.cmu.edu/~jrs/jrspapers.html#cg
 ------------------------------------------------------------------------- */
 
 #include "math.h"
 #include "stdlib.h"
 #include "string.h"
 #include "min.h"
 #include "atom.h"
 #include "domain.h"
 #include "comm.h"
 #include "update.h"
 #include "modify.h"
 #include "fix_minimize.h"
 #include "compute.h"
 #include "neighbor.h"
 #include "force.h"
 #include "pair.h"
 #include "bond.h"
 #include "angle.h"
 #include "dihedral.h"
 #include "improper.h"
 #include "kspace.h"
 #include "output.h"
 #include "thermo.h"
 #include "timer.h"
 #include "memory.h"
 #include "error.h"
 
 using namespace LAMMPS_NS;
 
 /* ---------------------------------------------------------------------- */
 
 Min::Min(LAMMPS *lmp) : Pointers(lmp)
 {
   dmax = 0.1;
   searchflag = 0;
   linestyle = 0;
 
   elist_global = elist_atom = NULL;
   vlist_global = vlist_atom = NULL;
 
   nextra_global = 0;
   fextra = NULL;
 
   nextra_atom = 0;
   xextra_atom = fextra_atom = NULL;
   extra_peratom = extra_nlen = NULL;
   extra_max = NULL;
   requestor = NULL;
 
   external_force_clear = 0;
 }
 
 /* ---------------------------------------------------------------------- */
 
 Min::~Min()
 {
   delete [] elist_global;
   delete [] elist_atom;
   delete [] vlist_global;
   delete [] vlist_atom;
 
   delete [] fextra;
 
   memory->sfree(xextra_atom);
   memory->sfree(fextra_atom);
   memory->destroy(extra_peratom);
   memory->destroy(extra_nlen);
   memory->destroy(extra_max);
   memory->sfree(requestor);
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Min::init()
 {
   // create fix needed for storing atom-based quantities
   // will delete it at end of run
 
   char **fixarg = new char*[3];
   fixarg[0] = (char *) "MINIMIZE";
   fixarg[1] = (char *) "all";
   fixarg[2] = (char *) "MINIMIZE";
   modify->add_fix(3,fixarg);
   delete [] fixarg;
   fix_minimize = (FixMinimize *) modify->fix[modify->nfix-1];
 
   // clear out extra global and per-atom dof
   // will receive requests for new per-atom dof during pair init()
   // can then add vectors to fix_minimize in setup()
 
   nextra_global = 0;
   delete [] fextra;
   fextra = NULL;
 
   nextra_atom = 0;
   memory->sfree(xextra_atom);
   memory->sfree(fextra_atom);
   memory->destroy(extra_peratom);
   memory->destroy(extra_nlen);
   memory->destroy(extra_max);
   memory->sfree(requestor);
   xextra_atom = fextra_atom = NULL;
   extra_peratom = extra_nlen = NULL;
   extra_max = NULL;
   requestor = NULL;
 
   // virial_style:
   // 1 if computed explicitly by pair->compute via sum over pair interactions
   // 2 if computed implicitly by pair->virial_compute via sum over ghost atoms
 
   if (force->newton_pair) virial_style = 2;
   else virial_style = 1;
 
   // setup lists of computes for global and per-atom PE and pressure
 
   ev_setup();
 
   // detect if fix omp is present for clearing force arrays
 
   int ifix = modify->find_fix("package_omp");
   if (ifix >= 0) external_force_clear = 1;
 
   // set flags for what arrays to clear in force_clear()
   // need to clear additionals arrays if they exist
 
   torqueflag = 0;
   if (atom->torque_flag) torqueflag = 1;
   erforceflag = 0;
   if (atom->erforce_flag) erforceflag = 1;
   e_flag = 0;
   if (atom->e_flag) e_flag = 1;
   rho_flag = 0;
   if (atom->rho_flag) rho_flag = 1;
 
+  // allow pair and Kspace compute() to be turned off via modify flags
+
+  if (force->pair && force->pair->compute_flag) pair_compute_flag = 1;
+  else pair_compute_flag = 0;
+  if (force->kspace && force->kspace->compute_flag) kspace_compute_flag = 1;
+  else kspace_compute_flag = 0;
+
   // orthogonal vs triclinic simulation box
 
   triclinic = domain->triclinic;
 
   // reset reneighboring criteria if necessary
 
   neigh_every = neighbor->every;
   neigh_delay = neighbor->delay;
   neigh_dist_check = neighbor->dist_check;
   
   if (neigh_every != 1 || neigh_delay != 0 || neigh_dist_check != 1) {
     if (comm->me == 0) 
       error->warning(FLERR,
 		     "Resetting reneighboring criteria during minimization");
   }
 
   neighbor->every = 1;
   neighbor->delay = 0;
   neighbor->dist_check = 1;
 
   niter = neval = 0;
-
-  // style-specific initialization
-
-  init_style();
 }
 
 /* ----------------------------------------------------------------------
    setup before run
 ------------------------------------------------------------------------- */
 
 void Min::setup()
 {
   if (comm->me == 0 && screen) fprintf(screen,"Setting up minimization ...\n");
 
   // setup extra global dof due to fixes
   // cannot be done in init() b/c update init() is before modify init()
 
   nextra_global = modify->min_dof();
   if (nextra_global) fextra = new double[nextra_global];
 
   // compute for potential energy
 
   int id = modify->find_compute("thermo_pe");
   if (id < 0) error->all(FLERR,"Minimization could not find thermo_pe compute");
   pe_compute = modify->compute[id];
 
   // style-specific setup does two tasks
   // setup extra global dof vectors
   // setup extra per-atom dof vectors due to requests from Pair classes
   // cannot be done in init() b/c update init() is before modify/pair init()
 
   setup_style();
 
   // ndoftotal = total dof for entire minimization problem
   // dof for atoms, extra per-atom, extra global
 
   bigint ndofme = 3*atom->nlocal;
   for (int m = 0; m < nextra_atom; m++)
     ndofme += extra_peratom[m]*atom->nlocal;
   MPI_Allreduce(&ndofme,&ndoftotal,1,MPI_LMP_BIGINT,MPI_SUM,world);
   ndoftotal += nextra_global;
 
   // setup domain, communication and neighboring
   // acquire ghosts
   // build neighbor lists
 
   atom->setup();
   if (triclinic) domain->x2lamda(atom->nlocal);
   domain->pbc();
   domain->reset_box();
   comm->setup();
   if (neighbor->style) neighbor->setup_bins();
   comm->exchange();
   if (atom->sortfreq > 0) atom->sort();
   comm->borders();
   if (triclinic) domain->lamda2x(atom->nlocal+atom->nghost);
   neighbor->build();
   neighbor->ncalls = 0;
 
   // remove these restriction eventually
 
   if (nextra_global && searchflag == 0)
     error->all(FLERR,
 	       "Cannot use a damped dynamics min style with fix box/relax");
   if (nextra_atom && searchflag == 0)
     error->all(FLERR,
 	       "Cannot use a damped dynamics min style with per-atom DOF");
 
   // atoms may have migrated in comm->exchange()
 
   reset_vectors();
 
   // compute all forces
 
   ev_set(update->ntimestep);
   force_clear();
   modify->setup_pre_force(vflag);
 
-  if (force->pair) force->pair->compute(eflag,vflag);
+  if (pair_compute_flag) force->pair->compute(eflag,vflag);
+  else if (force->pair) force->pair->compute_dummy(eflag,vflag);
 
   if (atom->molecular) {
     if (force->bond) force->bond->compute(eflag,vflag);
     if (force->angle) force->angle->compute(eflag,vflag);
     if (force->dihedral) force->dihedral->compute(eflag,vflag);
     if (force->improper) force->improper->compute(eflag,vflag);
   }
 
   if (force->kspace) {
     force->kspace->setup();
-    force->kspace->compute(eflag,vflag);
+    if (kspace_compute_flag) force->kspace->compute(eflag,vflag);
+    else force->kspace->compute_dummy(eflag,vflag);
   }
 
   if (force->newton) comm->reverse_comm();
 
   // update per-atom minimization variables stored by pair styles
 
   if (nextra_atom)
     for (int m = 0; m < nextra_atom; m++)
       requestor[m]->min_xf_get(m);
 
   modify->setup(vflag);
   output->setup(1);
 
   // stats for Finish to print
 
   ecurrent = pe_compute->compute_scalar();
   if (nextra_global) ecurrent += modify->min_energy(fextra);
   if (output->thermo->normflag) ecurrent /= atom->natoms;
 	
   einitial = ecurrent;
   fnorm2_init = sqrt(fnorm_sqr());
   fnorminf_init = fnorm_inf();
 }
 
 /* ----------------------------------------------------------------------
    setup without output or one-time post-init setup
    flag = 0 = just force calculation
    flag = 1 = reneighbor and force calculation
 ------------------------------------------------------------------------- */
 
 void Min::setup_minimal(int flag)
 {
   // setup domain, communication and neighboring
   // acquire ghosts
   // build neighbor lists
 
   if (flag) {
     if (triclinic) domain->x2lamda(atom->nlocal);
     domain->pbc();
     domain->reset_box();
     comm->setup();
     if (neighbor->style) neighbor->setup_bins();
     comm->exchange();
     comm->borders();
     if (triclinic) domain->lamda2x(atom->nlocal+atom->nghost);
     neighbor->build();
     neighbor->ncalls = 0;
   }
 
   // atoms may have migrated in comm->exchange()
 
   reset_vectors();
 
   // compute all forces
 
   ev_set(update->ntimestep);
   force_clear();
   modify->setup_pre_force(vflag);
 
-  if (force->pair) force->pair->compute(eflag,vflag);
+  if (pair_compute_flag) force->pair->compute(eflag,vflag);
+  else if (force->pair) force->pair->compute_dummy(eflag,vflag);
 
   if (atom->molecular) {
     if (force->bond) force->bond->compute(eflag,vflag);
     if (force->angle) force->angle->compute(eflag,vflag);
     if (force->dihedral) force->dihedral->compute(eflag,vflag);
     if (force->improper) force->improper->compute(eflag,vflag);
   }
 
   if (force->kspace) {
     force->kspace->setup();
-    force->kspace->compute(eflag,vflag);
+    if (kspace_compute_flag) force->kspace->compute(eflag,vflag);
+    else force->kspace->compute_dummy(eflag,vflag);
   }
 
   if (force->newton) comm->reverse_comm();
 
   // update per-atom minimization variables stored by pair styles
 
   if (nextra_atom)
     for (int m = 0; m < nextra_atom; m++)
       requestor[m]->min_xf_get(m);
 
   modify->setup(vflag);
 
   // stats for Finish to print
 
   ecurrent = pe_compute->compute_scalar();
   if (nextra_global) ecurrent += modify->min_energy(fextra);
   if (output->thermo->normflag) ecurrent /= atom->natoms;
 	
   einitial = ecurrent;
   fnorm2_init = sqrt(fnorm_sqr());
   fnorminf_init = fnorm_inf();
 }
 
 /* ----------------------------------------------------------------------
    perform minimization, calling iterate() for N steps
 ------------------------------------------------------------------------- */
 
 void Min::run(int n)
 {
   // minimizer iterations
 
   stop_condition = iterate(n);
   stopstr = stopstrings(stop_condition);
 
   // if early exit from iterate loop:
   // set update->nsteps to niter for Finish stats to print
   // set output->next values to this timestep
   // call energy_force() to insure vflag is set when forces computed
   // output->write does final output for thermo, dump, restart files
   // add ntimestep to all computes that store invocation times
   //   since are hardwiring call to thermo/dumps and computes may not be ready
 
   if (stop_condition) {
     update->nsteps = niter;
 
     if (update->restrict_output == 0) {
       for (int idump = 0; idump < output->ndump; idump++)
 	output->next_dump[idump] = update->ntimestep;
       output->next_dump_any = update->ntimestep;
       if (output->restart_every) output->next_restart = update->ntimestep;
     }
     output->next_thermo = update->ntimestep;
 
     modify->addstep_compute_all(update->ntimestep);
     ecurrent = energy_force(0);
     output->write(update->ntimestep);
   }
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Min::cleanup()
 {
   // stats for Finish to print
 	
   efinal = ecurrent;
   fnorm2_final = sqrt(fnorm_sqr());
   fnorminf_final = fnorm_inf();
 
   // reset reneighboring criteria
 
   neighbor->every = neigh_every;
   neighbor->delay = neigh_delay;
   neighbor->dist_check = neigh_dist_check;
 
   // delete fix at end of run, so its atom arrays won't persist
 
   modify->delete_fix("MINIMIZE");
 }
 
 /* ----------------------------------------------------------------------
    evaluate potential energy and forces
    may migrate atoms due to reneighboring
    return new energy, which should include nextra_global dof
    return negative gradient stored in atom->f
    return negative gradient for nextra_global dof in fextra
 ------------------------------------------------------------------------- */
 
 double Min::energy_force(int resetflag)
 {
   // check for reneighboring
   // always communicate since minimizer moved atoms
 
   int nflag = neighbor->decide();
 
   if (nflag == 0) {
     timer->stamp();
     comm->forward_comm();
     timer->stamp(Timer::COMM);
   } else {
     if (modify->n_min_pre_exchange) {
       timer->stamp();
       modify->min_pre_exchange();
       timer->stamp(Timer::MODIFY);
     }
     if (triclinic) domain->x2lamda(atom->nlocal);
     domain->pbc();
     if (domain->box_change) {
       domain->reset_box();
       comm->setup();
       if (neighbor->style) neighbor->setup_bins();
     }
     timer->stamp();
     comm->exchange();
     if (atom->sortfreq > 0 && 
 	update->ntimestep >= atom->nextsort) atom->sort();
     comm->borders();
     if (triclinic) domain->lamda2x(atom->nlocal+atom->nghost);
     timer->stamp(Timer::COMM);
     neighbor->build();
     timer->stamp(Timer::NEIGHBOR);
   }
 
   ev_set(update->ntimestep);
   force_clear();
 
   timer->stamp();
 
   if (modify->n_min_pre_force) {
     modify->min_pre_force(vflag);
     timer->stamp(Timer::MODIFY);
   }
 
-  if (force->pair) {
+  if (pair_compute_flag) {
     force->pair->compute(eflag,vflag);
     timer->stamp(Timer::PAIR);
   }
 
   if (atom->molecular) {
     if (force->bond) force->bond->compute(eflag,vflag);
     if (force->angle) force->angle->compute(eflag,vflag);
     if (force->dihedral) force->dihedral->compute(eflag,vflag);
     if (force->improper) force->improper->compute(eflag,vflag);
     timer->stamp(Timer::BOND);
   }
 
-  if (force->kspace) {
+  if (kspace_compute_flag) {
     force->kspace->compute(eflag,vflag);
     timer->stamp(Timer::KSPACE);
   }
 
   if (force->newton) {
     comm->reverse_comm();
     timer->stamp(Timer::COMM);
   }
 
   // update per-atom minimization variables stored by pair styles
 
   if (nextra_atom)
     for (int m = 0; m < nextra_atom; m++)
       requestor[m]->min_xf_get(m);
 
   // fixes that affect minimization
 
   if (modify->n_min_post_force) {
      timer->stamp();
      modify->min_post_force(vflag);
      timer->stamp(Timer::MODIFY);
   }
 
   // compute potential energy of system
   // normalize if thermo PE does
 
   double energy = pe_compute->compute_scalar();
   if (nextra_global) energy += modify->min_energy(fextra);
   if (output->thermo->normflag) energy /= atom->natoms;
 
   // if reneighbored, atoms migrated
   // if resetflag = 1, update x0 of atoms crossing PBC
   // reset vectors used by lo-level minimizer
 
   if (nflag) {
     if (resetflag) fix_minimize->reset_coords();
     reset_vectors();
   }
 
   return energy;
 }
 
 /* ----------------------------------------------------------------------
    clear force on own & ghost atoms
    setup and clear other arrays as needed
 ------------------------------------------------------------------------- */
 
 void Min::force_clear()
 {
   if (external_force_clear) return;
 
   int i;
 
   if (external_force_clear) return;
 
   // clear global force array
   // nall includes ghosts only if either newton flag is set
 
   int nall;
   if (force->newton) nall = atom->nlocal + atom->nghost;
   else nall = atom->nlocal;
 
   size_t nbytes = sizeof(double) * nall;
 
   if (nbytes) {
     memset(&(atom->f[0][0]),0,3*nbytes);
     if (torqueflag)  memset(&(atom->torque[0][0]),0,3*nbytes);
     if (erforceflag) memset(&(atom->erforce[0]),  0,  nbytes);
     if (e_flag)      memset(&(atom->de[0]),       0,  nbytes);
     if (rho_flag)    memset(&(atom->drho[0]),     0,  nbytes);
   }
 }
 
 /* ----------------------------------------------------------------------
    pair style makes request to add a per-atom variables to minimization
    requestor stores callback to pair class to invoke during min
      to get current variable and forces on it and to update the variable
    return flag that pair can use if it registers multiple variables
 ------------------------------------------------------------------------- */
 
 int Min::request(Pair *pair, int peratom, double maxvalue)
 {
   int n = nextra_atom + 1;
   xextra_atom = (double **) memory->srealloc(xextra_atom,n*sizeof(double *),
 					     "min:xextra_atom");
   fextra_atom = (double **) memory->srealloc(fextra_atom,n*sizeof(double *),
 					     "min:fextra_atom");
   memory->grow(extra_peratom,n,"min:extra_peratom");
   memory->grow(extra_nlen,n,"min:extra_nlen");
   memory->grow(extra_max,n,"min:extra_max");
   requestor = (Pair **) memory->srealloc(requestor,n*sizeof(Pair *),
 					 "min:requestor");
 
   requestor[nextra_atom] = pair;
   extra_peratom[nextra_atom] = peratom;
   extra_max[nextra_atom] = maxvalue;
   nextra_atom++;
   return nextra_atom-1;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Min::modify_params(int narg, char **arg)
 {
   if (narg == 0) error->all(FLERR,"Illegal min_modify command");
 
   int iarg = 0;
   while (iarg < narg) {
     if (strcmp(arg[iarg],"dmax") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal min_modify command");
       dmax = atof(arg[iarg+1]);
       iarg += 2;
     } else if (strcmp(arg[iarg],"line") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal min_modify command");
       if (strcmp(arg[iarg+1],"backtrack") == 0) linestyle = 0;
       else if (strcmp(arg[iarg+1],"quadratic") == 0) linestyle = 1;
       else if (strcmp(arg[iarg+1],"forcezero") == 0) linestyle = 2;
       else error->all(FLERR,"Illegal min_modify command");
       iarg += 2;
     } else error->all(FLERR,"Illegal min_modify command");
   }
 }
 
 /* ----------------------------------------------------------------------
    setup lists of computes for global and per-atom PE and pressure
 ------------------------------------------------------------------------- */
 
 void Min::ev_setup()
 {
   delete [] elist_global;
   delete [] elist_atom;
   delete [] vlist_global;
   delete [] vlist_atom;
   elist_global = elist_atom = NULL;
   vlist_global = vlist_atom = NULL;
 
   nelist_global = nelist_atom = 0;
   nvlist_global = nvlist_atom = 0;
   for (int i = 0; i < modify->ncompute; i++) {
     if (modify->compute[i]->peflag) nelist_global++;
     if (modify->compute[i]->peatomflag) nelist_atom++;
     if (modify->compute[i]->pressflag) nvlist_global++;
     if (modify->compute[i]->pressatomflag) nvlist_atom++;
   }
 
   if (nelist_global) elist_global = new Compute*[nelist_global];
   if (nelist_atom) elist_atom = new Compute*[nelist_atom];
   if (nvlist_global) vlist_global = new Compute*[nvlist_global];
   if (nvlist_atom) vlist_atom = new Compute*[nvlist_atom];
 
   nelist_global = nelist_atom = 0;
   nvlist_global = nvlist_atom = 0;
   for (int i = 0; i < modify->ncompute; i++) {
     if (modify->compute[i]->peflag)
       elist_global[nelist_global++] = modify->compute[i];
     if (modify->compute[i]->peatomflag)
       elist_atom[nelist_atom++] = modify->compute[i];
     if (modify->compute[i]->pressflag)
       vlist_global[nvlist_global++] = modify->compute[i];
     if (modify->compute[i]->pressatomflag)
       vlist_atom[nvlist_atom++] = modify->compute[i];
   }
 }
 
 /* ----------------------------------------------------------------------
    set eflag,vflag for current iteration
    invoke matchstep() on all timestep-dependent computes to clear their arrays
    eflag/vflag based on computes that need info on this ntimestep
    always set eflag_global = 1, since need energy every iteration
    eflag = 0 = no energy computation
    eflag = 1 = global energy only
    eflag = 2 = per-atom energy only
    eflag = 3 = both global and per-atom energy
    vflag = 0 = no virial computation (pressure)
    vflag = 1 = global virial with pair portion via sum of pairwise interactions
    vflag = 2 = global virial with pair portion via F dot r including ghosts
    vflag = 4 = per-atom virial only
    vflag = 5 or 6 = both global and per-atom virial
 ------------------------------------------------------------------------- */
 
 void Min::ev_set(bigint ntimestep)
 {
   int i,flag;
 
   int eflag_global = 1;
   for (i = 0; i < nelist_global; i++)
     elist_global[i]->matchstep(ntimestep);
 
   flag = 0;
   int eflag_atom = 0;
   for (i = 0; i < nelist_atom; i++)
     if (elist_atom[i]->matchstep(ntimestep)) flag = 1;
   if (flag) eflag_atom = 2;
 
   if (eflag_global) update->eflag_global = update->ntimestep;
   if (eflag_atom) update->eflag_atom = update->ntimestep;
   eflag = eflag_global + eflag_atom;
 
   flag = 0;
   int vflag_global = 0;
   for (i = 0; i < nvlist_global; i++)
     if (vlist_global[i]->matchstep(ntimestep)) flag = 1;
   if (flag) vflag_global = virial_style;
 
   flag = 0;
   int vflag_atom = 0;
   for (i = 0; i < nvlist_atom; i++)
     if (vlist_atom[i]->matchstep(ntimestep)) flag = 1;
   if (flag) vflag_atom = 4;
 
   if (vflag_global) update->vflag_global = update->ntimestep;
   if (vflag_atom) update->vflag_atom = update->ntimestep;
   vflag = vflag_global + vflag_atom;
 }
 
 /* ----------------------------------------------------------------------
    compute and return ||force||_2^2
 ------------------------------------------------------------------------- */
 
 double Min::fnorm_sqr()
 {
   int i,n;
   double *fatom;
 
   double local_norm2_sqr = 0.0;
   for (i = 0; i < nvec; i++) local_norm2_sqr += fvec[i]*fvec[i];
   if (nextra_atom) {
     for (int m = 0; m < nextra_atom; m++) {
       fatom = fextra_atom[m];
       n = extra_nlen[m];
       for (i = 0; i < n; i++)
 	local_norm2_sqr += fatom[i]*fatom[i];
     }
   }
 
   double norm2_sqr = 0.0;
   MPI_Allreduce(&local_norm2_sqr,&norm2_sqr,1,MPI_DOUBLE,MPI_SUM,world);
 
   if (nextra_global)
     for (i = 0; i < nextra_global; i++) 
       norm2_sqr += fextra[i]*fextra[i];
   
   return norm2_sqr;
 }
 
 /* ----------------------------------------------------------------------
    compute and return ||force||_inf
 ------------------------------------------------------------------------- */
 
 double Min::fnorm_inf()
 {
   int i,n;
   double *fatom;
 
   double local_norm_inf = 0.0;
   for (i = 0; i < nvec; i++)
     local_norm_inf = MAX(fabs(fvec[i]),local_norm_inf);
   if (nextra_atom) {
     for (int m = 0; m < nextra_atom; m++) {
       fatom = fextra_atom[m];
       n = extra_nlen[m];
       for (i = 0; i < n; i++)
 	local_norm_inf = MAX(fabs(fatom[i]),local_norm_inf);
     }
   }
 
   double norm_inf = 0.0;
   MPI_Allreduce(&local_norm_inf,&norm_inf,1,MPI_DOUBLE,MPI_MAX,world);
 
   if (nextra_global)
     for (i = 0; i < nextra_global; i++) 
       norm_inf = MAX(fabs(fextra[i]),norm_inf);
 
   return norm_inf;
 }
 
 /* ----------------------------------------------------------------------
    possible stop conditions
 ------------------------------------------------------------------------- */
 
 char *Min::stopstrings(int n)
 {
   const char *strings[] = {"max iterations",
 			   "max force evaluations",
 			   "energy tolerance",
 			   "force tolerance",
 			   "search direction is not downhill",
 			   "linesearch alpha is zero",
 			   "forces are zero",
 			   "quadratic factors are zero",
 			   "trust region too small",
 			   "HFTN minimizer error"};
   return (char *) strings[n];
 }
diff --git a/src/min.h b/src/min.h
index c297de643..17a082e39 100644
--- a/src/min.h
+++ b/src/min.h
@@ -1,141 +1,144 @@
 /* -*- c++ -*- ----------------------------------------------------------
    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_MIN_H
 #define LMP_MIN_H
 
 #include "pointers.h"
 
 namespace LAMMPS_NS {
 
 class Min : protected Pointers {
  public:
   double einitial,efinal,eprevious;
   double fnorm2_init,fnorminf_init,fnorm2_final,fnorminf_final;
   double alpha_final;
   int niter,neval;
   int stop_condition;
   char *stopstr;
   int searchflag;     // 0 if damped dynamics, 1 if sub-cycles on local search
 
   Min(class LAMMPS *);
   virtual ~Min();
-  void init();
+  virtual void init();
   void setup();
   void setup_minimal(int);
   void run(int);
   void cleanup();
   int request(class Pair *, int, double);
   virtual bigint memory_usage() {return 0;}
   void modify_params(int, char **);
   double fnorm_sqr();
   double fnorm_inf();
 
   virtual void init_style() {}
   virtual void setup_style() = 0;
   virtual void reset_vectors() = 0;
   virtual int iterate(int) = 0;
 
  protected:
   int eflag,vflag;            // flags for energy/virial computation
   int virial_style;           // compute virial explicitly or implicitly
   int external_force_clear;   // clear forces locally or externally
 
   double dmax;                // max dist to move any atom in one step
   int linestyle;              // 0 = backtrack, 1 = quadratic, 2 = forcezero
 
   int nelist_global,nelist_atom;    // # of PE,virial computes to check
   int nvlist_global,nvlist_atom;
   class Compute **elist_global;     // lists of PE,virial Computes
   class Compute **elist_atom;
   class Compute **vlist_global;
   class Compute **vlist_atom;
 
   int triclinic;              // 0 if domain is orthog, 1 if triclinic
   int pairflag;
   int torqueflag,erforceflag;
   int e_flag,rho_flag;
 
+  int pair_compute_flag;            // 0 if pair->compute is skipped
+  int kspace_compute_flag;          // 0 if kspace->compute is skipped
+
   int narray;                       // # of arrays stored by fix_minimize
   class FixMinimize *fix_minimize;  // fix that stores auxiliary data
 
   class Compute *pe_compute;        // compute for potential energy
   double ecurrent;                  // current potential energy
 
   bigint ndoftotal;           // total dof for entire problem
 
   int nvec;                   // local atomic dof = length of xvec
   double *xvec;               // variables for atomic dof, as 1d vector
   double *fvec;               // force vector for atomic dof, as 1d vector
 
   int nextra_global;          // # of extra global dof due to fixes
   double *fextra;             // force vector for extra global dof
                               // xextra is stored by fix
 
   int nextra_atom;            // # of extra per-atom variables
   double **xextra_atom;       // ptr to the variable
   double **fextra_atom;       // ptr to the force on the variable
   int *extra_peratom;         // # of values in variable, e.g. 3 in x
   int *extra_nlen;            // total local length of variable, e.g 3*nlocal
   double *extra_max;          // max allowed change per iter for atom's var
   class Pair **requestor;     // Pair that stores/manipulates the variable
 
   int neigh_every,neigh_delay,neigh_dist_check;  // neighboring params
 
   double energy_force(int);
   void force_clear();
 
   double compute_force_norm_sqr();
   double compute_force_norm_inf();
 
   void ev_setup();
   void ev_set(bigint);
 
   char *stopstrings(int);
 };
 
 }
 
 #endif
 
 /* ERROR/WARNING messages:
 
 W: Resetting reneighboring criteria during minimization
 
 Minimization requires that neigh_modify settings be delay = 0, every =
 1, check = yes.  Since these settings were not in place, LAMMPS
 changed them and will restore them to their original values after the
 minimization.
 
 E: Minimization could not find thermo_pe compute
 
 This compute is created by the thermo command.  It must have been
 explicitly deleted by a uncompute command.
 
 E: Cannot use a damped dynamics min style with fix box/relax
 
 This is a current restriction in LAMMPS.  Use another minimizer
 style.
 
 E: Cannot use a damped dynamics min style with per-atom DOF
 
 This is a current restriction in LAMMPS.  Use another minimizer
 style.
 
 E: Illegal ... command
 
 Self-explanatory.  Check the input script syntax and compare to the
 documentation for the command.  You can use -echo screen as a
 command-line option when running LAMMPS to see the offending line.
 
 */
diff --git a/src/min_fire.cpp b/src/min_fire.cpp
index 0a67f4809..61946529d 100644
--- a/src/min_fire.cpp
+++ b/src/min_fire.cpp
@@ -1,270 +1,272 @@
 /* ----------------------------------------------------------------------
    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 "math.h"
 #include "min_fire.h"
 #include "universe.h"
 #include "atom.h"
 #include "force.h"
 #include "update.h"
 #include "output.h"
 #include "timer.h"
 #include "error.h"
 
 using namespace LAMMPS_NS;
 
 // EPS_ENERGY = minimum normalization for energy tolerance
 
 #define EPS_ENERGY 1.0e-8
 
 // same as in other min classes
 
 enum{MAXITER,MAXEVAL,ETOL,FTOL,DOWNHILL,ZEROALPHA,ZEROFORCE,ZEROQUAD};
 
 #define DELAYSTEP 5
 #define DT_GROW 1.1
 #define DT_SHRINK 0.5
 #define ALPHA0 0.1
 #define ALPHA_SHRINK 0.99
 #define TMAX 10.0
 
 /* ---------------------------------------------------------------------- */
 
 MinFire::MinFire(LAMMPS *lmp) : Min(lmp) {}
 
 /* ---------------------------------------------------------------------- */
 
-void MinFire::init_style()
+void MinFire::init()
 {
+  Min::init();
+
   dt = update->dt;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void MinFire::setup_style()
 {
   double **v = atom->v;
   int nlocal = atom->nlocal;
 
   for (int i = 0; i < nlocal; i++)
     v[i][0] = v[i][1] = v[i][2] = 0.0;
 }
 
 /* ----------------------------------------------------------------------
    set current vector lengths and pointers
    called after atoms have migrated
 ------------------------------------------------------------------------- */
 
 void MinFire::reset_vectors()
 {
   // atomic dof
 
   nvec = 3 * atom->nlocal;
   if (nvec) xvec = atom->x[0];
   if (nvec) fvec = atom->f[0];
 }
 
 /* ---------------------------------------------------------------------- */
 
 int MinFire::iterate(int maxiter)
 {
   bigint ntimestep;
   double vmax,vdotf,vdotfall,vdotv,vdotvall,fdotf,fdotfall;
   double scale1,scale2;
   double dtvone,dtv,dtfm;
   int flag,flagall;
 
   alpha_final = 0.0;
   double alpha = ALPHA0;
   double dtmax = TMAX * dt;
   bigint last_negative = update->ntimestep;
 
   for (int iter = 0; iter < maxiter; iter++) {
     ntimestep = ++update->ntimestep;
     niter++;
 
     // vdotfall = v dot f
 
     double **v = atom->v;
     double **f = atom->f;
     int nlocal = atom->nlocal;
 
     vdotf = 0.0;
     for (int i = 0; i < nlocal; i++)
       vdotf += v[i][0]*f[i][0] + v[i][1]*f[i][1] + v[i][2]*f[i][2];
     MPI_Allreduce(&vdotf,&vdotfall,1,MPI_DOUBLE,MPI_SUM,world);
 
     // sum vdotf over replicas, if necessary
     // this communicator would be invalid for multiprocess replicas
 
     if (update->multireplica == 1) {
       vdotf = vdotfall;
       MPI_Allreduce(&vdotf,&vdotfall,1,MPI_DOUBLE,MPI_SUM,universe->uworld);
     }
 
     // if (v dot f) > 0:
     // v = (1-alpha) v + alpha |v| Fhat
     // |v| = length of v, Fhat = unit f
     // if more than DELAYSTEP since v dot f was negative:
     // increase timestep and decrease alpha
 
     if (vdotfall > 0.0) {
       vdotv = 0.0;
       for (int i = 0; i < nlocal; i++)
 	vdotv += v[i][0]*v[i][0] + v[i][1]*v[i][1] + v[i][2]*v[i][2];
       MPI_Allreduce(&vdotv,&vdotvall,1,MPI_DOUBLE,MPI_SUM,world);
 
       // sum vdotv over replicas, if necessary
       // this communicator would be invalid for multiprocess replicas
 
       if (update->multireplica == 1) {
 	vdotv = vdotvall;
 	MPI_Allreduce(&vdotv,&vdotvall,1,MPI_DOUBLE,MPI_SUM,universe->uworld);
       }
 
       fdotf = 0.0;
       for (int i = 0; i < nlocal; i++)
 	fdotf += f[i][0]*f[i][0] + f[i][1]*f[i][1] + f[i][2]*f[i][2];
       MPI_Allreduce(&fdotf,&fdotfall,1,MPI_DOUBLE,MPI_SUM,world);
 
       // sum fdotf over replicas, if necessary
       // this communicator would be invalid for multiprocess replicas
       
       if (update->multireplica == 1) {
 	fdotf = fdotfall;
 	MPI_Allreduce(&fdotf,&fdotfall,1,MPI_DOUBLE,MPI_SUM,universe->uworld);
       }
 
       scale1 = 1.0 - alpha;
       if (fdotfall == 0.0) scale2 = 0.0;
       else scale2 = alpha * sqrt(vdotvall/fdotfall);
       for (int i = 0; i < nlocal; i++) {
 	v[i][0] = scale1*v[i][0] + scale2*f[i][0];
 	v[i][1] = scale1*v[i][1] + scale2*f[i][1];
 	v[i][2] = scale1*v[i][2] + scale2*f[i][2];
       }
 
       if (ntimestep - last_negative > DELAYSTEP) {
 	dt = MIN(dt*DT_GROW,dtmax);
 	alpha *= ALPHA_SHRINK;
       }
 
     // else (v dot f) <= 0:
     // decrease timestep, reset alpha, set v = 0
 
     } else {
       last_negative = ntimestep;
       dt *= DT_SHRINK;
       alpha = ALPHA0;
       for (int i = 0; i < nlocal; i++)
 	v[i][0] = v[i][1] = v[i][2] = 0.0;
     }
 
     // limit timestep so no particle moves further than dmax
 
     double *rmass = atom->rmass;
     double *mass = atom->mass;
     int *type = atom->type;
 
     dtvone = dt;
 
     for (int i = 0; i < nlocal; i++) {
       vmax = MAX(fabs(v[i][0]),fabs(v[i][1]));
       vmax = MAX(vmax,fabs(v[i][2]));
       if (dtvone*vmax > dmax) dtvone = dmax/vmax;
     }
     MPI_Allreduce(&dtvone,&dtv,1,MPI_DOUBLE,MPI_MIN,world);
 
     // min dtv over replicas, if necessary
     // this communicator would be invalid for multiprocess replicas
 
     if (update->multireplica == 1) {
       dtvone = dtv;
       MPI_Allreduce(&dtvone,&dtv,1,MPI_DOUBLE,MPI_MIN,universe->uworld);
     }
 
     // Euler integration step
 
     double **x = atom->x;
     
     if (rmass) {
       for (int i = 0; i < nlocal; i++) {
 	dtfm = dtv / rmass[i];
 	x[i][0] += dtv * v[i][0];
 	x[i][1] += dtv * v[i][1];
 	x[i][2] += dtv * v[i][2];
 	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++) {
 	dtfm = dtv / mass[type[i]];
 	x[i][0] += dtv * v[i][0];
 	x[i][1] += dtv * v[i][1];
 	x[i][2] += dtv * v[i][2];
 	v[i][0] += dtfm * f[i][0];
 	v[i][1] += dtfm * f[i][1];
 	v[i][2] += dtfm * f[i][2];
       }
     }
     
     eprevious = ecurrent;
     ecurrent = energy_force(0);
     neval++;
 
     // energy tolerance criterion
     // only check after DELAYSTEP elapsed since velocties reset to 0
     // sync across replicas if running multi-replica minimization
 
     if (update->etol > 0.0 && ntimestep-last_negative > DELAYSTEP) {
       if (update->multireplica == 0) {
 	if (fabs(ecurrent-eprevious) < 
 	    update->etol * 0.5*(fabs(ecurrent) + fabs(eprevious) + EPS_ENERGY))
 	  return ETOL;
       } else {
 	if (fabs(ecurrent-eprevious) < 
 	    update->etol * 0.5*(fabs(ecurrent) + fabs(eprevious) + EPS_ENERGY))
 	  flag = 0;
 	else flag = 1;
 	MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,universe->uworld);
 	if (flagall == 0) return ETOL;
       }
     }
 
     // force tolerance criterion
     // sync across replicas if running multi-replica minimization
 
     if (update->ftol > 0.0) {
       fdotf = fnorm_sqr();
       if (update->multireplica == 0) {
 	if (fdotf < update->ftol*update->ftol) return FTOL;
       } else {
 	if (fdotf < update->ftol*update->ftol) flag = 0;
 	else flag = 1;
 	MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,universe->uworld);
 	if (flagall == 0) return FTOL;
       }
     }
 
     // output for thermo, dump, restart files
 
     if (output->next == ntimestep) {
       timer->stamp();
       output->write(ntimestep);
       timer->stamp(Timer::OUTPUT);
     }
   }
   
   return MAXITER;
 }
diff --git a/src/min_fire.h b/src/min_fire.h
index 358d7ba22..7d54357ed 100644
--- a/src/min_fire.h
+++ b/src/min_fire.h
@@ -1,43 +1,43 @@
 /* -*- c++ -*- ----------------------------------------------------------
    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 MINIMIZE_CLASS
 
 MinimizeStyle(fire,MinFire)
 
 #else
 
 #ifndef LMP_MIN_FIRE_H
 #define LMP_MIN_FIRE_H
 
 #include "min.h"
 
 namespace LAMMPS_NS {
 
 class MinFire : public Min {
  public:
   MinFire(class LAMMPS *);
   ~MinFire() {}
-  void init_style();
+  void init();
   void setup_style();
   void reset_vectors();
   int iterate(int);
 
  private:
   double dt;
 };
 
 }
 
 #endif
 #endif
diff --git a/src/min_hftn.cpp b/src/min_hftn.cpp
index f8f36d9b6..71ac7f909 100644
--- a/src/min_hftn.cpp
+++ b/src/min_hftn.cpp
@@ -1,1691 +1,1693 @@
 /* ----------------------------------------------------------------------
    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.
 ------------------------------------------------------------------------- */
 
 /* ----------------------------------------------------------------------
    Author:  Todd Plantenga (SNL)
    Sources: "Numerical Optimization", Nocedal and Wright, 2nd Ed, p170
             "Parallel Unconstrained Min", Plantenga, SAND98-8201
 ------------------------------------------------------------------------- */
 
 #include "math.h"
 #include "string.h"
 #include "atom.h"
 #include "fix_minimize.h"
 #include "min_hftn.h"
 #include "modify.h"
 #include "output.h"
 #include "pair.h"
 #include "update.h"
 #include "timer.h"
 
 using namespace LAMMPS_NS;
 
 /* ----------------------------------------------------------------------
  * This class performs Hessian-free truncated Newton minimization on an
  * unconstrained molecular potential.  The algorithm avoids computing the
  * Hessian matrix, but obtains a near-quadratic rate of convergence.
 ------------------------------------------------------------------------- */
 
 /* ----------------------------------------------------------------------
    File local data
 ------------------------------------------------------------------------- */
 
 //---- CONSTANTS MAP TO stopstrings DECLARED IN Min.run (min.cpp).
 
 static const int  STOP_MAX_ITER = 0;          //-- MAX ITERATIONS EXCEEDED
 static const int  STOP_MAX_FORCE_EVALS = 1;   //-- MAX FORCE EVALUATIONS EXCEEDED
 static const int  STOP_ENERGY_TOL = 2;        //-- STEP DID NOT CHANGE ENERGY
 static const int  STOP_FORCE_TOL = 3;         //-- CONVERGED TO DESIRED FORCE TOL
 static const int  STOP_TR_TOO_SMALL = 8;      //-- TRUST REGION TOO SMALL
 static const int  STOP_ERROR = 9;             //-- INTERNAL ERROR
 
 static const int  NO_CGSTEP_BECAUSE_F_TOL_SATISFIED = 0;
 static const int  CGSTEP_NEWTON                     = 1;
 static const int  CGSTEP_TO_TR                      = 2;
 static const int  CGSTEP_TO_DMAX                    = 3;
 static const int  CGSTEP_NEGATIVE_CURVATURE         = 4;
 static const int  CGSTEP_MAX_INNER_ITERS            = 5;
 static const int  CGSTEP_UNDETERMINED               = 6;
 
 //---- WHEN TESTING ENERGY_TOL, THE ENERGY MAGNITUDE MUST BE AT LEAST THIS BIG.
 
 static const double  MIN_ETOL_MAG = 1.0e-8;
 
 //---- MACHINE PRECISION IS SOMETIMES DEFINED BY THE C RUNTIME.
 
 #ifdef DBL_EPSILON
   #define MACHINE_EPS  DBL_EPSILON
 #else
   #define MACHINE_EPS  2.220446049250313e-16
 #endif
 
 /* ----------------------------------------------------------------------
    Constructor
 ------------------------------------------------------------------------- */
 
 MinHFTN::MinHFTN(LAMMPS *lmp) : Min(lmp)
 {
   searchflag = 1;
 
   for (int  i = 1; i < NUM_HFTN_ATOM_BASED_VECTORS; i++)
     _daExtraGlobal[i] = NULL;
   for (int  i = 0; i < NUM_HFTN_ATOM_BASED_VECTORS; i++)
     _daExtraAtom[i] = NULL;
   
   _fpPrint = NULL;
   
   return;
 }
 
 /* ----------------------------------------------------------------------
    Destructor
 ------------------------------------------------------------------------- */
 
 MinHFTN::~MinHFTN (void)
 {
   for (int  i = 1; i < NUM_HFTN_ATOM_BASED_VECTORS; i++)
     if (_daExtraGlobal[i] != NULL)
       delete [] _daExtraGlobal[i];
   for (int  i = 0; i < NUM_HFTN_ATOM_BASED_VECTORS; i++)
     if (_daExtraAtom[i] != NULL)
       delete [] _daExtraAtom[i];
   
   return;
 }
 
 /* ----------------------------------------------------------------------
-   Public method init_style
+   Public method init
 ------------------------------------------------------------------------- */
 
-void MinHFTN::init_style()
+void MinHFTN::init()
 {
+  Min::init();
+
   for (int  i = 1; i < NUM_HFTN_ATOM_BASED_VECTORS; i++) {
     if (_daExtraGlobal[i] != NULL)
       delete [] _daExtraGlobal[i];
     _daExtraGlobal[i] = NULL;
   }
   for (int  i = 0; i < NUM_HFTN_ATOM_BASED_VECTORS; i++) {
     if (_daExtraAtom[i] != NULL)
       delete [] _daExtraAtom[i];
     _daExtraAtom[i] = NULL;
   }
   
   return;
 }
 
 /* ----------------------------------------------------------------------
    Public method setup_style
 ------------------------------------------------------------------------- */
 
 void MinHFTN::setup_style()
 {
   //---- ALLOCATE MEMORY FOR ATOMIC DEGREES OF FREEDOM.
   for (int  i = 0; i < NUM_HFTN_ATOM_BASED_VECTORS; i++)
     fix_minimize->add_vector(3);
   
   //---- ALLOCATE MEMORY FOR EXTRA GLOBAL DEGREES OF FREEDOM.
   //---- THE FIX MODULE TAKES CARE OF THE FIRST VECTOR, X0 (XK).
   if (nextra_global) {
     for (int  i = 1; i < NUM_HFTN_ATOM_BASED_VECTORS; i++)
       _daExtraGlobal[i] = new double[nextra_global];
   }
 
   //---- ALLOCATE MEMORY FOR EXTRA PER-ATOM DEGREES OF FREEDOM.
   if (nextra_atom) {
     for (int  i = 0; i < NUM_HFTN_ATOM_BASED_VECTORS; i++)
       _daExtraAtom[i] = new double*[nextra_atom];
     
     for (int m = 0; m < nextra_atom; m++) {
       for (int  i = 0; i < NUM_HFTN_ATOM_BASED_VECTORS; i++)
 	fix_minimize->add_vector (extra_peratom[m]);
     }
   }
   
   return;
 }
 
 /* ----------------------------------------------------------------------
    Public method reset_vectors
    After an energy/force calculation, atoms may migrate from one processor
    to another.  Any local vector correlated with atom positions or forces
    must also be migrated.  This is accomplished by a subclass of Fix.
    This method updates local pointers to the latest Fix copies.
 ------------------------------------------------------------------------- */
 
 void MinHFTN::reset_vectors()
 {
   nvec = 3 * atom->nlocal;
   
   //---- ATOMIC DEGREES OF FREEDOM.
   if (nvec > 0) {
     xvec = atom->x[0];
     fvec = atom->f[0];
   }
   for (int  i = 0; i < NUM_HFTN_ATOM_BASED_VECTORS; i++)
     _daAVectors[i] = fix_minimize->request_vector (i);
   
   //---- EXTRA PER-ATOM DEGREES OF FREEDOM.
   if (nextra_atom) {
     int  n = NUM_HFTN_ATOM_BASED_VECTORS;
     for (int m = 0; m < nextra_atom; m++) {
       extra_nlen[m] = extra_peratom[m] * atom->nlocal;
       requestor[m]->min_xf_pointers(m,&xextra_atom[m],&fextra_atom[m]);
       for (int  i = 0; i < NUM_HFTN_ATOM_BASED_VECTORS; i++)
 	_daExtraAtom[i][m] = fix_minimize->request_vector (n++);
     }
   }
   
   return;
 }
 
 /* ----------------------------------------------------------------------
    Public method iterate
    Upon entry, Min::setup() and Min::run have executed, and energy has
    already been evaluated at the initial point.  Return an integer code
    that maps to a stop condition in min.cpp.
 ------------------------------------------------------------------------- */
 
 int MinHFTN::iterate(int)
 {
   //---- TURN THIS ON TO GENERATE AN OPTIMIZATION PROGRESS FILE.
   bool  bPrintProgress = false;
   
   if (bPrintProgress)
     open_hftn_print_file_();
   
   double  dFinalEnergy = 0.0;
   double  dFinalFnorm2 = 0.0;
   modify->min_clearstore();
   int  nStopCode = execute_hftn_ (bPrintProgress,
 				  einitial,
 				  fnorm2_init,
 				  dFinalEnergy,
 				  dFinalFnorm2);
   modify->min_clearstore();
   if (bPrintProgress)
     close_hftn_print_file_();
   
   return( nStopCode );
 }
 
 /* ----------------------------------------------------------------------
    Private method execute_hftn_
    @param[in] bPrintProgress - if true then print progress to a file
    @param[in] dInitialEnergy - energy at input x
    @param[in] dInitialForce2 - |F|_2 at input x
    @param[out] dFinalEnergy  - energy at output x
    @param[out] dFinalForce2  - |F|_2 at output x
 
    Return stop code described in the enumeration at the top of this file,
    and the following:
      atom->x  - positions at output x
      atom->f  - forces evaluated at output x
 ------------------------------------------------------------------------- */
 int MinHFTN::execute_hftn_(const bool      bPrintProgress,
 			   const double    dInitialEnergy,
 			   const double    dInitialForce2,
 			   double &  dFinalEnergy,
 			   double &  dFinalForce2)
 {
   //---- DEFINE OUTPUTS PRINTED BY "Finish".
   eprevious = dInitialEnergy;
   alpha_final = 0.0;
   dFinalEnergy = dInitialEnergy;
   dFinalForce2 = dInitialForce2;
   
   if (dInitialForce2 < update->ftol)
     return( STOP_FORCE_TOL );
   
   //---- SAVE ATOM POSITIONS BEFORE AN ITERATION.
   fix_minimize->store_box();
   for (int  i = 0; i < nvec; i++)
     _daAVectors[VEC_XK][i] = xvec[i];
   if (nextra_atom) {
     for (int  m = 0; m < nextra_atom; m++) {
       double *  xatom  = xextra_atom[m];
       double *  xkAtom = _daExtraAtom[VEC_XK][m];
       int  n = extra_nlen[m];
       for (int  i = 0; i < n; i++)
 	xkAtom[i] = xatom[i];
     }
   }
   if (nextra_global)
     modify->min_store();
   
   double  dXInf = calc_xinf_using_mpi_();
   
   //---- FIND THE NUMBER OF UNKNOWNS.
   int  nLocalNumUnknowns = nvec + nextra_atom;
   MPI_Allreduce (&nLocalNumUnknowns, &_nNumUnknowns,
 		 1, MPI_INT, MPI_SUM, world);
   
   //---- INITIALIZE THE TRUST RADIUS BASED ON THE GRADIENT.
   double  dTrustRadius = 1.5 * dInitialForce2;
   
   //---- TRUST RADIUS MUST KEEP STEPS FROM LETTING ATOMS MOVE SO FAR THEY
   //---- VIOLATE PHYSICS OR JUMP BEYOND A PARALLEL PROCESSING DOMAIN.
   //---- LINE SEARCH METHODS DO THIS BY RESTRICTING THE LARGEST CHANGE
   //---- OF ANY ATOM'S COMPONENT TO dmax.  AN EXACT CHECK IS MADE LATER,
   //---- BUT THIS GUIDES DETERMINATION OF A MAX TRUST RADIUS.
   double  dMaxTrustRadius = dmax * sqrt((double) _nNumUnknowns);
   
   dTrustRadius = MIN (dTrustRadius, dMaxTrustRadius);
   double  dLastNewtonStep2 = dMaxTrustRadius;
   
   if (bPrintProgress)
     hftn_print_line_ (false, -1, neval, dInitialEnergy, dInitialForce2,
 		      -1, dTrustRadius, 0.0, 0.0, 0.0);
   
   bool    bHaveEvaluatedAtX = true;
   double  dCurrentEnergy    = dInitialEnergy;
   double  dCurrentForce2    = dInitialForce2;
   for (niter = 0; niter < update->nsteps; niter++) {
     (update->ntimestep)++;
     
     //---- CALL THE INNER LOOP TO GET THE NEXT TRUST REGION STEP.
     
     double  dCgForce2StopTol = MIN ((dCurrentForce2 / 2.0), 0.1 / (niter+1));
     dCgForce2StopTol = MAX (dCgForce2StopTol, update->ftol);
     
     double  dNewEnergy;
     double  dNewForce2;
     int     nStepType;
     double  dStepLength2;
     double  dStepLengthInf;
     if (compute_inner_cg_step_ (dTrustRadius,
 				dCgForce2StopTol,
 				update->max_eval,
 				bHaveEvaluatedAtX,
 				dCurrentEnergy, dCurrentForce2,
 				dNewEnergy, dNewForce2,
 				nStepType,
 				dStepLength2, dStepLengthInf) == false) {
       //---- THERE WAS AN ERROR.  RESTORE TO LAST ACCEPTED STEP.
       if (nextra_global)
 	modify->min_step (0.0, _daExtraGlobal[VEC_CG_P]);
       for (int i = 0; i < nvec; i++)
 	xvec[i] = _daAVectors[VEC_XK][i];
       if (nextra_atom) {
 	for (int  m = 0; m < nextra_atom; m++) {
 	  double *  xatom  = xextra_atom[m];
 	  double *  xkAtom = _daExtraAtom[VEC_XK][m];
 	  int  n = extra_nlen[m];
 	  for (int  i = 0; i < n; i++)
 	    xatom[i] = xkAtom[i];
 	  requestor[m]->min_x_set(m);
 	}
       }
       dFinalEnergy = energy_force (0);
       neval++;
       dFinalForce2 = sqrt (fnorm_sqr());
       return( STOP_ERROR );
     }
     
     //---- STOP IF THE CURRENT POSITION WAS FOUND TO BE ALREADY GOOD ENOUGH.
     //---- IN THIS CASE THE ENERGY AND FORCES ARE ALREADY COMPUTED.
     if (nStepType == NO_CGSTEP_BECAUSE_F_TOL_SATISFIED) {
       if (bPrintProgress)
 	hftn_print_line_ (true, niter+1, neval, dNewEnergy, dNewForce2,
 			  nStepType, dTrustRadius, dStepLength2,
 			  0.0, 0.0);
       dFinalEnergy = dNewEnergy;
       dFinalForce2 = dNewForce2;
       return( STOP_FORCE_TOL );
     }
     
     //---- COMPUTE THE DIRECTIONAL DERIVATIVE H(x_k) p.
     bool  bUseForwardDiffs = (dCurrentForce2 > 1000.0 * sqrt (MACHINE_EPS));
     evaluate_dir_der_ (bUseForwardDiffs,
 		       VEC_CG_P,
 		       VEC_CG_HD,
 		       true,
 		       dCurrentEnergy);
     
     //---- COMPUTE p^T grad(x_k) AND SAVE IT FOR PRED.
     double  dGradDotP = calc_grad_dot_v_using_mpi_ (VEC_CG_P);
     
     //---- MOVE TO THE NEW POINT AND EVALUATE ENERGY AND FORCES.
     //---- THIS IS THE PLACE WHERE energy_force IS ALLOWED TO RESET.
     for (int i = 0; i < nvec; i++)
       xvec[i] = _daAVectors[VEC_XK][i] + _daAVectors[VEC_CG_P][i];
     if (nextra_atom) {
       for (int  m = 0; m < nextra_atom; m++) {
 	double *  xatom  = xextra_atom[m];
 	double *  xkAtom = _daExtraAtom[VEC_XK][m];
 	double *  pAtom  = _daExtraAtom[VEC_CG_P][m];
 	int  n = extra_nlen[m];
 	for (int  i = 0; i < n; i++)
 	  xatom[i] = xkAtom[i] + pAtom[i];
 	requestor[m]->min_x_set(m);
       }
     }
     if (nextra_global)
       modify->min_step (1.0, _daExtraGlobal[VEC_CG_P]);
     dNewEnergy = energy_force (1);
     neval++;
     
     dNewForce2 = sqrt (fnorm_sqr());
     
     double  dAred = dCurrentEnergy - dNewEnergy;
     
     //---- STOP IF THE FORCE TOLERANCE IS MET.
     if (dNewForce2 < update->ftol) {
       if (bPrintProgress)
 	hftn_print_line_ (true, niter+1, neval, dNewEnergy, dNewForce2,
 			  nStepType, dTrustRadius, dStepLength2,
 			  dAred, -1.0);
       //---- (IMPLICITLY ACCEPT THE LAST STEP TO THE NEW POINT.)
       dFinalEnergy = dNewEnergy;
       dFinalForce2 = dNewForce2;
       return( STOP_FORCE_TOL );
     }
     
     //---- STOP IF THE ACTUAL ENERGY REDUCTION IS TINY.
     if (nStepType != CGSTEP_TO_DMAX) {
       double  dMag = 0.5 * (fabs (dCurrentEnergy) + fabs (dNewEnergy));
       dMag = MAX (dMag, MIN_ETOL_MAG);
       if (   (fabs (dAred) < (update->etol * dMag))
 	     || (dStepLengthInf == 0.0) ) {
 	if (bPrintProgress)
 	  hftn_print_line_ (true, niter+1, neval,
 			    dNewEnergy, dNewForce2,
 			    nStepType, dTrustRadius, dStepLength2,
 			    dAred, -1.0);
 	//---- (IMPLICITLY ACCEPT THE LAST STEP TO THE NEW POINT.)
 	dFinalEnergy = dNewEnergy;
 	dFinalForce2 = dNewForce2;
 	return( STOP_ENERGY_TOL );
       }
     }
     
     //---- COMPUTE THE PREDICTED REDUCTION  - p^T grad - 0.5 p^T Hp
     double  dPHP = calc_dot_prod_using_mpi_ (VEC_CG_P, VEC_CG_HD);
     double  dPred = - dGradDotP - (0.5 * dPHP);
     
     //---- ACCEPT OR REJECT THE STEP PROPOSED BY THE INNER CG LOOP.
     //---- WHEN NEAR A SOLUTION, THE FORCE NORM IS PROBABLY MORE ACCURATE,
     //---- SO DON'T ACCEPT A STEP THAT REDUCES ENERGY SOME TINY AMOUNT
     //---- WHILE INCREASING THE FORCE NORM.
     bool  bStepAccepted = (dAred > 0.0)
       && (   (dNewForce2 < dCurrentForce2)
 	     || (dCurrentForce2 > 1.0e-6));
     if (bStepAccepted) {
       //---- THE STEP IS ACCEPTED.
       if (bPrintProgress)
 	hftn_print_line_ (true, niter+1, neval, dNewEnergy, dNewForce2,
 			  nStepType, dTrustRadius, dStepLength2,
 			  dAred, dPred);
       
       fix_minimize->store_box();
       modify->min_clearstore();
       for (int  i = 0; i < nvec; i++)
 	_daAVectors[VEC_XK][i] = xvec[i];
       if (nextra_atom) {
 	for (int  m = 0; m < nextra_atom; m++) {
 	  double *  xatom  = xextra_atom[m];
 	  double *  xkAtom = _daExtraAtom[VEC_XK][m];
 	  int  n = extra_nlen[m];
 	  for (int  i = 0; i < n; i++)
 	    xkAtom[i] = xatom[i];
 	}
       }
       if (nextra_global)
 	modify->min_store();
       
       if (niter > 0)
 	eprevious = dCurrentEnergy;
       dCurrentEnergy = dNewEnergy;
       dCurrentForce2 = dNewForce2;
       bHaveEvaluatedAtX = true;
       
       if (nStepType == CGSTEP_NEWTON)
 	dLastNewtonStep2 = dStepLength2;
       
       //---- UPDATE THE TRUST REGION BASED ON AGREEMENT BETWEEN
       //---- THE ACTUAL REDUCTION AND THE PREDICTED MODEL REDUCTION.
       if ((dAred > 0.75 * dPred) && (dStepLength2 >= 0.99 * dTrustRadius))
 	dTrustRadius = 2.0 * dTrustRadius;
       dTrustRadius = MIN (dTrustRadius, dMaxTrustRadius);
       
       //---- DMAX VIOLATIONS TRUNCATE THE CG STEP WITHOUT COMPARISONS;
       //---- BETTER TO ADJUST THE TRUST REGION SO DMAX STOPS HAPPENING.
       if (nStepType == CGSTEP_TO_DMAX) {
 	if (dStepLength2 <= MACHINE_EPS)
 	  dTrustRadius = 0.1 * dTrustRadius;
 	else
 	  dTrustRadius = MIN (dTrustRadius, 2.0 * dStepLength2);
       }
     }
     else {
       //---- THE STEP IS REJECTED.
       if (bPrintProgress)
 	hftn_print_line_ (false, niter+1, neval,
 			  dCurrentEnergy, dCurrentForce2,
 			  nStepType, dTrustRadius, dStepLength2,
 			  dAred, dPred);
       
       //---- RESTORE THE LAST X_K POSITION.
       if (nextra_global)
 	modify->min_step (0.0, _daExtraGlobal[VEC_CG_P]);
       for (int  i = 0; i < nvec; i++)
 	xvec[i] = _daAVectors[VEC_XK][i];
       if (nextra_atom) {
 	for (int  m = 0; m < nextra_atom; m++) {
 	  double *  xatom  = xextra_atom[m];
 	  double *  xkAtom = _daExtraAtom[VEC_XK][m];
 	  int  n = extra_nlen[m];
 	  for (int  i = 0; i < n; i++)
 	    xatom[i] = xkAtom[i];
 	  requestor[m]->min_x_set(m);
 	}
       }
       modify->min_clearstore();
       bHaveEvaluatedAtX = false;
       
       //---- UPDATE THE TRUST REGION.
       //---- EXPERIMENTS INDICATE NEGATIVE CURVATURE CAN TAKE A BAD
       //---- STEP A LONG WAY, SO BE MORE AGGRESSIVE IN THIS CASE.
       //---- ALSO, IF NEAR A SOLUTION AND DONE WITH NEWTON STEPS,
       //---- THEN REDUCE TO SOMETHING NEAR THE LAST GOOD NEWTON STEP.
       if ((nStepType == CGSTEP_NEGATIVE_CURVATURE) && (-dAred > dPred))
 	dTrustRadius = 0.10 * MIN (dTrustRadius, dStepLength2);
       else if (   (nStepType == CGSTEP_TO_DMAX)
 		  && (dStepLength2 <= MACHINE_EPS))
 	dTrustRadius = 0.10 * dTrustRadius;
       else if (-dAred > dPred)
 	dTrustRadius = 0.20 * MIN (dTrustRadius, dStepLength2);
       else
 	dTrustRadius = 0.25 * MIN (dTrustRadius, dStepLength2);
       
       if (   (nStepType != CGSTEP_NEWTON)
 	     && (dCurrentForce2 < sqrt (MACHINE_EPS)))
 	dTrustRadius = MIN (dTrustRadius, 2.0 * dLastNewtonStep2);
       
       dLastNewtonStep2 = dMaxTrustRadius;
       
       //---- STOP IF THE TRUST RADIUS IS TOO SMALL TO CONTINUE.
       if (   (dTrustRadius <= 0.0)
 	     || (dTrustRadius <= MACHINE_EPS * MAX (1.0, dXInf))) {
 	dFinalEnergy = dCurrentEnergy;
 	dFinalForce2 = dCurrentForce2;
 	return( STOP_TR_TOO_SMALL );
       }
     }
     
     //---- OUTPUT FOR thermo, dump, restart FILES.
     if (output->next == update->ntimestep) {
       //---- IF THE LAST STEP WAS REJECTED, THEN REEVALUATE ENERGY AND
       //---- FORCES AT THE OLD POINT SO THE OUTPUT DOES NOT DISPLAY
       //---- THE INCREASED ENERGY OF THE REJECTED STEP.
       if (bStepAccepted == false) {
 	dCurrentEnergy = energy_force (1);
 	neval++;
       }
       timer->stamp();
       output->write (update->ntimestep);
       timer->stamp (Timer::OUTPUT);
     }
     
     //---- RETURN IF NUMBER OF EVALUATIONS EXCEEDED.
     if (neval >= update->max_eval) {
       dFinalEnergy = dCurrentEnergy;
       dFinalForce2 = dCurrentForce2;
       return( STOP_MAX_FORCE_EVALS );
     }
     
   }     //-- END for LOOP OVER niter
   
   dFinalEnergy = dCurrentEnergy;
   dFinalForce2 = dCurrentForce2;
   return( STOP_MAX_ITER );
 }
 
 /* ----------------------------------------------------------------------
    Private method compute_inner_cg_step_
    Execute CG using Hessian-vector products approximated by finite difference
      directional derivatives.
 
    On input these must be defined:
      atom->x   - positions at x
      atom->f   - ignored
      VEC_XK    - positions at x
    On output these are defined:
      atom->x   - unchanged
      atom->f   - forces evaluated at x, but only if nStepType == NO_CGSTEP
      VEC_XK    - unchanged
      VEC_CG_P  - step from VEC_XK to new positions
    During processing these are modified:
      VEC_CG_D  - conjugate gradient inner loop step
      VEC_CG_HD - Hessian-vector product
      VEC_CG_R  - residual of inner loop step
      VEC_DIF1  - temp storage
      VEC_DIF2  - temp storage
 
    @param[in] dTrustRadius     - trust region radius for this subiteration
    @param[in] dForceTol        - stop tolerance on |F|_2 for this subiteration
    @param[in] nMaxEvals        - total energy/force evaluations allowed
    @param[in] bHaveEvalAtXin   - true if forces are valid at input x
    @param[in] dEnergyAtXin     - energy at input x, if bHaveEvalAtXin is true
    @param[in] dForce2AtXin     - |F|_2 at input x, if bHaveEvalAtXin is true
    @param[out] dEnergyAtXout   - energy at output x, if NO_CGSTEP (see below)
    @param[out] dForce2AtXout   - |F|_2 at output x, if NO_CGSTEP (see below)
    @param[out] nStepType       - step type for hftn_print_line_()
    @param[out] dStepLength2    - |step|_2
    @param[out] dStepLengthInf  - |step|_inf
 
    Return false if there was a fatal error.
    If nStepType equals NO_CGSTEP_BECAUSE_F_TOL_SATISFIED, then the energy
    and forces are evaluated and returned in dEnergyAtXout, dForce2AtXout;
    else energy and forces are not evaluated.
 ------------------------------------------------------------------------- */
 
 bool MinHFTN::compute_inner_cg_step_(const double    dTrustRadius,
 				     const double    dForceTol,
 				     const int       nMaxEvals,
 				     const bool      bHaveEvalAtXin,
 				     const double    dEnergyAtXin,
 				     const double    dForce2AtXin,
 				     double &  dEnergyAtXout,
 				     double &  dForce2AtXout,
 				     int    &  nStepType,
 				     double &  dStepLength2,
 				     double &  dStepLengthInf)
 {
   //---- SET  p_0 = 0.
   if (nextra_global) {
     for (int  i = 0; i < nextra_global; i++)
       _daExtraGlobal[VEC_CG_P][i] = 0.0;
   }
   for (int  i = 0; i < nvec; i++)
     _daAVectors[VEC_CG_P][i] = 0.0;
   if (nextra_atom) {
     for (int  m = 0; m < nextra_atom; m++) {
       double *  pAtom = _daExtraAtom[VEC_CG_P][m];
       int  n = extra_nlen[m];
       for (int  i = 0; i < n; i++)
 	pAtom[i] = 0.0;
     }
   }
   double  dPP = 0.0;
   
   //---- OBTAIN THE ENERGY AND FORCES AT THE INPUT POSITION.
   double  dEnergyAtX = dEnergyAtXin;
   double  dForce2AtX = dForce2AtXin;
   if (bHaveEvalAtXin == false) {
     dEnergyAtX = energy_force (0);
     neval++;
     dForce2AtX = sqrt (fnorm_sqr());
   }
   
   //---- RETURN IMMEDIATELY IF THE FORCE TOLERANCE IS ALREADY MET.
   //---- THE STEP TYPE INFORMS THE CALLER THAT ENERGY AND FORCES HAVE
   //---- BEEN EVALUATED.
   if (dForce2AtX <= dForceTol) {
     dEnergyAtXout = dEnergyAtX;
     dForce2AtXout = dForce2AtX;
     nStepType = NO_CGSTEP_BECAUSE_F_TOL_SATISFIED;
     dStepLength2 = 0.0;
     dStepLengthInf = 0.0;
     return( true );
   }
   
   //---- r_0 = -grad  (FIRST SEARCH DIRECTION IS STEEPEST DESCENT)
   //---- d_0 = r_0
   //---- REMEMBER THAT FORCES = -GRADIENT.
   if (nextra_global) {
     for (int  i = 0; i < nextra_global; i++) {
       _daExtraGlobal[VEC_CG_R][i] = fextra[i];
       _daExtraGlobal[VEC_CG_D][i] = fextra[i];
     }
   }
   for (int  i = 0; i < nvec; i++) {
     _daAVectors[VEC_CG_R][i] = fvec[i];
     _daAVectors[VEC_CG_D][i] = fvec[i];
   }
   if (nextra_atom) {
     for (int  m = 0; m < nextra_atom; m++) {
       double *  fatom = fextra_atom[m];
       double *  rAtom = _daExtraAtom[VEC_CG_R][m];
       double *  dAtom = _daExtraAtom[VEC_CG_D][m];
       int  n = extra_nlen[m];
       for (int  i = 0; i < n; i++) {
 	rAtom[i] = fatom[i];
 	dAtom[i] = fatom[i];
       }
     }
   }
   double  dRR = dForce2AtX * dForce2AtX;
   double  dR0norm2 = sqrt (dRR);
   
   //---- LIMIT THE NUMBER OF INNER CG ITERATIONS.
   //---- BASE IT ON THE NUMBER OF UNKNOWNS, OR MAXIMUM EVALUATIONS ASSUMING
   //---- FORWARD DIFFERENCES ARE USED.
   //---- NOTE THAT SETTING MAX=1 GIVES STEEPEST DESCENT.
   int  nLimit1 = _nNumUnknowns / 5;
   if (nLimit1 < 100)
     nLimit1 = MIN (_nNumUnknowns, 100);
   int  nLimit2 = (nMaxEvals - neval) / 2;
   int  nMaxInnerIters = MIN (nLimit1, nLimit2);
   
   //---- FURTHER LIMIT ITERATIONS IF NEAR MACHINE ROUNDOFF.
   //---- THE METHOD CAN WASTE A LOT EVALUATIONS WITH LITTLE PAYOFF PROSPECT.
   if (dForce2AtX < (sqrt (MACHINE_EPS) * MAX (1.0, fabs (dEnergyAtX))) )
     nMaxInnerIters = MIN (nMaxInnerIters, _nNumUnknowns / 20);
   
   bool  bUseForwardDiffs = (dForce2AtX > 1000.0 * sqrt (MACHINE_EPS));
   
   //---- MAIN CG LOOP.
   for (int  nInnerIter = 0; nInnerIter < nMaxInnerIters; nInnerIter++) {
     //---- COMPUTE HESSIAN-VECTOR PRODUCT:  H(x_k) d_i.
     double  dDummyEnergy;
     evaluate_dir_der_ (bUseForwardDiffs,
 		       VEC_CG_D,
 		       VEC_CG_HD,
 		       false,
 		       dDummyEnergy);
     
     //---- CALCULATE  d_i^T H d_i AND d_i^T d_i.
     double  dDHD;
     double  dDD;
     calc_dhd_dd_using_mpi_ (dDHD, dDD);
     
     //---- HANDLE NEGATIVE CURVATURE.
     if (dDHD <= (MACHINE_EPS * dDD)) {
       //---- PROJECT BOTH DIRECTIONS TO THE TRUST RADIUS AND DECIDE
       //---- WHICH MAKES A BETTER PREDICTED REDUCTION.
       //---- p_i^T H(x_k) d_i AND grad_i^T d_i.
       
       double  dPdotD  = calc_dot_prod_using_mpi_ (VEC_CG_P, VEC_CG_D);
       double  dPdotHD = calc_dot_prod_using_mpi_ (VEC_CG_P, VEC_CG_HD);
       
       //---- MOVE TO X_K AND COMPUTE ENERGY AND FORCES.
       if (nextra_global)
 	modify->min_step (0.0, _daExtraGlobal[VEC_CG_P]);
       for (int  i = 0; i < nvec; i++)
 	xvec[i] = _daAVectors[VEC_XK][i];
       if (nextra_atom) {
 	for (int  m = 0; m < nextra_atom; m++) {
 	  double *  xatom  = xextra_atom[m];
 	  double *  xkAtom = _daExtraAtom[VEC_XK][m];
 	  int  n = extra_nlen[m];
 	  for (int  i = 0; i < n; i++)
 	    xatom[i] = xkAtom[i];
 	  requestor[m]->min_x_set(m);
 	}
       }
       dEnergyAtX = energy_force (0);
       neval++;
       
       double  dGradDotD = calc_grad_dot_v_using_mpi_ (VEC_CG_D);
       
       double  tau = compute_to_tr_ (dPP, dPdotD, dDD, dTrustRadius,
 				    true, dDHD, dPdotHD, dGradDotD);
       
       //---- MOVE THE POINT.
       if (nextra_global) {
 	double *  pGlobal = _daExtraGlobal[VEC_CG_P];
 	double *  dGlobal = _daExtraGlobal[VEC_CG_D];
 	for (int  i = 0; i < nextra_global; i++) {
 	  pGlobal[i] += tau * dGlobal[i];
 	}
       }
       for (int  i = 0; i < nvec; i++)
 	_daAVectors[VEC_CG_P][i] += tau * _daAVectors[VEC_CG_D][i];
       if (nextra_atom) {
 	for (int  m = 0; m < nextra_atom; m++) {
 	  double *  pAtom = _daExtraAtom[VEC_CG_P][m];
 	  double *  dAtom = _daExtraAtom[VEC_CG_D][m];
 	  int  n = extra_nlen[m];
 	  for (int  i = 0; i < n; i++)
 	    pAtom[i] += tau * dAtom[i];
 	}
       }
       
       nStepType = CGSTEP_NEGATIVE_CURVATURE;
       calc_plengths_using_mpi_ (dStepLength2, dStepLengthInf);
       return( true );
     }
     
     //---- COMPUTE THE OPTIMAL STEP LENGTH BASED ON THE QUADRATIC CG MODEL.
     double  dAlpha = dRR / dDHD;
     
     //---- MIGHT WANT TO ENABLE THIS TO DEBUG INTERNAL CG STEPS.
     //fprintf (_fpPrint, "     alpha = %11.8f  neval=%4d\n", dAlpha, neval);
     
     //---- p_i+1 = p_i + alpha_i d_i
     //---- (SAVE THE CURRENT p_i IN CASE THE STEP HAS TO BE SHORTENED.)
     if (nextra_global) {
       double *  pGlobal  = _daExtraGlobal[VEC_CG_P];
       double *  dGlobal  = _daExtraGlobal[VEC_CG_D];
       double *  d1Global = _daExtraGlobal[VEC_DIF1];
       for (int  i = 0; i < nextra_global; i++) {
 	d1Global[i] = pGlobal[i];
 	pGlobal[i] += dAlpha * dGlobal[i];
       }
     }
     for (int  i = 0; i < nvec; i++) {
       _daAVectors[VEC_DIF1][i] = _daAVectors[VEC_CG_P][i];
       _daAVectors[VEC_CG_P][i] += dAlpha * _daAVectors[VEC_CG_D][i];
     }
     if (nextra_atom) {
       for (int  m = 0; m < nextra_atom; m++) {
 	double *  pAtom  = _daExtraAtom[VEC_CG_P][m];
 	double *  dAtom  = _daExtraAtom[VEC_CG_D][m];
 	double *  d1Atom = _daExtraAtom[VEC_DIF1][m];
 	int  n = extra_nlen[m];
 	for (int  i = 0; i < n; i++) {
 	  d1Atom[i] = pAtom[i];
 	  pAtom[i] += dAlpha * dAtom[i];
 	}
       }
     }
     
     //---- COMPUTE VECTOR PRODUCTS  p_i+1^T p_i+1 AND p_i^T d_i.
     double  dPnewDotPnew;
     double  dPoldDotD;
     calc_ppnew_pdold_using_mpi_ (dPnewDotPnew, dPoldDotD);
     
     nStepType = CGSTEP_UNDETERMINED;
     
     //---- IF STEP LENGTH IS TOO LARGE, THEN REDUCE IT AND RETURN.
     double  tau;
     if (step_exceeds_TR_ (dTrustRadius, dPP, dPoldDotD, dDD, tau)) {
       adjust_step_to_tau_ (tau);
       nStepType = CGSTEP_TO_TR;
     }
     if (step_exceeds_DMAX_()) {
       adjust_step_to_tau_ (0.0);
       nStepType = CGSTEP_TO_DMAX;
     }
     if ((nStepType == CGSTEP_TO_TR) || (nStepType == CGSTEP_TO_DMAX)) {
       calc_plengths_using_mpi_ (dStepLength2, dStepLengthInf);
       return( true );
     }
     
     dStepLength2 = sqrt (dPnewDotPnew);
     
     //---- r_i+1 = r_i - alpha * H d_i
     if (nextra_global) {
       double *  rGlobal  = _daExtraGlobal[VEC_CG_R];
       double *  hdGlobal = _daExtraGlobal[VEC_CG_HD];
       for (int  i = 0; i < nextra_global; i++)
 	rGlobal[i] -= dAlpha * hdGlobal[i];
     }
     for (int  i = 0; i < nvec; i++)
       _daAVectors[VEC_CG_R][i] -= dAlpha * _daAVectors[VEC_CG_HD][i];
     if (nextra_atom) {
       for (int  m = 0; m < nextra_atom; m++) {
 	double *  rAtom  = _daExtraAtom[VEC_CG_R][m];
 	double *  hdAtom = _daExtraAtom[VEC_CG_HD][m];
 	int  n = extra_nlen[m];
 	for (int  i = 0; i < n; i++)
 	  rAtom[i] -= dAlpha * hdAtom[i];
       }
     }
     double  dRnewDotRnew = calc_dot_prod_using_mpi_ (VEC_CG_R, VEC_CG_R);
     
     //---- IF RESIDUAL IS SMALL ENOUGH, THEN RETURN THE CURRENT STEP.
     if (sqrt (dRnewDotRnew) < dForceTol * dR0norm2) {
       nStepType = CGSTEP_NEWTON;
       calc_plengths_using_mpi_ (dStepLength2, dStepLengthInf);
       return( true );
     }
     
     //---- beta = r_i+1^T r_i+1 / r_i^T r_i
     //---- d_i+1 = r_i+1 + beta d_i
     double  dBeta = dRnewDotRnew / dRR;
     if (nextra_global) {
       double *  rGlobal = _daExtraGlobal[VEC_CG_R];
       double *  dGlobal = _daExtraGlobal[VEC_CG_D];
       for (int  i = 0; i < nextra_global; i++)
 	dGlobal[i] = rGlobal[i] + dBeta * dGlobal[i];
     }
     for (int  i = 0; i < nvec; i++)
       _daAVectors[VEC_CG_D][i] = _daAVectors[VEC_CG_R][i]
 	+ dBeta * _daAVectors[VEC_CG_D][i];
     if (nextra_atom) {
       for (int  m = 0; m < nextra_atom; m++) {
 	double *  rAtom = _daExtraAtom[VEC_CG_R][m];
 	double *  dAtom = _daExtraAtom[VEC_CG_D][m];
 	int  n = extra_nlen[m];
 	for (int  i = 0; i < n; i++)
 	  dAtom[i] = rAtom[i] + dBeta * dAtom[i];
       }
     }
     
     //---- CONTINUE THE LOOP.
     dRR = dRnewDotRnew;
     dPP = dPnewDotPnew;
   }
   
   nStepType = CGSTEP_MAX_INNER_ITERS;
   calc_plengths_using_mpi_ (dStepLength2, dStepLengthInf);
   return( true );    
 }
 
 /* ----------------------------------------------------------------------
    Private method calc_xinf_using_mpi_
 ------------------------------------------------------------------------- */
 
 double MinHFTN::calc_xinf_using_mpi_(void) const
 {
   double dXInfLocal = 0.0;
   for (int  i = 0; i < nvec; i++)
     dXInfLocal = MAX(dXInfLocal,fabs(xvec[i]));
   
   double  dXInf;
   MPI_Allreduce (&dXInfLocal, &dXInf, 1, MPI_DOUBLE, MPI_MAX, world);
   
   if (nextra_atom) {
     for (int  m = 0; m < nextra_atom; m++) {
       double *  xatom = xextra_atom[m];
       int  n = extra_nlen[m];
       double  dXInfLocalExtra = 0.0;
       for (int  i = 0; i < n; i++)
 	dXInfLocalExtra = MAX (dXInfLocalExtra, fabs (xatom[i]));
       double  dXInfExtra;
       MPI_Allreduce (&dXInfLocalExtra, &dXInfExtra,
 		     1, MPI_DOUBLE, MPI_MAX, world);
       dXInf = MAX (dXInf, dXInfExtra);
     }
   }
   
   return( dXInf );
 }
 
 
 /* ----------------------------------------------------------------------
    Private method calc_dot_prod_using_mpi_
 ------------------------------------------------------------------------- */
 
 double MinHFTN::calc_dot_prod_using_mpi_(const int  nIx1,
 					  const int  nIx2) const
 {
   double dDotLocal = 0.0;
   for (int  i = 0; i < nvec; i++)
     dDotLocal += _daAVectors[nIx1][i] * _daAVectors[nIx2][i];
   if (nextra_atom) {
     for (int  m = 0; m < nextra_atom; m++) {
       double *  i1Atom = _daExtraAtom[nIx1][m];
       double *  i2Atom = _daExtraAtom[nIx2][m];
       int  n = extra_nlen[m];
       for (int  i = 0; i < n; i++)
 	dDotLocal += i1Atom[i] * i2Atom[i];
     }
   }
   
   double  dDot;
   MPI_Allreduce (&dDotLocal, &dDot, 1, MPI_DOUBLE, MPI_SUM, world);
   
   if (nextra_global) {
     for (int  i = 0; i < nextra_global; i++) {
       double *  i1Global = _daExtraGlobal[nIx1];
       double *  i2Global = _daExtraGlobal[nIx2];
       dDot += i1Global[i] * i2Global[i];
     }
   }
   
   return( dDot );
 }
 
 /* ----------------------------------------------------------------------
    Private method calc_grad_dot_v_using_mpi_
 ------------------------------------------------------------------------- */
 
 double MinHFTN::calc_grad_dot_v_using_mpi_(const int  nIx) const
 {
   //---- ASSUME THAT FORCES HAVE BEEN EVALUATED AT DESIRED ATOM POSITIONS.
   //---- REMEMBER THAT FORCES = -GRADIENT.
   
   double dGradDotVLocal = 0.0;
   for (int i = 0; i < nvec; i++)
     dGradDotVLocal += - _daAVectors[nIx][i] * fvec[i];
   if (nextra_atom) {
     for (int m = 0; m < nextra_atom; m++) {
       double *  fatom = fextra_atom[m];
       double *  iAtom = _daExtraAtom[nIx][m];
       int  n = extra_nlen[m];
       for (int i = 0; i < n; i++)
 	dGradDotVLocal += - iAtom[i] * fatom[i];
     }
   }
   
   double  dGradDotV;
   MPI_Allreduce (&dGradDotVLocal, &dGradDotV, 1, MPI_DOUBLE, MPI_SUM, world);
   
   if (nextra_global) {
     for (int  i = 0; i < nextra_global; i++) {
       double *  iGlobal = _daExtraGlobal[nIx];
       dGradDotV += - iGlobal[i] * fextra[i];
     }
   }
   
   return( dGradDotV );
 }
 
 /* ----------------------------------------------------------------------
    Private method calc_dhd_dd_using_mpi_
 ------------------------------------------------------------------------- */
 
 void MinHFTN::calc_dhd_dd_using_mpi_(double &  dDHD,
 				     double &  dDD) const
 {
   double dDHDLocal = 0.0;
   double dDDLocal  = 0.0;
   for (int  i = 0; i < nvec; i++) {
     dDHDLocal += _daAVectors[VEC_CG_D][i] * _daAVectors[VEC_CG_HD][i];
     dDDLocal  += _daAVectors[VEC_CG_D][i] * _daAVectors[VEC_CG_D][i];
   }
   if (nextra_atom) {
     for (int  m = 0; m < nextra_atom; m++) {
       double *  dAtom  = _daExtraAtom[VEC_CG_D][m];
       double *  hdAtom = _daExtraAtom[VEC_CG_HD][m];
       int  n = extra_nlen[m];
       for (int  i = 0; i < n; i++) {
 	dDHDLocal += dAtom[i] * hdAtom[i];
 	dDDLocal += dAtom[i] * dAtom[i];
       }
     }
   }
   
   double  daDotsLocal[2];
   daDotsLocal[0] = dDHDLocal;
   daDotsLocal[1] = dDDLocal;
   double  daDots[2];
   MPI_Allreduce (daDotsLocal, daDots, 2, MPI_DOUBLE, MPI_SUM, world);
   
   if (nextra_global) {
     double *  dGlobal  = _daExtraGlobal[VEC_CG_D];
     double *  hdGlobal = _daExtraGlobal[VEC_CG_HD];
     for (int  i = 0; i < nextra_global; i++) {
       daDots[0] += dGlobal[i] * hdGlobal[i];
       daDots[1] += dGlobal[i] * dGlobal[i];
     }
   }
   dDHD = daDots[0];
   dDD  = daDots[1];
   
   return;
 }
 
 /* ----------------------------------------------------------------------
    Private method calc_ppnew_pdold_using_mpi_
 ------------------------------------------------------------------------- */
 
 void MinHFTN::calc_ppnew_pdold_using_mpi_(double &  dPnewDotPnew,
 					  double &  dPoldDotD) const
 {
   double dPnewDotPnewLocal = 0.0;
   double dPoldDotDLocal    = 0.0;
   for (int  i = 0; i < nvec; i++) {
     dPnewDotPnewLocal
       += _daAVectors[VEC_CG_P][i] * _daAVectors[VEC_CG_P][i];
     dPoldDotDLocal
       += _daAVectors[VEC_DIF1][i] * _daAVectors[VEC_CG_D][i];
   }
   if (nextra_atom) {
     for (int  m = 0; m < nextra_atom; m++) {
       double *  dAtom  = _daExtraAtom[VEC_CG_D][m];
       double *  pAtom  = _daExtraAtom[VEC_CG_P][m];
       double *  d1Atom = _daExtraAtom[VEC_DIF1][m];
       int  n = extra_nlen[m];
       for (int  i = 0; i < n; i++) {
 	dPnewDotPnewLocal += pAtom[i] * pAtom[i];
 	dPoldDotDLocal += d1Atom[i] * dAtom[i];
       }
     }
   }
   
   double  daDotsLocal[2];
   daDotsLocal[0] = dPnewDotPnewLocal;
   daDotsLocal[1] = dPoldDotDLocal;
   double  daDots[2];
   MPI_Allreduce (daDotsLocal, daDots, 2, MPI_DOUBLE, MPI_SUM, world);
   
   if (nextra_global) {
     for (int  i = 0; i < nextra_global; i++) {
       double *  dGlobal  = _daExtraGlobal[VEC_CG_D];
       double *  pGlobal  = _daExtraGlobal[VEC_CG_P];
       double *  d1Global = _daExtraGlobal[VEC_DIF1];
       daDots[0] += pGlobal[i] * pGlobal[i];
       daDots[1] += d1Global[i] * dGlobal[i];
     }
   }
   
   dPnewDotPnew = daDots[0];
   dPoldDotD    = daDots[1];
   
   return;
 }
 
 /* ----------------------------------------------------------------------
    Private method calc_plengths_using_mpi_
 ------------------------------------------------------------------------- */
 
 void MinHFTN::calc_plengths_using_mpi_(double &  dStepLength2,
 				       double &  dStepLengthInf) const
 {
   double dPPLocal   = 0.0;
   double dPInfLocal = 0.0;
   for (int  i = 0; i < nvec; i++) {
     dPPLocal += _daAVectors[VEC_CG_P][i] * _daAVectors[VEC_CG_P][i];
     dPInfLocal = MAX (dPInfLocal, fabs (_daAVectors[VEC_CG_P][i]));
   }
   if (nextra_atom) {
     for (int  m = 0; m < nextra_atom; m++) {
       double *  pAtom = _daExtraAtom[VEC_CG_P][m];
       int  n = extra_nlen[m];
       for (int  i = 0; i < n; i++) {
 	dPPLocal += pAtom[i] * pAtom[i];
 	dPInfLocal = MAX (dPInfLocal, fabs (pAtom[i]));
       }
     }
   }
   
   double  dPP;
   MPI_Allreduce (&dPPLocal, &dPP, 1, MPI_DOUBLE, MPI_SUM, world);
   
   double  dPInf;
   MPI_Allreduce (&dPInfLocal, &dPInf, 1, MPI_DOUBLE, MPI_MAX, world);
   
   if (nextra_global) {
     for (int  i = 0; i < nextra_global; i++) {
       double *  pGlobal = _daExtraGlobal[VEC_CG_P];
       dPP += pGlobal[i] * pGlobal[i];
       dPInf = MAX (dPInf, fabs (pGlobal[i]));
     }
   }
   
   dStepLength2 = sqrt (dPP);
   dStepLengthInf = dPInf;
   return;
 }
 
 /* ----------------------------------------------------------------------
    Private method step_exceeds_TR_
 ------------------------------------------------------------------------- */
 
 bool MinHFTN::step_exceeds_TR_(const double    dTrustRadius,
 			       const double    dPP,
 			       const double    dPD,
 			       const double    dDD,
 			       double &  dTau) const
 {
   double  dPnewNorm2;
   double  dPnewNormInf;
   calc_plengths_using_mpi_ (dPnewNorm2, dPnewNormInf);
   
   if (dPnewNorm2 > dTrustRadius) {
     dTau = compute_to_tr_ (dPP, dPD, dDD, dTrustRadius,
 			   false, 0.0, 0.0, 0.0);
     return( true );
   }
   
   //---- STEP LENGTH IS NOT TOO LONG.
   dTau = 0.0;
   return( false );
 }
 
 /* ----------------------------------------------------------------------
    Private method step_exceeds_DMAX_
 
    Check that atoms do not move too far:
      for atom coordinates:    limit is dmax
      for extra per-atom DOF:  limit is extra_max[]
      for extra global DOF:    limit is set by modify->max_alpha,
                               which calls fix_box_relax->max_alpha
 ------------------------------------------------------------------------- */
 
 bool MinHFTN::step_exceeds_DMAX_(void) const
 {
   double  dAlpha = dmax * sqrt((double) _nNumUnknowns);
   
   double  dPInfLocal = 0.0;
   for (int  i = 0; i < nvec; i++)
     dPInfLocal = MAX (dPInfLocal, fabs (_daAVectors[VEC_CG_P][i]));
   double  dPInf;
   MPI_Allreduce (&dPInfLocal, &dPInf, 1, MPI_DOUBLE, MPI_MAX, world);
   if (dPInf > dmax)
     return( true );
   if (dPInf > MACHINE_EPS)
     dAlpha = MIN (dAlpha, dmax / dPInf);
   
   if (nextra_atom) {
     for (int  m = 0; m < nextra_atom; m++) {
       double *  pAtom = _daExtraAtom[VEC_CG_P][m];
       dPInfLocal = 0.0;
       int  n = extra_nlen[m];
       for (int  i = 0; i < n; i++)
 	dPInfLocal = MAX (dPInfLocal, fabs (pAtom[i]));
       MPI_Allreduce (&dPInfLocal, &dPInf, 1, MPI_DOUBLE, MPI_MAX, world);
       if (dPInf > extra_max[m])
 	return( true );
       if (dPInf > MACHINE_EPS)
 	dAlpha = MIN (dAlpha, extra_max[m] / dPInf);
     }
   }
   
   if (nextra_global) {
     //---- IF THE MAXIMUM DISTANCE THAT THE GLOBAL BOX CONSTRAINT WILL
     //---- ALLOW IS SMALLER THAN THE PROPOSED DISTANCE, THEN THE STEP
     //---- IS TOO LONG.  PROPOSED DISTANCE IS ESTIMATED BY |P|_INF.
     double  dAlphaExtra = modify->max_alpha (_daExtraGlobal[VEC_CG_P]);
     if (dAlphaExtra < dAlpha)
       return( true );
   }
   
   //---- STEP LENGTH IS NOT TOO LONG.
   return( false );
 }
 
 /* ----------------------------------------------------------------------
    Private method adjust_step_to_tau_
    Adjust the step so that VEC_CG_P = VEC_DIF1 + tau * VEC_CG_D.
 ------------------------------------------------------------------------- */
 
 void MinHFTN::adjust_step_to_tau_(const double tau)
 {
   if (nextra_global) {
     double *  pGlobal  = _daExtraGlobal[VEC_CG_P];
     double *  dGlobal  = _daExtraGlobal[VEC_CG_D];
     double *  d1Global = _daExtraGlobal[VEC_DIF1];
     for (int  i = 0; i < nextra_global; i++)
       pGlobal[i] = d1Global[i] + (tau * dGlobal[i]);
   }
   for (int  i = 0; i < nvec; i++) {
     _daAVectors[VEC_CG_P][i] = _daAVectors[VEC_DIF1][i]
       + (tau * _daAVectors[VEC_CG_D][i]);
   }
   if (nextra_atom) {
     for (int  m = 0; m < nextra_atom; m++) {
       double *  pAtom  = _daExtraAtom[VEC_CG_P][m];
       double *  dAtom  = _daExtraAtom[VEC_CG_D][m];
       double *  d1Atom = _daExtraAtom[VEC_DIF1][m];
       int  n = extra_nlen[m];
       for (int  i = 0; i < n; i++)
 	pAtom[i] = d1Atom[i] + (tau * dAtom[i]);
     }
   }
   return;
 }
 
 /* ----------------------------------------------------------------------
    Private method compute_to_tr_
    Return the value tau that solves
      || p + tau*d ||_2 = dTrustRadius
 
    If both roots are considered, the TR method chooses the one that minimizes
      grad^T (p + tau*d) + 0.5 (p + tau*d)^T H (p + tau*d)
 
    @param[in] dPP                - p^T p
    @param[in] dPD                - p^T d
    @param[in] dDD                - d^T d
    @param[in] dTrustRadius       - distance to match
    @param[in] bConsiderBothRoots - evaluate both roots, or return the positive
    @param[in] dDHD               - d^T H d
    @param[in] dPdotHD            - p^T H d
    @param[in] dGradDotD          - grad(x_k)^T d
 ------------------------------------------------------------------------- */
 
 double MinHFTN::compute_to_tr_(const double  dPP,
 			       const double  dPD,
 			       const double  dDD,
 			       const double  dTrustRadius,
 			       const bool    bConsiderBothRoots,
 			       const double  dDHD,
 			       const double  dPdotHD,
 			       const double  dGradDotD) const
 {
   //---- SOLVE A QUADRATIC EQUATION FOR TAU.
   //---- THE COEFFICIENTS ARE SUCH THAT THERE ARE ALWAYS TWO REAL ROOTS,
   //---- ONE POSITIVE AND ONE NEGATIVE.
   
   //---- CHECK FOR ERRONEOUS DATA.
   if (   (dDD <= 0.0) || (dPP < 0.0) || (dTrustRadius < 0.0)
 	 || (dTrustRadius * dTrustRadius < dPP) ) {
     printf ("HFTN internal error - bad data given to compute_to_tr_()\n");
     return( 0.0 );
   }
   
   double  dTRsqrd = dTrustRadius * dTrustRadius;
   double  dDiscr = (dPD * dPD) - (dDD * (dPP - dTRsqrd));
   dDiscr = MAX (0.0, dDiscr);    //-- SHOULD NEVER BE NEGATIVE
   dDiscr = sqrt (dDiscr);
   
   double  dRootPos = (-dPD + dDiscr) / dDD;
   double  dRootNeg = (-dPD - dDiscr) / dDD;
   
   if (bConsiderBothRoots == false)
     return( dRootPos );
   
   //---- EVALUATE THE CG OBJECTIVE FUNCTION FOR EACH ROOT.
   double  dTmpTerm = dGradDotD + dPdotHD;
   double  dCgRedPos = (dRootPos * dTmpTerm) + (0.5 * dRootPos*dRootPos * dDHD);
   double  dCgRedNeg = (dRootNeg * dTmpTerm) + (0.5 * dRootNeg*dRootNeg * dDHD);
   
   if ((-dCgRedPos) > (-dCgRedNeg))
     return( dRootPos );
   else
     return( dRootNeg );
 }
 
 /* ----------------------------------------------------------------------
    Private method evaluate_dir_der_
    Compute the directional derivative using a finite difference approximation.
    This is equivalent to the Hessian times direction vector p.
    As a side effect, the method computes the energy and forces at x.
  
    On input these must be defined:
      atom->x   - positions at x
      atom->f   - ignored
      nIxDir    - VEC_ index of the direction p
      nIxResult - ignored
    On output these are defined:
      atom->x   - unchanged
      atom->f   - forces evaluated at x, only if bEvaluateAtX is true
      nIxDir    - unchanged
      nIxResult - directional derivative Hp
    During processing these are modified:
      VEC_DIF1
      VEC_DIF2
  
    @param[in] bUseForwardDiffs - if true use forward difference approximation,
                                  else use central difference
    @param[in] nIxDir           - VEC_ index of the direction
    @param[in] nIxResult        - VEC_ index to place the result
                                  (it is acceptable for nIxDir = nIxResult)
    @param[in] bEvaluateAtX     - if true, then evaluate at x before returning
    @param[out] dNewEnergy      - energy at x, if bEvaluateAtX is true
    @param[out] dNewForce2      - |F|_2 at x, if bEvaluateAtX is true
 ------------------------------------------------------------------------- */
 
 void MinHFTN::evaluate_dir_der_(const bool      bUseForwardDiffs,
 				const int       nIxDir,
 				const int       nIxResult,
 				const bool      bEvaluateAtX,
 				double &  dNewEnergy)
 {
   //---- COMPUTE THE MAGNITUDE OF THE DIRECTION VECTOR:  |p|_2.
   double dDirNorm2SqrdLocal = 0.0;
   for (int  i = 0; i < nvec; i++)
     dDirNorm2SqrdLocal
       += _daAVectors[nIxDir][i] * _daAVectors[nIxDir][i];
   if (nextra_atom) {
     for (int  m = 0; m < nextra_atom; m++) {
       double *  iAtom = _daExtraAtom[nIxDir][m];
       int  n = extra_nlen[m];
       for (int  i = 0; i < n; i++)
 	dDirNorm2SqrdLocal += iAtom[i] * iAtom[i];
     }
   }
   double  dDirNorm2Sqrd = 0.0;
   MPI_Allreduce (&dDirNorm2SqrdLocal, &dDirNorm2Sqrd,
 		 1, MPI_DOUBLE, MPI_SUM, world);
   if (nextra_global) {
     for (int  i = 0; i < nextra_global; i++) {
       double *  iGlobal = _daExtraGlobal[nIxDir];
       dDirNorm2Sqrd += iGlobal[i] * iGlobal[i];
     }
   }
   double  dDirNorm2 = sqrt (dDirNorm2Sqrd);
   
   //---- IF THE STEP IS TOO SMALL, RETURN ZERO FOR THE DERIVATIVE.
   if (dDirNorm2 == 0.0) {
     for (int  i = 0; i < nvec; i++)
       _daAVectors[nIxResult][i] = 0.0;
     if (nextra_atom) {
       for (int  m = 0; m < nextra_atom; m++) {
 	double *  iAtom = _daExtraAtom[nIxDir][m];
 	int  n = extra_nlen[m];
 	for (int  i = 0; i < n; i++)
 	  iAtom[i] = 0;
       }
     }
     if (nextra_global) {
       for (int  i = 0; i < nextra_global; i++)
 	_daExtraGlobal[nIxDir][i] = 0.0;
     }
     
     if (bEvaluateAtX) {
       dNewEnergy = energy_force (0);
       neval++;
     }
     
     return;
   }
   
   //---- FORWARD DIFFERENCES ARE LESS ACCURATE THAN CENTRAL DIFFERENCES,
   //---- BUT REQUIRE ONLY 2 ENERGY+FORCE EVALUATIONS VERSUS 3 EVALUATIONS.
   //---- STORAGE REQUIREMENTS ARE THE SAME.
   
   if (bUseForwardDiffs) {
     //---- EQUATION IS FROM THE OLD LAMMPS VERSION, SAND98-8201.
     double  dEps = 2.0 * sqrt (1000.0 * MACHINE_EPS) / dDirNorm2;
     
     //---- SAVE A COPY OF x.
     fix_minimize->store_box();
     for (int  i = 0; i < nvec; i++)
       _daAVectors[VEC_DIF1][i] = xvec[i];
     if (nextra_atom) {
       for (int  m = 0; m < nextra_atom; m++) {
 	double *  xatom  = xextra_atom[m];
 	double *  d1Atom = _daExtraAtom[VEC_DIF1][m];
 	int  n = extra_nlen[m];
 	for (int  i = 0; i < n; i++)
 	  d1Atom[i] = xatom[i];
       }
     }
     if (nextra_global) {
       modify->min_pushstore();
       modify->min_store();
     }
     
     //---- EVALUATE FORCES AT x + eps*p.
     if (nextra_global)
       modify->min_step (dEps, _daExtraGlobal[nIxDir]);
     for (int  i = 0; i < nvec; i++)
       xvec[i] += dEps * _daAVectors[nIxDir][i];
     if (nextra_atom) {
       for (int  m = 0; m < nextra_atom; m++) {
 	double *  xatom = xextra_atom[m];
 	double *  iAtom = _daExtraAtom[nIxDir][m];
 	int  n = extra_nlen[m];
 	for (int  i = 0; i < n; i++)
 	  xatom[i] += dEps * iAtom[i];
 	requestor[m]->min_x_set(m);
       }
     }
     energy_force (0);
     neval++;
     
     //---- STORE THE FORCE IN DIF2.
     if (nextra_global) {
       for (int  i = 0; i < nextra_global; i++)
 	_daExtraGlobal[VEC_DIF2][i] = fextra[i];
     }
     for (int  i = 0; i < nvec; i++)
       _daAVectors[VEC_DIF2][i] = fvec[i];
     if (nextra_atom) {
       for (int  m = 0; m < nextra_atom; m++) {
 	double *  fatom  = fextra_atom[m];
 	double *  d2Atom = _daExtraAtom[VEC_DIF2][m];
 	int  n = extra_nlen[m];
 	for (int  i = 0; i < n; i++)
 	  d2Atom[i] = fatom[i];
       }
     }
     
     //---- MOVE BACK TO x AND EVALUATE FORCES.
     if (nextra_global) {
       modify->min_step (0.0, _daExtraGlobal[VEC_DIF1]);
       modify->min_popstore();
     }
     for (int  i = 0; i < nvec; i++)
       xvec[i] = _daAVectors[VEC_DIF1][i];
     if (nextra_atom) {
       for (int  m = 0; m < nextra_atom; m++) {
 	double *  xatom  = xextra_atom[m];
 	double *  d1Atom = _daExtraAtom[VEC_DIF1][m];
 	int  n = extra_nlen[m];
 	for (int  i = 0; i < n; i++)
 	  xatom[i] += d1Atom[i];
 	requestor[m]->min_x_set(m);
       }
     }
     dNewEnergy = energy_force (0);
     neval++;
     
     //---- COMPUTE THE DIFFERENCE VECTOR:  [grad(x + eps*p) - grad(x)] / eps.
     //---- REMEMBER THAT FORCES = -GRADIENT.
     for (int  i = 0; i < nvec; i++)
       _daAVectors[nIxResult][i] = (fvec[i] - _daAVectors[VEC_DIF2][i]) / dEps;
     if (nextra_atom) {
       for (int  m = 0; m < nextra_atom; m++) {
 	double *  iAtom  = _daExtraAtom[nIxResult][m];
 	double *  d2Atom = _daExtraAtom[VEC_DIF2][m];
 	int  n = extra_nlen[m];
 	for (int  i = 0; i < n; i++)
 	  iAtom[i] = (fextra_atom[m][i] - d2Atom[i]) / dEps;
       }
     }
     if (nextra_global) {
       for (int  i = 0; i < nextra_global; i++)
 	_daExtraGlobal[nIxResult][i]
 	  = (fextra[i] - _daExtraGlobal[VEC_DIF2][i]) / dEps;
     }
   }
   
   else {    //-- bUseForwardDiffs == false
     //---- EQUATION IS FROM THE OLD LAMMPS VERSION, SAND98-8201.
     double  dEps = pow (3000.0 * MACHINE_EPS, 0.33333333) / dDirNorm2;
     
     //---- SAVE A COPY OF x.
     fix_minimize->store_box();
     for (int  i = 0; i < nvec; i++)
       _daAVectors[VEC_DIF1][i] = xvec[i];
     if (nextra_atom) {
       for (int  m = 0; m < nextra_atom; m++) {
 	double *  xatom  = xextra_atom[m];
 	double *  d1Atom = _daExtraAtom[VEC_DIF1][m];
 	int  n = extra_nlen[m];
 	for (int  i = 0; i < n; i++)
 	  d1Atom[i] = xatom[i];
       }
     }
     if (nextra_global) {
       modify->min_pushstore();
       modify->min_store();
     }
     
     //---- EVALUATE FORCES AT x + eps*p.
     if (nextra_global)
       modify->min_step (dEps, _daExtraGlobal[nIxDir]);
     for (int  i = 0; i < nvec; i++)
       xvec[i] += dEps * _daAVectors[nIxDir][i];
     if (nextra_atom) {
       for (int  m = 0; m < nextra_atom; m++) {
 	double *  xatom = xextra_atom[m];
 	double *  iAtom = _daExtraAtom[nIxDir][m];
 	int  n = extra_nlen[m];
 	for (int  i = 0; i < n; i++)
 	  xatom[i] += dEps * iAtom[i];
 	requestor[m]->min_x_set(m);
       }
     }
     energy_force (0);
     neval++;
     
     //---- STORE THE FORCE IN DIF2.
     if (nextra_global) {
       for (int  i = 0; i < nextra_global; i++)
 	_daExtraGlobal[VEC_DIF2][i] = fextra[i];
     }
     for (int  i = 0; i < nvec; i++)
       _daAVectors[VEC_DIF2][i] = fvec[i];
     if (nextra_atom) {
       for (int  m = 0; m < nextra_atom; m++) {
 	double *  fatom  = fextra_atom[m];
 	double *  d2Atom = _daExtraAtom[VEC_DIF2][m];
 	int  n = extra_nlen[m];
 	for (int  i = 0; i < n; i++)
 	  d2Atom[i] = fatom[i];
       }
     }
     
     //---- EVALUATE FORCES AT x - eps*p.
     if (nextra_global)
       modify->min_step (-dEps, _daExtraGlobal[nIxDir]);
     for (int  i = 0; i < nvec; i++)
       xvec[i] = _daAVectors[VEC_DIF1][i]
 	- dEps * _daAVectors[nIxDir][i];
     if (nextra_atom) {
       for (int  m = 0; m < nextra_atom; m++) {
 	double *  xatom  = xextra_atom[m];
 	double *  iAtom  = _daExtraAtom[nIxDir][m];
 	double *  d1Atom = _daExtraAtom[VEC_DIF1][m];
 	int  n = extra_nlen[m];
 	for (int  i = 0; i < n; i++)
 	  xatom[i] = d1Atom[i] - dEps * iAtom[i];
 	requestor[m]->min_x_set(m);
       }
     }
     energy_force (0);
     neval++;
     
     //---- COMPUTE THE DIFFERENCE VECTOR:
     //----     [grad(x + eps*p) - grad(x - eps*p)] / 2*eps.
     //---- REMEMBER THAT FORCES = -GRADIENT.
     if (nextra_global) {
       double *  iGlobal  = _daExtraGlobal[nIxResult];
       double *  d2Global = _daExtraGlobal[VEC_DIF2];
       for (int  i = 0; i < nextra_global; i++)
 	iGlobal[i] = (fextra[i] - d2Global[i]) / (2.0 + dEps);
     }
     for (int  i = 0; i < nvec; i++)
       _daAVectors[nIxResult][i] = 
 	(fvec[i] - _daAVectors[VEC_DIF2][i]) / (2.0 * dEps);
     if (nextra_atom) {
       for (int  m = 0; m < nextra_atom; m++) {
 	double *  fatom  = fextra_atom[m];
 	double *  iAtom  = _daExtraAtom[nIxResult][m];
 	double *  d2Atom = _daExtraAtom[VEC_DIF2][m];
 	int  n = extra_nlen[m];
 	for (int  i = 0; i < n; i++)
 	  iAtom[i] = (fatom[i] - d2Atom[i]) / (2.0 + dEps);
       }
     }
     
     if (bEvaluateAtX) {
       //---- EVALUATE FORCES AT x.
       if (nextra_global) {
 	modify->min_step (0.0, _daExtraGlobal[VEC_DIF1]);
 	modify->min_popstore();
       }
       for (int  i = 0; i < nvec; i++)
 	xvec[i] = _daAVectors[VEC_DIF1][i];
       if (nextra_atom) {
 	for (int  m = 0; m < nextra_atom; m++) {
 	  double *  xatom  = xextra_atom[m];
 	  double *  d1Atom = _daExtraAtom[VEC_DIF1][m];
 	  int  n = extra_nlen[m];
 	  for (int  i = 0; i < n; i++)
 	    xatom[i] = d1Atom[i];
 	  requestor[m]->min_x_set(m);
 	}
       }
       dNewEnergy = energy_force (0);
       neval++;
     }
   }
   
   return;
 }
 
 /* ----------------------------------------------------------------------
    Private method open_hftn_print_file_
 ------------------------------------------------------------------------- */
 
 void MinHFTN::open_hftn_print_file_(void)
 {
   int  nMyRank;
   MPI_Comm_rank (world, &nMyRank);
   
   char  szTmp[50];
   sprintf (szTmp, "progress_MinHFTN_%d.txt", nMyRank);
   _fpPrint = fopen (szTmp, "w");
   if (_fpPrint == NULL) {
     printf ("*** MinHFTN cannot open file '%s'\n", szTmp);
     printf ("*** continuing...\n");
     return;
   }
   
   fprintf (_fpPrint, "  Iter   Evals      Energy         |F|_2"
 	   "    Step   TR used    |step|_2      ared      pred\n");
   return;
 }
 
 /* ----------------------------------------------------------------------
    Private method hftn_print_line_
    Step types:
    1 - Nw   (inner iteration converged like a Newton step)
    2 - TR   (inner iteration reached the trust region boundary)
    3 - Neg  (inner iteration ended with negative curvature)
 ------------------------------------------------------------------------- */
 
 void MinHFTN::hftn_print_line_(const bool    bIsStepAccepted,
 			       const int     nIteration,
 			       const int     nTotalEvals,
 			       const double  dEnergy,
 			       const double  dForce2,
 			       const int     nStepType,
 			       const double  dTrustRadius,
 			       const double  dStepLength2,
 			       const double  dActualRed,
 			       const double  dPredictedRed) const
 {
   const char  sFormat1[]
     = "  %4d   %5d  %14.8f  %11.5e\n";
   const char  sFormatA[]
     = "  %4d   %5d  %14.8f  %11.5e  %3s  %9.3e   %8.2e  %10.3e %10.3e\n";
   const char  sFormatR[]
     = "r %4d   %5d  %14.8f  %11.5e  %3s  %9.3e   %8.2e  %10.3e %10.3e\n";
   
   if (_fpPrint == NULL)
     return;
   
   char  sStepType[4];
   if (nStepType == NO_CGSTEP_BECAUSE_F_TOL_SATISFIED)
     strcpy (sStepType, " - ");
   else if (nStepType == CGSTEP_NEWTON)
     strcpy (sStepType, "Nw ");
   else if (nStepType == CGSTEP_TO_TR)
     strcpy (sStepType, "TR ");
   else if (nStepType == CGSTEP_TO_DMAX)
     strcpy (sStepType, "dmx");
   else if (nStepType == CGSTEP_NEGATIVE_CURVATURE)
     strcpy (sStepType, "Neg");
   else if (nStepType == CGSTEP_MAX_INNER_ITERS)
     strcpy (sStepType, "its");
   else
     strcpy (sStepType, "???");
   
   if (nIteration == -1) {
     fprintf (_fpPrint, sFormat1,
 	     0, nTotalEvals, dEnergy, dForce2);
   }
   else {
     if (bIsStepAccepted)
       fprintf (_fpPrint, sFormatA,
 	       nIteration, nTotalEvals, dEnergy, dForce2,
 	       sStepType, dTrustRadius, dStepLength2,
 	       dActualRed, dPredictedRed);
     else
       fprintf (_fpPrint, sFormatR,
 	       nIteration, nTotalEvals, dEnergy, dForce2,
 	       sStepType, dTrustRadius, dStepLength2,
 	       dActualRed, dPredictedRed);
   }
   
   fflush (_fpPrint);
   return;
 }
 
 /* ----------------------------------------------------------------------
    Private method close_hftn_print_file_
 ------------------------------------------------------------------------- */
 
 void MinHFTN::close_hftn_print_file_(void)
 {
   if (_fpPrint != NULL) fclose (_fpPrint);
   return;
 }
diff --git a/src/min_hftn.h b/src/min_hftn.h
index 6630b0d89..1387581cc 100644
--- a/src/min_hftn.h
+++ b/src/min_hftn.h
@@ -1,126 +1,125 @@
 /* -*- c++ -*- ----------------------------------------------------------
    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 MINIMIZE_CLASS
 
 MinimizeStyle(hftn,MinHFTN)
 
 #else
 
 #ifndef LMP_MIN_HFTN_H
 #define LMP_MIN_HFTN_H
 
 #include "min.h"
 
 namespace LAMMPS_NS
 {
   //---- THE ALGORITHM NEEDS TO STORE THIS MANY ATOM-BASED VECTORS,
   //---- IN ADDITION TO ATOM POSITIONS AND THE FORCE VECTOR.
 
   static const int  NUM_HFTN_ATOM_BASED_VECTORS = 7;
   static const int  VEC_XK    = 0;   //-- ATOM POSITIONS AT SUBITER START
   static const int  VEC_CG_P  = 1;   //-- STEP p IN CG SUBITER
   static const int  VEC_CG_D  = 2;   //-- DIRECTION d IN CG SUBITER
   static const int  VEC_CG_HD = 3;   //-- HESSIAN-VECTOR PRODUCT Hd
   static const int  VEC_CG_R  = 4;   //-- RESIDUAL r IN CG SUBITER
   static const int  VEC_DIF1  = 5;   //-- FOR FINITE DIFFERENCING
   static const int  VEC_DIF2  = 6;   //-- FOR FINITE DIFFERENCING
 
 class MinHFTN : public Min
 {
   public:
   
   MinHFTN (LAMMPS *);
   ~MinHFTN (void);
-  
-  void init_style();
+  void init();
   void setup_style();
   void reset_vectors();
   int iterate (int);
 
   private:
 
   //---- ATOM-BASED STORAGE VECTORS.
   double *   _daAVectors[NUM_HFTN_ATOM_BASED_VECTORS];
   double **  _daExtraAtom[NUM_HFTN_ATOM_BASED_VECTORS];
   
   //---- GLOBAL DOF STORAGE.  ELEMENT [0] IS X0 (XK), NOT USED IN THIS ARRAY.
   double *   _daExtraGlobal[NUM_HFTN_ATOM_BASED_VECTORS];
   
   int     _nNumUnknowns;
   FILE *  _fpPrint;
   
   int   execute_hftn_ (const bool      bPrintProgress,
 		       const double    dInitialEnergy,
 		       const double    dInitialForce2,
 		       double &  dFinalEnergy,
 		       double &  dFinalForce2);
   bool    compute_inner_cg_step_ (const double    dTrustRadius,
 				  const double    dForceTol,
 				  const int       nMaxEvals,
 				  const bool      bHaveEvalAtXin,
 				  const double    dEnergyAtXin,
 				  const double    dForce2AtXin,
 				  double &  dEnergyAtXout,
 				  double &  dForce2AtXout,
 				  int    &  nStepType,
 				  double &  dStepLength2,
 				  double &  dStepLengthInf);
   double  calc_xinf_using_mpi_ (void) const;
   double  calc_dot_prod_using_mpi_ (const int  nIx1,
 				    const int  nIx2) const;
   double  calc_grad_dot_v_using_mpi_ (const int  nIx) const;
   void    calc_dhd_dd_using_mpi_ (double &  dDHD,
 				  double &  dDD) const;
   void    calc_ppnew_pdold_using_mpi_ (double &  dPnewDotPnew,
 				       double &  dPoldDotD) const;
   void    calc_plengths_using_mpi_ (double &  dStepLength2,
 				    double &  dStepLengthInf) const;
   bool    step_exceeds_TR_ (const double    dTrustRadius,
 			    const double    dPP,
 			    const double    dPD,
 			    const double    dDD,
 			    double &  dTau) const;
   bool    step_exceeds_DMAX_ (void) const;
   void    adjust_step_to_tau_ (const double  tau);
   double  compute_to_tr_ (const double  dPP,
 			  const double  dPD,
 			  const double  dDD,
 			  const double  dTrustRadius,
 			  const bool    bConsiderBothRoots,
 			  const double  dDHD,
 			  const double  dPdotHD,
 			  const double  dGradDotD) const;
   void    evaluate_dir_der_ (const bool      bUseForwardDiffs,
 			     const int       nIxDir,
 			     const int       nIxResult,
 			     const bool      bEvaluateAtX,
 			     double &  dNewEnergy);
   void  open_hftn_print_file_ (void);
   void  hftn_print_line_ (const bool    bIsStepAccepted,
 			  const int     nIteration,
 			  const int     nTotalEvals,
 			  const double  dEnergy,
 			  const double  dForce2,
 			  const int     nStepType,
 			  const double  dTrustRadius,
 			  const double  dStepLength2,
 			  const double  dActualRed,
 			  const double  dPredictedRed) const;
   void  close_hftn_print_file_ (void);
 };
  
 }
 
 #endif
 #endif
diff --git a/src/min_linesearch.cpp b/src/min_linesearch.cpp
index 73d9ef83f..b50971a35 100644
--- a/src/min_linesearch.cpp
+++ b/src/min_linesearch.cpp
@@ -1,924 +1,926 @@
 /* ----------------------------------------------------------------------
    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: Aidan Thompson (SNL)
                         improved CG and backtrack ls, added quadratic ls
    Contributing author: Asad Hasan (CMU)
                         added forcezero ls
    Sources: Numerical Recipes frprmn routine
             "Conjugate Gradient Method Without the Agonizing Pain" by
             JR Shewchuk, http://www-2.cs.cmu.edu/~jrs/jrspapers.html#cg
 ------------------------------------------------------------------------- */
 
 #include "math.h"
 #include "min_linesearch.h"
 #include "atom.h"
 #include "update.h"
 #include "neighbor.h"
 #include "domain.h"
 #include "modify.h"
 #include "fix_minimize.h"
 #include "pair.h"
 #include "output.h"
 #include "thermo.h"
 #include "timer.h"
 #include "error.h"
 
 using namespace LAMMPS_NS;
 
 // ALPHA_MAX = max alpha allowed to avoid long backtracks
 // ALPHA_REDUCE = reduction ratio, should be in range [0.5,1)
 // BACKTRACK_SLOPE, should be in range (0,0.5]
 // QUADRATIC_TOL = tolerance on alpha0, should be in range [0.1,1)
 // EMACH = machine accuracy limit of energy changes (1.0e-8)
 // EPS_QUAD = tolerance for quadratic projection
 
 #define ALPHA_MAX 1.0
 #define ALPHA_REDUCE 0.5
 #define BACKTRACK_SLOPE 0.4
 #define QUADRATIC_TOL 0.1
 #define EMACH 1.0e-8
 #define EPS_QUAD 1.0e-28
 
 // same as in other min classes
 
 enum{MAXITER,MAXEVAL,ETOL,FTOL,DOWNHILL,ZEROALPHA,ZEROFORCE,ZEROQUAD};
 
 /* ---------------------------------------------------------------------- */
 
 MinLineSearch::MinLineSearch(LAMMPS *lmp) : Min(lmp)
 {
   searchflag = 1;
   gextra = hextra = NULL;
   x0extra_atom = gextra_atom = hextra_atom = NULL;
 }
 
 /* ---------------------------------------------------------------------- */
 
 MinLineSearch::~MinLineSearch()
 {
   delete [] gextra;
   delete [] hextra;
   delete [] x0extra_atom;
   delete [] gextra_atom;
   delete [] hextra_atom;
 }
 
 /* ---------------------------------------------------------------------- */
 
-void MinLineSearch::init_style()
+void MinLineSearch::init()
 {
+  Min::init();
+
   if (linestyle == 0) linemin = &MinLineSearch::linemin_backtrack;
   else if (linestyle == 1) linemin = &MinLineSearch::linemin_quadratic;
   else if (linestyle == 2) linemin = &MinLineSearch::linemin_forcezero;
 
   delete [] gextra;
   delete [] hextra;
   gextra = hextra = NULL;
 
   delete [] x0extra_atom;
   delete [] gextra_atom;
   delete [] hextra_atom;
   x0extra_atom = gextra_atom = hextra_atom = NULL;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void MinLineSearch::setup_style()
 {
   // memory for x0,g,h for atomic dof
 
   fix_minimize->add_vector(3);
   fix_minimize->add_vector(3);
   fix_minimize->add_vector(3);
 
   // memory for g,h for extra global dof, fix stores x0
 
   if (nextra_global) {
     gextra = new double[nextra_global];
     hextra = new double[nextra_global];
   }
 
   // memory for x0,g,h for extra per-atom dof
 
   if (nextra_atom) {
     x0extra_atom = new double*[nextra_atom];
     gextra_atom = new double*[nextra_atom];
     hextra_atom = new double*[nextra_atom];
 
     for (int m = 0; m < nextra_atom; m++) {
       fix_minimize->add_vector(extra_peratom[m]);
       fix_minimize->add_vector(extra_peratom[m]);
       fix_minimize->add_vector(extra_peratom[m]);
     }
   }
 }
 
 /* ----------------------------------------------------------------------
    set current vector lengths and pointers
    called after atoms have migrated
 ------------------------------------------------------------------------- */
 
 void MinLineSearch::reset_vectors()
 {
   // atomic dof
 
   nvec = 3 * atom->nlocal;
   if (nvec) xvec = atom->x[0];
   if (nvec) fvec = atom->f[0];
   x0 = fix_minimize->request_vector(0);
   g = fix_minimize->request_vector(1);
   h = fix_minimize->request_vector(2);
 
   // extra per-atom dof
 
   if (nextra_atom) {
     int n = 3;
     for (int m = 0; m < nextra_atom; m++) {
       extra_nlen[m] = extra_peratom[m] * atom->nlocal;
       requestor[m]->min_xf_pointers(m,&xextra_atom[m],&fextra_atom[m]);
       x0extra_atom[m] = fix_minimize->request_vector(n++);
       gextra_atom[m] = fix_minimize->request_vector(n++);
       hextra_atom[m] = fix_minimize->request_vector(n++);
     }
   }
 }
 
 /* ----------------------------------------------------------------------
    line minimization methods
    find minimum-energy starting at x along h direction
    input args:   eoriginal = energy at initial x
    input extra:  n,x,x0,f,h for atomic, extra global, extra per-atom dof
    output args:  return 0 if successful move, non-zero alpha
                  return non-zero if failed
                  alpha = distance moved along h for x at min eng config
                  update neval counter of eng/force function evaluations
                  output extra: if fail, energy_force() of original x
                  if succeed, energy_force() at x + alpha*h
                  atom->x = coords at new configuration
                  atom->f = force at new configuration
                  ecurrent = energy of new configuration
 ------------------------------------------------------------------------- */
 
 /* ----------------------------------------------------------------------
    linemin: backtracking line search (Proc 3.1, p 41 in Nocedal and Wright)
    uses no gradient info, but should be very robust
    start at maxdist, backtrack until energy decrease is sufficient
 ------------------------------------------------------------------------- */
 
 int MinLineSearch::linemin_backtrack(double eoriginal, double &alpha)
 {
   int i,m,n;
   double fdothall,fdothme,hme,hmax,hmaxall;
   double de_ideal,de;
   double *xatom,*x0atom,*fatom,*hatom;
 
   // fdothall = projection of search dir along downhill gradient
   // if search direction is not downhill, exit with error
 
   fdothme = 0.0;
   for (i = 0; i < nvec; i++) fdothme += fvec[i]*h[i];
   if (nextra_atom)
     for (m = 0; m < nextra_atom; m++) {
       fatom = fextra_atom[m];
       hatom = hextra_atom[m];
       n = extra_nlen[m];
       for (i = 0; i < n; i++) fdothme += fatom[i]*hatom[i];
     }
   MPI_Allreduce(&fdothme,&fdothall,1,MPI_DOUBLE,MPI_SUM,world);
   if (nextra_global)
     for (i = 0; i < nextra_global; i++) fdothall += fextra[i]*hextra[i];
   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
   // 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
   // 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 < nvec; i++) hme = MAX(hme,fabs(h[i]));
   MPI_Allreduce(&hme,&hmaxall,1,MPI_DOUBLE,MPI_MAX,world);
   alpha = MIN(ALPHA_MAX,dmax/hmaxall);
   if (nextra_atom)
     for (m = 0; m < nextra_atom; m++) {
       hatom = hextra_atom[m];
       n = extra_nlen[m];
       hme = 0.0;
       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);
       hmaxall = MAX(hmaxall,hmax);
     }
   if (nextra_global) {
     double alpha_extra = modify->max_alpha(hextra);
     alpha = MIN(alpha,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
 
   fix_minimize->store_box();
   for (i = 0; i < nvec; i++) x0[i] = xvec[i];
   if (nextra_atom)
     for (m = 0; m < nextra_atom; m++) {
       xatom = xextra_atom[m];
       x0atom = x0extra_atom[m];
       n = extra_nlen[m];
       for (i = 0; i < n; i++) x0atom[i] = xatom[i];
     }
   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);
   // 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);
 
   // backtrack with alpha until energy decrease is sufficient
 
   while (1) {
     ecurrent = alpha_step(alpha,1);
 
     // if energy change is better than ideal, exit with success
 
     de_ideal = -BACKTRACK_SLOPE*alpha*fdothall;
     de = ecurrent - eoriginal;
     if (de <= de_ideal) {
       if (nextra_global) {
 	int itmp = modify->min_reset_ref();
 	if (itmp) ecurrent = energy_force(1);
       }
       return 0;
     }
 
     // reduce alpha
 
     alpha *= ALPHA_REDUCE;
 
     // backtracked all the way to 0.0
     // reset to starting point, exit with error
 
     if (alpha <= 0.0 || de_ideal >= -EMACH) {
       ecurrent = alpha_step(0.0,0);
       return ZEROALPHA;
     }
   }
 }
 
 /* ----------------------------------------------------------------------
     // linemin: quadratic line search (adapted from Dennis and Schnabel)
     // The objective function is approximated by a quadratic 
     // function in alpha, for sufficiently small alpha. 
     // This idea is the same as that used in the well-known secant
     // method. However, since the change in the objective function 
     // (difference of two finite numbers) is not known as accurately 
     // as the gradient (which is close to zero), all the expressions 
     // are written in terms of gradients. In this way, we can converge 
     // the LAMMPS forces much closer to zero. 
     //
     // We know E,Eprev,fh,fhprev. The Taylor series about alpha_prev 
     // truncated at the quadratic term is:
     //
     //     E = Eprev - del_alpha*fhprev + (1/2)del_alpha^2*Hprev
     //
     // and
     //
     //     fh = fhprev - del_alpha*Hprev
     //
     // where del_alpha = alpha-alpha_prev
     //
     // We solve these two equations for Hprev and E=Esolve, giving:
     //
     //     Esolve = Eprev - del_alpha*(f+fprev)/2
     //
     // We define relerr to be:
     //
     //      relerr = |(Esolve-E)/Eprev|
     //             = |1.0 - (0.5*del_alpha*(f+fprev)+E)/Eprev|
     // 
     // If this is accurate to within a reasonable tolerance, then
     // we go ahead and use a secant step to fh = 0:
     //
     //      alpha0 = alpha - (alpha-alphaprev)*fh/delfh;
     //
 ------------------------------------------------------------------------- */
 
 int MinLineSearch::linemin_quadratic(double eoriginal, double &alpha)
 {
   int i,m,n;
   double fdothall,fdothme,hme,hmax,hmaxall;
   double de_ideal,de;
   double delfh,engprev,relerr,alphaprev,fhprev,ff,fh,alpha0;
   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
 
   fdothme = 0.0;
   for (i = 0; i < nvec; i++) fdothme += fvec[i]*h[i];
   if (nextra_atom)
     for (m = 0; m < nextra_atom; m++) {
       fatom = fextra_atom[m];
       hatom = hextra_atom[m];
       n = extra_nlen[m];
       for (i = 0; i < n; i++) fdothme += fatom[i]*hatom[i];
     }
   MPI_Allreduce(&fdothme,&fdothall,1,MPI_DOUBLE,MPI_SUM,world);
   if (nextra_global)
     for (i = 0; i < nextra_global; i++) fdothall += fextra[i]*hextra[i];
   if (output->thermo->normflag) fdothall /= atom->natoms;
   if (fdothall <= 0.0) return DOWNHILL;
 
   // 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 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 < nvec; i++) hme = MAX(hme,fabs(h[i]));
   MPI_Allreduce(&hme,&hmaxall,1,MPI_DOUBLE,MPI_MAX,world);
   alphamax = MIN(ALPHA_MAX,dmax/hmaxall);
   if (nextra_atom)
     for (m = 0; m < nextra_atom; m++) {
       hatom = hextra_atom[m];
       n = extra_nlen[m];
       hme = 0.0;
       for (i = 0; i < n; i++) hme = MAX(hme,fabs(hatom[i]));
       MPI_Allreduce(&hme,&hmax,1,MPI_DOUBLE,MPI_MAX,world);
       alphamax = MIN(alphamax,extra_max[m]/hmax);
       hmaxall = MAX(hmaxall,hmax);
     }
   if (nextra_global) {
     double alpha_extra = modify->max_alpha(hextra);
     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
 
   fix_minimize->store_box();
   for (i = 0; i < nvec; i++) x0[i] = xvec[i];
   if (nextra_atom)
     for (m = 0; m < nextra_atom; m++) {
       xatom = xextra_atom[m];
       x0atom = x0extra_atom[m];
       n = extra_nlen[m];
       for (i = 0; i < n; i++) x0atom[i] = xatom[i];
     }
   if (nextra_global) modify->min_store();
 
   // 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);
   // 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);
 
   while (1) {
     ecurrent = alpha_step(alpha,1);
 
     // compute new fh, alpha, delfh
 
     dot[0] = dot[1] = 0.0;
     for (i = 0; i < nvec; i++) {
       dot[0] += fvec[i]*fvec[i];
       dot[1] += fvec[i]*h[i];
     }
     if (nextra_atom)
       for (m = 0; m < nextra_atom; m++) {
 	fatom = fextra_atom[m];
 	hatom = hextra_atom[m];
 	n = extra_nlen[m];
 	for (i = 0; i < n; i++) {
 	  dot[0] += fatom[i]*fatom[i];
 	  dot[1] += fatom[i]*hatom[i];
 	}
       }
     MPI_Allreduce(dot,dotall,2,MPI_DOUBLE,MPI_SUM,world);
     if (nextra_global) {
       for (i = 0; i < nextra_global; i++) {
 	dotall[0] += fextra[i]*fextra[i];
 	dotall[1] += fextra[i]*hextra[i];
       }
     }
     ff = dotall[0];
     fh = dotall[1];
     if (output->thermo->normflag) {
       ff /= atom->natoms;
       fh /= atom->natoms;
     }
 
     delfh = fh - fhprev;
 
     // if fh or delfh is epsilon, reset to starting point, exit with error
 
     if (fabs(fh) < EPS_QUAD || fabs(delfh) < EPS_QUAD) {
       ecurrent = alpha_step(0.0,0);
       return ZEROQUAD;
     }
 
     // Check if ready for quadratic projection, equivalent to secant method
     // alpha0 = projected alpha
 
     relerr = fabs(1.0-(0.5*(alpha-alphaprev)*(fh+fhprev)+ecurrent)/engprev);
     alpha0 = alpha - (alpha-alphaprev)*fh/delfh;
 
     if (relerr <= QUADRATIC_TOL && alpha0 > 0.0 && alpha0 < alphamax) {
       ecurrent = alpha_step(alpha0,1);
       if (ecurrent - eoriginal < EMACH) {
 	if (nextra_global) {
 	  int itmp = modify->min_reset_ref();
 	  if (itmp) ecurrent = energy_force(1);
 	}
 	return 0;
       }
     }
 
     // if backtracking energy change is better than ideal, exit with success
 
     de_ideal = -BACKTRACK_SLOPE*alpha*fdothall;
     de = ecurrent - eoriginal;
 
     if (de <= de_ideal) {
       if (nextra_global) {
 	int itmp = modify->min_reset_ref();
 	if (itmp) ecurrent = energy_force(1);
       }
       return 0;
     }
 
     // save previous state
 
     fhprev = fh;
     engprev = ecurrent;
     alphaprev = alpha;
 
     // reduce alpha
 
     alpha *= ALPHA_REDUCE;
 
     // backtracked all the way to 0.0
     // reset to starting point, exit with error
 
     if (alpha <= 0.0 || de_ideal >= -EMACH) {
       ecurrent = alpha_step(0.0,0);
       return ZEROALPHA;
     }
   }
 }
 
 /* ----------------------------------------------------------------------
 
 forcezero linesearch method - seeks a zero of force in a robust manner. 
     (motivated by a line minimization routine of f77 DYNAMO code)
 
 central idea: 
   In each linesearch we attempt to converge to a zero of force 
   (usual case) or reduces forces (worst case).
   Energy does not play any role in the search procedure, 
   except we ensure that it doesn't increase.
 
 pseudo code:
   i)  Fix an alpha max:
         // also account for nextra atom & global 
 	alpha_max <= dmax/hmaxall 
 
   ii) Initialize:
         fhCurr = current_force.dot.search_direction
         fhoriginal = fhCurr
         // try decreasing the energy to 1/10 of initial
         alpha_init = 0.1*fabs(eoriginal)/fhCurr; 
         // initial alpha is smaller than alpha_max
         alpha_del = MIN(alpha_init, 0.5*alpha_max);
         alpha = 0.0
   iii) Loop:
         backtrack = false
 	alpha += alpha_del
 	if (alpha > alpha_max):
 	   // we have done enough in the search space
 	   EXIT with success
 
         Step with the new alpha
 	Compute:
 	   current energy and 'fhCurr'
 	   de = ecurrent - eprev
 
 	   // ZERO_ENERGY = 1e-12, is max allowed energy increase
 	   if (de > ZERO_ENERGY):
 	      bactrack = true
 
 	   // GRAD_TOL = 0.1
 	   if ( (not backtrack) && (fabs(fhCurr/fh0) <= GRAD_TOL) ): 
 	      // forces sufficiently reduced without energy increase
 	      EXIT with success
 
 	   // projected force changed sign but didn't become small enough
 	   if ( fhCurr < 0):
 	      backtrack = true
 
 	   if (bactrack):
 	      // forces along search direction changed sign
 	      if (fhCurr < 0):
 	         Get alpha_del by solving for zero 
                     of force (1D Newton's Method)
 	      else:
 	         // force didn't change sign but only energy increased,
 		 // we overshot a minimum which is very close to a 
                  // maximum (or there is an inflection point)
 
 		 // New alpha_del should be much smaller
 		 // ALPHA_FACT = 0.1
 		 alpha_del *= ALPHA_FACT
 
 		 // Check to see if new 'alpha_del' isn't too small
 		 if (alpha_del < MIN_ALPHA):
 		    EXIT with failure("linesearch alpha is zero")
 
 	       Undo the step of alpha.
 
 	   // continue the loop with a new alpha_del
 	   else:   
 	      Get new alpha_del by linearizing force and solving for its zero
 
  ---------------------------------------------------------------------- */
 
 int MinLineSearch::linemin_forcezero(double eoriginal, double &alpha)
 {
   int i,m,n;
   double fdothall,fdothme,hme,hmax,hmaxall;
   double de_ideal,de;
   double *xatom,*x0atom,*fatom,*hatom;
 
   double alpha_max, alpha_init, alpha_del; 
   // projection of: force on itself, current force on search direction, 
   double ffCurr, fhCurr;
   // previous force on search direction, initial force on search direction
   double fhPrev, fhoriginal;
   // current energy, previous energy
   double engCurr, engPrev;
   bool backtrack;
 
   // hardcoded constants
 
   // factor by which alpha is reduced when backtracking
   double ALPHA_FACT = 0.1;
   // maximum amount by which we'll permit energy increase
   double ZERO_ENERGY = 1e-12;
   // fraction to which we want to reduce the directional derivative
   double GRAD_TOL = 0.1;
   // largest alpha increment which will trigger a failed_linesearch
   double MIN_ALPHA_FAC = 1e-20;
   double LIMIT_BOOST = 4.0;
 
   // fdothall = projection of search dir along downhill gradient
   // if search direction is not downhill, exit with error
 
   fdothme = 0.0;
   for (i = 0; i < nvec; i++) fdothme += fvec[i]*h[i];
   if (nextra_atom)
     for (m = 0; m < nextra_atom; m++) {
       fatom = fextra_atom[m];
       hatom = hextra_atom[m];
       n = extra_nlen[m];
       for (i = 0; i < n; i++) 
 	fdothme += fatom[i]*hatom[i];
     }
 
   MPI_Allreduce(&fdothme,&fdothall,1,MPI_DOUBLE,MPI_SUM,world);
   if (nextra_global)
     for (i = 0; i < nextra_global; i++) 
       fdothall += fextra[i]*hextra[i];
   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
   // 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 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 < nvec; i++) 
     hme = MAX(hme,fabs(h[i]));
 
   MPI_Allreduce(&hme,&hmaxall,1,MPI_DOUBLE,MPI_MAX,world);
   alpha_max = dmax/hmaxall;
   if (nextra_atom)
     for (m = 0; m < nextra_atom; m++) {
       hatom = hextra_atom[m];
       n = extra_nlen[m];
       hme = 0.0;
       for (i = 0; i < n; i++) hme = MAX(hme,fabs(hatom[i]));
       MPI_Allreduce(&hme,&hmax,1,MPI_DOUBLE,MPI_MAX,world);
       alpha_max = MIN(alpha_max,extra_max[m]/hmax);
       hmaxall = MAX(hmaxall,hmax);
     }
 
   if (nextra_global) {
     double alpha_extra = modify->max_alpha(hextra);
     alpha_max = MIN(alpha_max, 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
 
   fix_minimize->store_box();
 
   for (i = 0; i < nvec; i++) x0[i] = xvec[i];
   if (nextra_atom)
     for (m = 0; m < nextra_atom; m++) {
       xatom = xextra_atom[m];
       x0atom = x0extra_atom[m];
       n = extra_nlen[m];
       for (i = 0; i < n; i++) x0atom[i] = xatom[i];
     }
 
   if (nextra_global) modify->min_store();
 
   // initialize important variables before main linesearch loop 
 
   ffCurr = 0.0;
   fhCurr = fdothall;
   fhoriginal = fhCurr;
   engCurr = eoriginal; 
 
   // stores energy difference due to the current move
 
   de = 0.0;
 
   // choosing the initial alpha that we'll use
   // rough estimate that'll decrease energy to 1/10
 
   alpha_init = 0.1*fabs(eoriginal)/fdothall;
 
   // initialize aplha to 0.0 
 
   alpha = 0.0;
   
   // compute increment to alpha, ensure that we 
   // don't take the largest allowed alpha
   // first alpha that will actually apply
 
   alpha_del = MIN(alpha_init,0.5*alpha_max);
  
   // main linesearch loop
 
   while (1) {
     backtrack = false;
     fhPrev = fhCurr;
     engPrev = engCurr;
 
     // apply the increment to alpha, but first 
     // check whether we are still in allowed search space
 
     alpha += alpha_del;
     if (alpha > alpha_max) {
 
       // undo the increment 
 
       alpha -= alpha_del; 
       if (nextra_global) {
 	int itmp = modify->min_reset_ref();
 	if (itmp) ecurrent = energy_force(1);
       }
 
       // exit linesearch with success: have done 
       // enough in allowed search space
 
       return 0;
     }
 
     // move the system 
 
     // '1' updates coordinates of atoms which cross PBC
 
     engCurr = alpha_step(alpha,1);
     ecurrent = engCurr;
 
     // compute the new directional derivative and also f_dot_f
 
     fhCurr = compute_dir_deriv(ffCurr);
 
     // energy change
 
     de = engCurr - engPrev;
 
     // if the function value increases measurably, 
     // then we have to reduce alpha
 
     if (de >= ZERO_ENERGY)
       backtrack = true;
 
     // check if the directional derivative has sufficiently decreased
     // NOTE: the fabs is essential here
 
     if ((!backtrack) && (fabs(fhCurr/fhoriginal) <= GRAD_TOL)) {
       if (nextra_global) {
 	int itmp = modify->min_reset_ref();
 	if (itmp) ecurrent = energy_force(1);
       }
 
       // we are done
 
       return 0;
     }
 
     // check if the directional derivative changed sign 
     // but it's not small: we overshot the minima -- BACKTRACK
 
     if (fhCurr < 0.0)
       backtrack = true;
 
     // backtrack by undoing step and choosing a new alpha
 
     if (backtrack) {
 
       // move back
 
       alpha -= alpha_del;
       
       // choose new alpha 
       // if the force changed sign, linearize force and 
       // solve for new alpha_del
 
       if (fhCurr < 0.0)
 	alpha_del *= fhPrev/(fhPrev - fhCurr);
       else
 
     // force didn't change sign but only energy increased, 
     // we overshot a minimum which is very close to a maxima 
     // (or there is an inflection point)
     // new alpha_del should be much smaller
 
 	alpha_del *= ALPHA_FACT;
 
       // since we moved back ...
 
       engCurr = engPrev;
       ecurrent = engCurr;
       fhCurr = fhPrev;
 
       // if new move is too small then we have failed; 
       // exit with 'failed_linesearch'
 
       if (hmaxall*alpha_del <= MIN_ALPHA_FAC) {
 
 	// undo all line minization moves
 
 	engCurr = alpha_step(0.0,1); 
 	ecurrent= engCurr;
 	return ZEROALPHA;
       }
 
     } else { 
 
       // get a new alpha by linearizing force and start over 
        
       double boostFactor = LIMIT_BOOST;
       
       // avoids problems near an energy inflection point 
       
       if (fhPrev > fhCurr)
 	boostFactor = fhCurr/(fhPrev - fhCurr);
 
       // don't want to boost too much 
 
       boostFactor = MIN(boostFactor, LIMIT_BOOST); 
       alpha_del *= boostFactor; 
     }
   }
 }
 
 /* ---------------------------------------------------------------------- */
 
 double MinLineSearch::alpha_step(double alpha, int resetflag)
 {
   int i,n,m;
   double *xatom,*x0atom,*hatom;
 
   // reset to starting point
 
   if (nextra_global) modify->min_step(0.0,hextra);
   for (i = 0; i < nvec; i++) xvec[i] = x0[i];
   if (nextra_atom)
     for (m = 0; m < nextra_atom; m++) {
       xatom = xextra_atom[m];
       x0atom = x0extra_atom[m];
       n = extra_nlen[m];
       for (i = 0; i < n; i++) xatom[i] = x0atom[i];
       requestor[m]->min_x_set(m);
     }
   
   // step forward along h
 
   if (alpha > 0.0) {
     if (nextra_global) modify->min_step(alpha,hextra);
     for (i = 0; i < nvec; i++) xvec[i] += alpha*h[i];
     if (nextra_atom)
       for (m = 0; m < nextra_atom; m++) {
 	xatom = xextra_atom[m];
 	hatom = hextra_atom[m];
 	n = extra_nlen[m];
 	for (i = 0; i < n; i++) xatom[i] += alpha*hatom[i];
 	requestor[m]->min_x_set(m);
       }
   }
 
   // compute and return new energy
 
   neval++;
   return energy_force(resetflag);
 }
 
 /* ---------------------------------------------------------------------- */
 
 // compute projection of force on: itself and the search direction 
 
 double MinLineSearch::compute_dir_deriv(double &ff)
 {
    int i,m,n;
    double *xatom,*hatom, *fatom;
    double dot[2],dotall[2];
    double fh;
 
    // compute new fh, alpha, delfh
 
     dot[0] = dot[1] = 0.0;
     for (i = 0; i < nvec; i++) {
       dot[0] += fvec[i]*fvec[i];
       dot[1] += fvec[i]*h[i];
     }
 
     if (nextra_atom)
       for (m = 0; m < nextra_atom; m++) {
         fatom = fextra_atom[m];
         hatom = hextra_atom[m];
         n = extra_nlen[m];
         for (i = 0; i < n; i++) {
           dot[0] += fatom[i]*fatom[i];
           dot[1] += fatom[i]*hatom[i];
         }
       }
 
     MPI_Allreduce(dot,dotall,2,MPI_DOUBLE,MPI_SUM,world);
     if (nextra_global) {
       for (i = 0; i < nextra_global; i++) {
         dotall[0] += fextra[i]*fextra[i];
         dotall[1] += fextra[i]*hextra[i];
       }
     }
 
     ff = dotall[0];
     fh = dotall[1];
     if (output->thermo->normflag) {
       ff /= atom->natoms;
       fh /= atom->natoms;
     }
 
     return fh;
 }
diff --git a/src/min_linesearch.h b/src/min_linesearch.h
index cabf5f14d..bd539747d 100644
--- a/src/min_linesearch.h
+++ b/src/min_linesearch.h
@@ -1,57 +1,57 @@
 /* -*- c++ -*- ----------------------------------------------------------
    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_MIN_LSRCH_H
 #define LMP_MIN_LSRCH_H
 
 #include "min.h"
 
 namespace LAMMPS_NS {
 
 class MinLineSearch : public Min {
  public:
   MinLineSearch(class LAMMPS *);
   ~MinLineSearch();
-  void init_style();
+  void init();
   void setup_style();
   void reset_vectors();
 
  protected:
   // vectors needed by linesearch minimizers
   // allocated and stored by fix_minimize
   // x,f are stored by parent or Atom class or Pair class
 
   double *x0;                 // coords at start of linesearch
   double *g;                  // old gradient vector
   double *h;                  // search direction vector
 
   double *gextra;             // g,h for extra global dof, x0 is stored by fix
   double *hextra;
 
   double **x0extra_atom;      // x0,g,h for extra per-atom dof
   double **gextra_atom;
   double **hextra_atom;
 
   typedef int (MinLineSearch::*FnPtr)(double, double &);
   FnPtr linemin;
   int linemin_backtrack(double, double &);
   int linemin_quadratic(double, double &);
   int linemin_forcezero(double, double &);
 
   double alpha_step(double, int);
   double compute_dir_deriv(double &);
 };
 
 }
 
 #endif
diff --git a/src/min_quickmin.cpp b/src/min_quickmin.cpp
index 07a887073..e12379827 100644
--- a/src/min_quickmin.cpp
+++ b/src/min_quickmin.cpp
@@ -1,237 +1,239 @@
 /* ----------------------------------------------------------------------
    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 "lmptype.h"
 #include "mpi.h"
 #include "math.h"
 #include "min_quickmin.h"
 #include "universe.h"
 #include "atom.h"
 #include "force.h"
 #include "update.h"
 #include "output.h"
 #include "timer.h"
 #include "error.h"
 
 using namespace LAMMPS_NS;
 
 // EPS_ENERGY = minimum normalization for energy tolerance
 
 #define EPS_ENERGY 1.0e-8
 
 // same as in other min classes
 
 enum{MAXITER,MAXEVAL,ETOL,FTOL,DOWNHILL,ZEROALPHA,ZEROFORCE,ZEROQUAD};
 
 #define DELAYSTEP 5
 
 /* ---------------------------------------------------------------------- */
 
 MinQuickMin::MinQuickMin(LAMMPS *lmp) : Min(lmp) {}
 
 /* ---------------------------------------------------------------------- */
 
-void MinQuickMin::init_style()
+void MinQuickMin::init()
 {
+  Min::init();
+
   dt = update->dt;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void MinQuickMin::setup_style()
 {
   double **v = atom->v;
   int nlocal = atom->nlocal;
 
   for (int i = 0; i < nlocal; i++)
     v[i][0] = v[i][1] = v[i][2] = 0.0;
 }
 
 /* ----------------------------------------------------------------------
    set current vector lengths and pointers
    called after atoms have migrated
 ------------------------------------------------------------------------- */
 
 void MinQuickMin::reset_vectors()
 {
   // atomic dof
 
   nvec = 3 * atom->nlocal;
   if (nvec) xvec = atom->x[0];
   if (nvec) fvec = atom->f[0];
 }
 
 /* ----------------------------------------------------------------------
    minimization via QuickMin damped dynamics
 ------------------------------------------------------------------------- */
 
 int MinQuickMin::iterate(int maxiter)
 {
   bigint ntimestep;
   double vmax,vdotf,vdotfall,fdotf,fdotfall,scale;
   double dtvone,dtv,dtfm;
   int flag,flagall;
 
   alpha_final = 0.0;
   bigint last_negative = update->ntimestep;
 
   for (int iter = 0; iter < maxiter; iter++) {
     ntimestep = ++update->ntimestep;
     niter++;
 
     // zero velocity if anti-parallel to force
     // else project velocity in direction of force
 
     double **v = atom->v;
     double **f = atom->f;
     int nlocal = atom->nlocal;
 
     vdotf = 0.0;
     for (int i = 0; i < nlocal; i++)
       vdotf += v[i][0]*f[i][0] + v[i][1]*f[i][1] + v[i][2]*f[i][2];
     MPI_Allreduce(&vdotf,&vdotfall,1,MPI_DOUBLE,MPI_SUM,world);
 
     // sum vdotf over replicas, if necessary
     // this communicator would be invalid for multiprocess replicas
 
     if (update->multireplica == 1) {
       vdotf = vdotfall;
       MPI_Allreduce(&vdotf,&vdotfall,1,MPI_DOUBLE,MPI_SUM,universe->uworld);
     }
 
     if (vdotfall < 0.0) {
       last_negative = ntimestep;
       for (int i = 0; i < nlocal; i++)
 	v[i][0] = v[i][1] = v[i][2] = 0.0;
 
     } else {
       fdotf = 0.0;
       for (int i = 0; i < nlocal; i++)
 	fdotf += f[i][0]*f[i][0] + f[i][1]*f[i][1] + f[i][2]*f[i][2];
       MPI_Allreduce(&fdotf,&fdotfall,1,MPI_DOUBLE,MPI_SUM,world);
 
       // sum fdotf over replicas, if necessary
       // this communicator would be invalid for multiprocess replicas
 
       if (update->multireplica == 1) {
 	fdotf = fdotfall;
 	MPI_Allreduce(&fdotf,&fdotfall,1,MPI_DOUBLE,MPI_SUM,universe->uworld);
       }
 
       if (fdotfall == 0.0) scale = 0.0;
       else scale = vdotfall/fdotfall;
       for (int i = 0; i < nlocal; i++) {
 	v[i][0] = scale * f[i][0];
 	v[i][1] = scale * f[i][1];
 	v[i][2] = scale * f[i][2];
       }
     }
 
     // limit timestep so no particle moves further than dmax
 
     double *rmass = atom->rmass;
     double *mass = atom->mass;
     int *type = atom->type;
 
     dtvone = dt;
 
     for (int i = 0; i < nlocal; i++) {
       vmax = MAX(fabs(v[i][0]),fabs(v[i][1]));
       vmax = MAX(vmax,fabs(v[i][2]));
       if (dtvone*vmax > dmax) dtvone = dmax/vmax;
     }
     MPI_Allreduce(&dtvone,&dtv,1,MPI_DOUBLE,MPI_MIN,world);
 
     // min dtv over replicas, if necessary
     // this communicator would be invalid for multiprocess replicas
 
     if (update->multireplica == 1) {
       dtvone = dtv;
       MPI_Allreduce(&dtvone,&dtv,1,MPI_DOUBLE,MPI_MIN,universe->uworld);
     }
 
     // Euler integration step
 
     double **x = atom->x;
     
     if (rmass) {
       for (int i = 0; i < nlocal; i++) {
 	dtfm = dtv / rmass[i];
 	x[i][0] += dtv * v[i][0];
 	x[i][1] += dtv * v[i][1];
 	x[i][2] += dtv * v[i][2];
 	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++) {
 	dtfm = dtv / mass[type[i]];
 	x[i][0] += dtv * v[i][0];
 	x[i][1] += dtv * v[i][1];
 	x[i][2] += dtv * v[i][2];
 	v[i][0] += dtfm * f[i][0];
 	v[i][1] += dtfm * f[i][1];
 	v[i][2] += dtfm * f[i][2];
       }
     }
     
     eprevious = ecurrent;
     ecurrent = energy_force(0);
     neval++;
 
     // energy tolerance criterion
     // only check after DELAYSTEP elapsed since velocties reset to 0
     // sync across replicas if running multi-replica minimization
 
     if (update->etol > 0.0 && ntimestep-last_negative > DELAYSTEP) {
       if (update->multireplica == 0) {
 	if (fabs(ecurrent-eprevious) < 
 	    update->etol * 0.5*(fabs(ecurrent) + fabs(eprevious) + EPS_ENERGY))
 	  return ETOL;
       } else {
 	if (fabs(ecurrent-eprevious) < 
 	    update->etol * 0.5*(fabs(ecurrent) + fabs(eprevious) + EPS_ENERGY))
 	  flag = 0;
 	else flag = 1;
 	MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,universe->uworld);
 	if (flagall == 0) return ETOL;
       }
     }
 
     // force tolerance criterion
     // sync across replicas if running multi-replica minimization
 
     if (update->ftol > 0.0) {
       fdotf = fnorm_sqr();
       if (update->multireplica == 0) {
 	if (fdotf < update->ftol*update->ftol) return FTOL;
       } else {
 	if (fdotf < update->ftol*update->ftol) flag = 0;
 	else flag = 1;
 	MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,universe->uworld);
 	if (flagall == 0) return FTOL;
       }
     }
 
     // output for thermo, dump, restart files
 
     if (output->next == ntimestep) {
       timer->stamp();
       output->write(ntimestep);
       timer->stamp(Timer::OUTPUT);
     }
   }
   
   return MAXITER;
 }
diff --git a/src/min_quickmin.h b/src/min_quickmin.h
index 2ced7dce5..e46bcb25e 100644
--- a/src/min_quickmin.h
+++ b/src/min_quickmin.h
@@ -1,43 +1,43 @@
 /* -*- c++ -*- ----------------------------------------------------------
    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 MINIMIZE_CLASS
 
 MinimizeStyle(quickmin,MinQuickMin)
 
 #else
 
 #ifndef LMP_MIN_QUICKMIN_H
 #define LMP_MIN_QUICKMIN_H
 
 #include "min.h"
 
 namespace LAMMPS_NS {
 
 class MinQuickMin : public Min {
  public:
   MinQuickMin(class LAMMPS *);
   ~MinQuickMin() {}
-  void init_style();
+  void init();
   void setup_style();
   void reset_vectors();
   int iterate(int);
 
  private:
   double dt;
 };
 
 }
 
 #endif
 #endif
diff --git a/src/pair.cpp b/src/pair.cpp
index 234235211..722feec10 100644
--- a/src/pair.cpp
+++ b/src/pair.cpp
@@ -1,1141 +1,1156 @@
 /* ----------------------------------------------------------------------
    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: Paul Crozier (SNL)
 ------------------------------------------------------------------------- */
 
 #include "mpi.h"
 #include "float.h"
 #include "limits.h"
 #include "math.h"
 #include "stdio.h"
 #include "stdlib.h"
 #include "string.h"
 #include "pair.h"
 #include "atom.h"
 #include "neighbor.h"
 #include "neigh_list.h"
 #include "domain.h"
 #include "comm.h"
 #include "force.h"
 #include "update.h"
 #include "accelerator_cuda.h"
 #include "memory.h"
 #include "error.h"
 #include "suffix.h"
 
 using namespace LAMMPS_NS;
 
 enum{GEOMETRIC,ARITHMETIC,SIXTHPOWER};
 enum{R,RSQ,BMP};
 
 /* ---------------------------------------------------------------------- */
 
 Pair::Pair(LAMMPS *lmp) : Pointers(lmp)
 {
   THIRD = 1.0/3.0;
 
   eng_vdwl = eng_coul = 0.0;
 
   comm_forward = comm_reverse = comm_reverse_off = 0;
 
   single_enable = 1;
   restartinfo = 1;
   respa_enable = 0;
   one_coeff = 0;
   no_virial_fdotr_compute = 0;
   ghostneigh = 0;
 
   nextra = 0;
   pvector = NULL;
   single_extra = 0;
   svector = NULL;
 
   // pair_modify settings
 
+  compute_flag = 1;
   offset_flag = 0;
   mix_flag = GEOMETRIC;
   tail_flag = 0;
   etail = ptail = etail_ij = ptail_ij = 0.0;
   ncoultablebits = 12;
   tabinner = sqrt(2.0);
 
   allocated = 0;
   suffix_flag = Suffix::NONE;
 
   maxeatom = maxvatom = 0;
   eatom = NULL;
   vatom = NULL;
 }
 
 /* ---------------------------------------------------------------------- */
 
 Pair::~Pair()
 {
   memory->destroy(eatom);
   memory->destroy(vatom);
 }
 
 /* ----------------------------------------------------------------------
    modify parameters of the pair style
    pair_hybrid has its own version of this routine for its sub-styles
 ------------------------------------------------------------------------- */
 
 void Pair::modify_params(int narg, char **arg)
 {
   if (narg == 0) error->all(FLERR,"Illegal pair_modify command");
 
   int iarg = 0;
   while (iarg < narg) {
     if (strcmp(arg[iarg],"mix") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal pair_modify command");
       if (strcmp(arg[iarg+1],"geometric") == 0) mix_flag = GEOMETRIC;
       else if (strcmp(arg[iarg+1],"arithmetic") == 0) mix_flag = ARITHMETIC;
       else if (strcmp(arg[iarg+1],"sixthpower") == 0) mix_flag = SIXTHPOWER;
       else error->all(FLERR,"Illegal pair_modify command");
       iarg += 2;
     } else if (strcmp(arg[iarg],"shift") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal pair_modify command");
       if (strcmp(arg[iarg+1],"yes") == 0) offset_flag = 1;
       else if (strcmp(arg[iarg+1],"no") == 0) offset_flag = 0;
       else error->all(FLERR,"Illegal pair_modify command");
       iarg += 2;
     } else if (strcmp(arg[iarg],"table") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal pair_modify command");
       ncoultablebits = atoi(arg[iarg+1]);
       if (ncoultablebits > sizeof(float)*CHAR_BIT) 
         error->all(FLERR,"Too many total bits for bitmapped lookup table");
       iarg += 2;
     } else if (strcmp(arg[iarg],"tabinner") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal pair_modify command");
       tabinner = atof(arg[iarg+1]);
       iarg += 2;
     } else if (strcmp(arg[iarg],"tail") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal pair_modify command");
       if (strcmp(arg[iarg+1],"yes") == 0) tail_flag = 1;
       else if (strcmp(arg[iarg+1],"no") == 0) tail_flag = 0;
       else error->all(FLERR,"Illegal pair_modify command");
       iarg += 2;
+    } else if (strcmp(arg[iarg],"compute") == 0) {
+      if (iarg+2 > narg) error->all(FLERR,"Illegal pair_modify command");
+      if (strcmp(arg[iarg+1],"yes") == 0) compute_flag = 1;
+      else if (strcmp(arg[iarg+1],"no") == 0) compute_flag = 0;
+      else error->all(FLERR,"Illegal pair_modify command");
+      iarg += 2;
     } else error->all(FLERR,"Illegal pair_modify command");
   }
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Pair::init()
 {
   int i,j;
 
   if (offset_flag && tail_flag)
     error->all(FLERR,"Cannot have both pair_modify shift and tail set to yes");
   if (tail_flag && domain->dimension == 2)
     error->all(FLERR,"Cannot use pair tail corrections with 2d simulations");
   if (tail_flag && domain->nonperiodic && comm->me == 0)
     error->warning(FLERR,"Using pair tail corrections with nonperiodic system");
 
   if (!allocated) error->all(FLERR,"All pair coeffs are not set");
 
   // I,I coeffs must be set
   // init_one() will check if I,J is set explicitly or inferred by mixing
 
   for (i = 1; i <= atom->ntypes; i++)
     if (setflag[i][i] == 0) error->all(FLERR,"All pair coeffs are not set");
 
   // style-specific initialization
 
   init_style();
 
   // call init_one() for each I,J
   // set cutsq for each I,J, used to neighbor
   // cutforce = max of all I,J cutoffs
 
   cutforce = 0.0;
   etail = ptail = 0.0;
   double cut;
 
   for (i = 1; i <= atom->ntypes; i++)
     for (j = i; j <= atom->ntypes; j++) {
       cut = init_one(i,j);
       cutsq[i][j] = cutsq[j][i] = cut*cut;
       cutforce = MAX(cutforce,cut);
       if (tail_flag) {
 	etail += etail_ij;
 	ptail += ptail_ij;
 	if (i != j) {
 	  etail += etail_ij;
 	  ptail += ptail_ij;
 	}
       }
     }
 }
 
 /* ----------------------------------------------------------------------
    reset all type-based params by invoking init_one() for each I,J
    called by fix adapt after it changes one or more params
 ------------------------------------------------------------------------- */
 
 void Pair::reinit()
 {
   int i,j;
   double tmp;
 
   etail = ptail = 0.0;
 
   for (i = 1; i <= atom->ntypes; i++)
     for (j = i; j <= atom->ntypes; j++) {
       tmp = init_one(i,j);
       if (tail_flag) {
 	etail += etail_ij;
 	ptail += ptail_ij;
 	if (i != j) {
 	  etail += etail_ij;
 	  ptail += ptail_ij;
 	}
       }
     }
 }
 
 /* ----------------------------------------------------------------------
    init specific to a pair style
    specific pair style can override this function
      if needs its own error checks
      if needs another kind of neighbor list
    request default neighbor list = half list
 ------------------------------------------------------------------------- */
 
 void Pair::init_style()
 {
   neighbor->request(this);
 }
 
 /* ----------------------------------------------------------------------
    neighbor callback to inform pair style of neighbor list to use
    specific pair style can override this function
 ------------------------------------------------------------------------- */
 
 void Pair::init_list(int which, NeighList *ptr)
 {
   list = ptr;
 }
 
 /* ----------------------------------------------------------------------
    mixing of pair potential prefactors (epsilon)
 ------------------------------------------------------------------------- */
 
 double Pair::mix_energy(double eps1, double eps2, double sig1, double sig2)
 {
   double value;
   if (mix_flag == GEOMETRIC)
     value = sqrt(eps1*eps2);
   else if (mix_flag == ARITHMETIC)
     value = sqrt(eps1*eps2);
   else if (mix_flag == SIXTHPOWER)
     value = 2.0 * sqrt(eps1*eps2) *
       pow(sig1,3.0) * pow(sig2,3.0) / (pow(sig1,6.0) + pow(sig2,6.0));
   return value;
 }
 
 /* ----------------------------------------------------------------------
    mixing of pair potential distances (sigma, cutoff)
 ------------------------------------------------------------------------- */
 
 double Pair::mix_distance(double sig1, double sig2)
 {
   double value;
   if (mix_flag == GEOMETRIC)
     value = sqrt(sig1*sig2);
   else if (mix_flag == ARITHMETIC)
     value = 0.5 * (sig1+sig2);
   else if (mix_flag == SIXTHPOWER)
     value = pow((0.5 * (pow(sig1,6.0) + pow(sig2,6.0))),1.0/6.0);
   return value;
 }
 
+/* ---------------------------------------------------------------------- */
+
+void Pair::compute_dummy(int eflag, int vflag)
+{
+  if (eflag || vflag) ev_setup(eflag,vflag);
+  else evflag = 0;
+}
+
 /* ----------------------------------------------------------------------
    setup for energy, virial computation
    see integrate::ev_set() for values of eflag (0-3) and vflag (0-6)
 ------------------------------------------------------------------------- */
 
 void Pair::ev_setup(int eflag, int vflag)
 {
   int i,n;
 
   evflag = 1;
 
   eflag_either = eflag;
   eflag_global = eflag % 2;
   eflag_atom = eflag / 2;
 
   vflag_either = vflag;
   vflag_global = vflag % 4;
   vflag_atom = vflag / 4;
 
   // reallocate per-atom arrays if necessary
 
   if (eflag_atom && atom->nmax > maxeatom) {
     maxeatom = atom->nmax;
     memory->destroy(eatom);
     memory->create(eatom,comm->nthreads*maxeatom,"pair:eatom");
   }
   if (vflag_atom && atom->nmax > maxvatom) {
     maxvatom = atom->nmax;
     memory->destroy(vatom);
     memory->create(vatom,comm->nthreads*maxvatom,6,"pair:vatom");
   }
 
   // zero accumulators
   // use force->newton instead of newton_pair
   //   b/c some bonds/dihedrals call pair::ev_tally with pairwise info
 
   if (eflag_global) eng_vdwl = eng_coul = 0.0;
   if (vflag_global) for (i = 0; i < 6; i++) virial[i] = 0.0;
   if (eflag_atom) {
     n = atom->nlocal;
     if (force->newton) n += atom->nghost;
     for (i = 0; i < n; i++) eatom[i] = 0.0;
   }
   if (vflag_atom) {
     n = atom->nlocal;
     if (force->newton) n += atom->nghost;
     for (i = 0; i < n; i++) {
       vatom[i][0] = 0.0;
       vatom[i][1] = 0.0;
       vatom[i][2] = 0.0;
       vatom[i][3] = 0.0;
       vatom[i][4] = 0.0;
       vatom[i][5] = 0.0;
     }
   }
 
   // if vflag_global = 2 and pair::compute() calls virial_fdotr_compute()
   // compute global virial via (F dot r) instead of via pairwise summation
   // unset other flags as appropriate
 
   if (vflag_global == 2 && no_virial_fdotr_compute == 0) {
     vflag_fdotr = 1;
     vflag_global = 0;
     if (vflag_atom == 0) vflag_either = 0;
     if (vflag_either == 0 && eflag_either == 0) evflag = 0;
   } else vflag_fdotr = 0;
 
   if (lmp->cuda) lmp->cuda->evsetup_eatom_vatom(eflag_atom,vflag_atom);
 }
 
 /* ----------------------------------------------------------------------
    tally eng_vdwl and virial into global and per-atom accumulators
    need i < nlocal test since called by bond_quartic and dihedral_charmm
 ------------------------------------------------------------------------- */
 
 void Pair::ev_tally(int i, int j, int nlocal, int newton_pair,
 		    double evdwl, double ecoul, double fpair,
 		    double delx, double dely, double delz)
 {
   double evdwlhalf,ecoulhalf,epairhalf,v[6];
 
   if (eflag_either) {
     if (eflag_global) {
       if (newton_pair) {
 	eng_vdwl += evdwl;
 	eng_coul += ecoul;
       } else {
 	evdwlhalf = 0.5*evdwl;
 	ecoulhalf = 0.5*ecoul;
 	if (i < nlocal) {
 	  eng_vdwl += evdwlhalf;
 	  eng_coul += ecoulhalf;
 	}
 	if (j < nlocal) {
 	  eng_vdwl += evdwlhalf;
 	  eng_coul += ecoulhalf;
 	}
       }
     }
     if (eflag_atom) {
       epairhalf = 0.5 * (evdwl + ecoul);
       if (newton_pair || i < nlocal) eatom[i] += epairhalf;
       if (newton_pair || j < nlocal) eatom[j] += epairhalf;
     }
   }
 
   if (vflag_either) {
     v[0] = delx*delx*fpair;
     v[1] = dely*dely*fpair;
     v[2] = delz*delz*fpair;
     v[3] = delx*dely*fpair;
     v[4] = delx*delz*fpair;
     v[5] = dely*delz*fpair;
 
     if (vflag_global) {
       if (newton_pair) {
 	virial[0] += v[0];
 	virial[1] += v[1];
 	virial[2] += v[2];
 	virial[3] += v[3];
 	virial[4] += v[4];
 	virial[5] += v[5];
       } else {
 	if (i < nlocal) {
 	  virial[0] += 0.5*v[0];
 	  virial[1] += 0.5*v[1];
 	  virial[2] += 0.5*v[2];
 	  virial[3] += 0.5*v[3];
 	  virial[4] += 0.5*v[4];
 	  virial[5] += 0.5*v[5];
 	}
 	if (j < nlocal) {
 	  virial[0] += 0.5*v[0];
 	  virial[1] += 0.5*v[1];
 	  virial[2] += 0.5*v[2];
 	  virial[3] += 0.5*v[3];
 	  virial[4] += 0.5*v[4];
 	  virial[5] += 0.5*v[5];
 	}
       }
     }
 
     if (vflag_atom) {
       if (newton_pair || i < nlocal) {
 	vatom[i][0] += 0.5*v[0];
 	vatom[i][1] += 0.5*v[1];
 	vatom[i][2] += 0.5*v[2];
 	vatom[i][3] += 0.5*v[3];
 	vatom[i][4] += 0.5*v[4];
 	vatom[i][5] += 0.5*v[5];
       }
       if (newton_pair || j < nlocal) {
 	vatom[j][0] += 0.5*v[0];
 	vatom[j][1] += 0.5*v[1];
 	vatom[j][2] += 0.5*v[2];
 	vatom[j][3] += 0.5*v[3];
 	vatom[j][4] += 0.5*v[4];
 	vatom[j][5] += 0.5*v[5];
       }
     }
   }
 }
 
 /* ---------------------------------------------------------------------- 
    tally eng_vdwl and virial into global and per-atom accumulators
    can use this version with full neighbor lists
 ------------------------------------------------------------------------- */
 
 void Pair::ev_tally_full(int i, double evdwl, double ecoul, double fpair, 
                          double delx, double dely, double delz)
 {
   double v[6];
 
   if (eflag_either) {
     if (eflag_global) {
       eng_vdwl += 0.5*evdwl;
       eng_coul += 0.5*ecoul;
     }
     if (eflag_atom) eatom[i] += 0.5 * (evdwl + ecoul);
   }
 
   if (vflag_either) {
     v[0] = 0.5*delx*delx*fpair;
     v[1] = 0.5*dely*dely*fpair;
     v[2] = 0.5*delz*delz*fpair;
     v[3] = 0.5*delx*dely*fpair;
     v[4] = 0.5*delx*delz*fpair;
     v[5] = 0.5*dely*delz*fpair;
 
     if (vflag_global) {
       virial[0] += v[0];
       virial[1] += v[1];
       virial[2] += v[2];
       virial[3] += v[3];
       virial[4] += v[4];
       virial[5] += v[5];
     }
 
     if (vflag_atom) {
       vatom[i][0] += v[0];
       vatom[i][1] += v[1];
       vatom[i][2] += v[2];
       vatom[i][3] += v[3];
       vatom[i][4] += v[4];
       vatom[i][5] += v[5];
     }
   }
 }
 
 /* ----------------------------------------------------------------------
    tally eng_vdwl and virial into global and per-atom accumulators
    for virial, have delx,dely,delz and fx,fy,fz
 ------------------------------------------------------------------------- */
 
 void Pair::ev_tally_xyz(int i, int j, int nlocal, int newton_pair,
 			double evdwl, double ecoul,
 			double fx, double fy, double fz,
 			double delx, double dely, double delz)
 {
   double evdwlhalf,ecoulhalf,epairhalf,v[6];
   
   if (eflag_either) {
     if (eflag_global) {
       if (newton_pair) {
 	eng_vdwl += evdwl;
 	eng_coul += ecoul;
       } else {
 	evdwlhalf = 0.5*evdwl;
 	ecoulhalf = 0.5*ecoul;
 	if (i < nlocal) {
 	  eng_vdwl += evdwlhalf;
 	  eng_coul += ecoulhalf;
 	}
 	if (j < nlocal) {
 	  eng_vdwl += evdwlhalf;
 	  eng_coul += ecoulhalf;
 	}
       }
     }
     if (eflag_atom) {
       epairhalf = 0.5 * (evdwl + ecoul);
       if (newton_pair || i < nlocal) eatom[i] += epairhalf;
       if (newton_pair || j < nlocal) eatom[j] += epairhalf;
     }
   }
 
   if (vflag_either) {
     v[0] = delx*fx;
     v[1] = dely*fy;
     v[2] = delz*fz;
     v[3] = delx*fy;
     v[4] = delx*fz;
     v[5] = dely*fz;
 
     if (vflag_global) {
       if (newton_pair) {
 	virial[0] += v[0];
 	virial[1] += v[1];
 	virial[2] += v[2];
 	virial[3] += v[3];
 	virial[4] += v[4];
 	virial[5] += v[5];
       } else {
 	if (i < nlocal) {
 	  virial[0] += 0.5*v[0];
 	  virial[1] += 0.5*v[1];
 	  virial[2] += 0.5*v[2];
 	  virial[3] += 0.5*v[3];
 	  virial[4] += 0.5*v[4];
 	  virial[5] += 0.5*v[5];
 	}
 	if (j < nlocal) {
 	  virial[0] += 0.5*v[0];
 	  virial[1] += 0.5*v[1];
 	  virial[2] += 0.5*v[2];
 	  virial[3] += 0.5*v[3];
 	  virial[4] += 0.5*v[4];
 	  virial[5] += 0.5*v[5];
 	}
       }
     }
 
     if (vflag_atom) {
       if (newton_pair || i < nlocal) {
 	vatom[i][0] += 0.5*v[0];
 	vatom[i][1] += 0.5*v[1];
 	vatom[i][2] += 0.5*v[2];
 	vatom[i][3] += 0.5*v[3];
 	vatom[i][4] += 0.5*v[4];
 	vatom[i][5] += 0.5*v[5];
       }
       if (newton_pair || j < nlocal) {
 	vatom[j][0] += 0.5*v[0];
 	vatom[j][1] += 0.5*v[1];
 	vatom[j][2] += 0.5*v[2];
 	vatom[j][3] += 0.5*v[3];
 	vatom[j][4] += 0.5*v[4];
 	vatom[j][5] += 0.5*v[5];
       }
     }
   }
 }
 
 /* ----------------------------------------------------------------------
    tally eng_vdwl and virial into global and per-atom accumulators
    for virial, have delx,dely,delz and fx,fy,fz
    called when using full neighbor lists
 ------------------------------------------------------------------------- */
 
 void Pair::ev_tally_xyz_full(int i, double evdwl, double ecoul,
 			     double fx, double fy, double fz,
 			     double delx, double dely, double delz)
 {
   double evdwlhalf,ecoulhalf,epairhalf,v[6];
   
   if (eflag_either) {
     if (eflag_global) {
       evdwlhalf = 0.5*evdwl;
       ecoulhalf = 0.5*ecoul;
       eng_vdwl += evdwlhalf;
       eng_coul += ecoulhalf;
     }
     if (eflag_atom) {
       epairhalf = 0.5 * (evdwl + ecoul);
       eatom[i] += epairhalf;
     }
   }
 
   if (vflag_either) {
     v[0] = 0.5*delx*fx;
     v[1] = 0.5*dely*fy;
     v[2] = 0.5*delz*fz;
     v[3] = 0.5*delx*fy;
     v[4] = 0.5*delx*fz;
     v[5] = 0.5*dely*fz;
 
     if (vflag_global) {
       virial[0] += v[0];
       virial[1] += v[1];
       virial[2] += v[2];
       virial[3] += v[3];
       virial[4] += v[4];
       virial[5] += v[5];
     }
     
     if (vflag_atom) {
       vatom[i][0] += v[0];
       vatom[i][1] += v[1];
       vatom[i][2] += v[2];
       vatom[i][3] += v[3];
       vatom[i][4] += v[4];
       vatom[i][5] += v[5];
     }
   }
 }
 
 /* ----------------------------------------------------------------------
    tally eng_vdwl and virial into global and per-atom accumulators
    called by SW and hbond potentials, newton_pair is always on
    virial = riFi + rjFj + rkFk = (rj-ri) Fj + (rk-ri) Fk = drji*fj + drki*fk
  ------------------------------------------------------------------------- */
 
 void Pair::ev_tally3(int i, int j, int k, double evdwl, double ecoul,
 		     double *fj, double *fk, double *drji, double *drki)
 {
   double epairthird,v[6];
 
   if (eflag_either) {
     if (eflag_global) {
       eng_vdwl += evdwl;
       eng_coul += ecoul;
     }
     if (eflag_atom) {
       epairthird = THIRD * (evdwl + ecoul);
       eatom[i] += epairthird;
       eatom[j] += epairthird;
       eatom[k] += epairthird;
     }
   }
 
   if (vflag_either) {
     v[0] = drji[0]*fj[0] + drki[0]*fk[0];
     v[1] = drji[1]*fj[1] + drki[1]*fk[1];
     v[2] = drji[2]*fj[2] + drki[2]*fk[2];
     v[3] = drji[0]*fj[1] + drki[0]*fk[1];
     v[4] = drji[0]*fj[2] + drki[0]*fk[2];
     v[5] = drji[1]*fj[2] + drki[1]*fk[2];
       
     if (vflag_global) {
       virial[0] += v[0];
       virial[1] += v[1];
       virial[2] += v[2];
       virial[3] += v[3];
       virial[4] += v[4];
       virial[5] += v[5];
     }
 
     if (vflag_atom) {
       vatom[i][0] += THIRD*v[0]; vatom[i][1] += THIRD*v[1];
       vatom[i][2] += THIRD*v[2]; vatom[i][3] += THIRD*v[3]; 
       vatom[i][4] += THIRD*v[4]; vatom[i][5] += THIRD*v[5];
 
       vatom[j][0] += THIRD*v[0]; vatom[j][1] += THIRD*v[1];
       vatom[j][2] += THIRD*v[2]; vatom[j][3] += THIRD*v[3];
       vatom[j][4] += THIRD*v[4]; vatom[j][5] += THIRD*v[5];
 
       vatom[k][0] += THIRD*v[0]; vatom[k][1] += THIRD*v[1];
       vatom[k][2] += THIRD*v[2]; vatom[k][3] += THIRD*v[3];
       vatom[k][4] += THIRD*v[4]; vatom[k][5] += THIRD*v[5];
     }
   }
 }
 
 /* ----------------------------------------------------------------------
    tally eng_vdwl and virial into global and per-atom accumulators
    called by AIREBO potential, newton_pair is always on
  ------------------------------------------------------------------------- */
 
 void Pair::ev_tally4(int i, int j, int k, int m, double evdwl,
 		     double *fi, double *fj, double *fk,
 		     double *drim, double *drjm, double *drkm)
 {
   double epairfourth,v[6];
 
   if (eflag_either) {
     if (eflag_global) eng_vdwl += evdwl;
     if (eflag_atom) {
       epairfourth = 0.25 * evdwl;
       eatom[i] += epairfourth;
       eatom[j] += epairfourth;
       eatom[k] += epairfourth;
       eatom[m] += epairfourth;
     }
   }
 
   if (vflag_atom) {
     v[0] = 0.25 * (drim[0]*fi[0] + drjm[0]*fj[0] + drkm[0]*fk[0]);
     v[1] = 0.25 * (drim[1]*fi[1] + drjm[1]*fj[1] + drkm[1]*fk[1]);
     v[2] = 0.25 * (drim[2]*fi[2] + drjm[2]*fj[2] + drkm[2]*fk[2]);
     v[3] = 0.25 * (drim[0]*fi[1] + drjm[0]*fj[1] + drkm[0]*fk[1]);
     v[4] = 0.25 * (drim[0]*fi[2] + drjm[0]*fj[2] + drkm[0]*fk[2]);
     v[5] = 0.25 * (drim[1]*fi[2] + drjm[1]*fj[2] + drkm[1]*fk[2]);
     
     vatom[i][0] += v[0]; vatom[i][1] += v[1]; vatom[i][2] += v[2];
     vatom[i][3] += v[3]; vatom[i][4] += v[4]; vatom[i][5] += v[5];
     vatom[j][0] += v[0]; vatom[j][1] += v[1]; vatom[j][2] += v[2];
     vatom[j][3] += v[3]; vatom[j][4] += v[4]; vatom[j][5] += v[5];
     vatom[k][0] += v[0]; vatom[k][1] += v[1]; vatom[k][2] += v[2];
     vatom[k][3] += v[3]; vatom[k][4] += v[4]; vatom[k][5] += v[5];
     vatom[m][0] += v[0]; vatom[m][1] += v[1]; vatom[m][2] += v[2];
     vatom[m][3] += v[3]; vatom[m][4] += v[4]; vatom[m][5] += v[5];
   }
 }
 
 /* ----------------------------------------------------------------------
    tally ecoul and virial into each of n atoms in list
    called by TIP4P potential, newton_pair is always on
    changes v values by dividing by n
  ------------------------------------------------------------------------- */
 
 void Pair::ev_tally_list(int n, int *list, double ecoul, double *v)
 {
   int i,j;
 
   if (eflag_either) {
     if (eflag_global) eng_coul += ecoul;
     if (eflag_atom) {
       double epairatom = ecoul/n;
       for (i = 0; i < n; i++) eatom[list[i]] += epairatom;
     }
   }
 
   if (vflag_either) {
     if (vflag_global) {
       virial[0] += v[0];
       virial[1] += v[1];
       virial[2] += v[2];
       virial[3] += v[3];
       virial[4] += v[4];
       virial[5] += v[5];
     }
 
     if (vflag_atom) {
       v[0] /= n;
       v[1] /= n;
       v[2] /= n;
       v[3] /= n;
       v[4] /= n;
       v[5] /= n;
       for (i = 0; i < n; i++) {
 	j = list[i];
 	vatom[j][0] += v[0];
 	vatom[j][1] += v[1];
 	vatom[j][2] += v[2];
 	vatom[j][3] += v[3];
 	vatom[j][4] += v[4];
 	vatom[j][5] += v[5];
       }
     }
   }
 }
 
 /* ----------------------------------------------------------------------
    tally virial into per-atom accumulators
    called by AIREBO potential, newton_pair is always on
    fpair is magnitude of force on atom I
 ------------------------------------------------------------------------- */
 
 void Pair::v_tally2(int i, int j, double fpair, double *drij)
 {
   double v[6];
   
   v[0] = 0.5 * drij[0]*drij[0]*fpair;
   v[1] = 0.5 * drij[1]*drij[1]*fpair;
   v[2] = 0.5 * drij[2]*drij[2]*fpair;
   v[3] = 0.5 * drij[0]*drij[1]*fpair;
   v[4] = 0.5 * drij[0]*drij[2]*fpair;
   v[5] = 0.5 * drij[1]*drij[2]*fpair;
 
   vatom[i][0] += v[0]; vatom[i][1] += v[1]; vatom[i][2] += v[2];
   vatom[i][3] += v[3]; vatom[i][4] += v[4]; vatom[i][5] += v[5];
   vatom[j][0] += v[0]; vatom[j][1] += v[1]; vatom[j][2] += v[2];
   vatom[j][3] += v[3]; vatom[j][4] += v[4]; vatom[j][5] += v[5];
 }
 
 /* ----------------------------------------------------------------------
    tally virial into per-atom accumulators
    called by AIREBO and Tersoff potential, newton_pair is always on
 ------------------------------------------------------------------------- */
 
 void Pair::v_tally3(int i, int j, int k,
 		    double *fi, double *fj, double *drik, double *drjk)
 {
   double v[6];
   
   v[0] = THIRD * (drik[0]*fi[0] + drjk[0]*fj[0]);
   v[1] = THIRD * (drik[1]*fi[1] + drjk[1]*fj[1]);
   v[2] = THIRD * (drik[2]*fi[2] + drjk[2]*fj[2]);
   v[3] = THIRD * (drik[0]*fi[1] + drjk[0]*fj[1]);
   v[4] = THIRD * (drik[0]*fi[2] + drjk[0]*fj[2]);
   v[5] = THIRD * (drik[1]*fi[2] + drjk[1]*fj[2]);
 
   vatom[i][0] += v[0]; vatom[i][1] += v[1]; vatom[i][2] += v[2];
   vatom[i][3] += v[3]; vatom[i][4] += v[4]; vatom[i][5] += v[5];
   vatom[j][0] += v[0]; vatom[j][1] += v[1]; vatom[j][2] += v[2];
   vatom[j][3] += v[3]; vatom[j][4] += v[4]; vatom[j][5] += v[5];
   vatom[k][0] += v[0]; vatom[k][1] += v[1]; vatom[k][2] += v[2];
   vatom[k][3] += v[3]; vatom[k][4] += v[4]; vatom[k][5] += v[5];
 }
 
 /* ----------------------------------------------------------------------
    tally virial into per-atom accumulators
    called by AIREBO potential, newton_pair is always on
 ------------------------------------------------------------------------- */
 
 void Pair::v_tally4(int i, int j, int k, int m,
 		    double *fi, double *fj, double *fk,
 		    double *drim, double *drjm, double *drkm)
 {
   double v[6];
 
   v[0] = 0.25 * (drim[0]*fi[0] + drjm[0]*fj[0] + drkm[0]*fk[0]);
   v[1] = 0.25 * (drim[1]*fi[1] + drjm[1]*fj[1] + drkm[1]*fk[1]);
   v[2] = 0.25 * (drim[2]*fi[2] + drjm[2]*fj[2] + drkm[2]*fk[2]);
   v[3] = 0.25 * (drim[0]*fi[1] + drjm[0]*fj[1] + drkm[0]*fk[1]);
   v[4] = 0.25 * (drim[0]*fi[2] + drjm[0]*fj[2] + drkm[0]*fk[2]);
   v[5] = 0.25 * (drim[1]*fi[2] + drjm[1]*fj[2] + drkm[1]*fk[2]);
 
   vatom[i][0] += v[0]; vatom[i][1] += v[1]; vatom[i][2] += v[2];
   vatom[i][3] += v[3]; vatom[i][4] += v[4]; vatom[i][5] += v[5];
   vatom[j][0] += v[0]; vatom[j][1] += v[1]; vatom[j][2] += v[2];
   vatom[j][3] += v[3]; vatom[j][4] += v[4]; vatom[j][5] += v[5];
   vatom[k][0] += v[0]; vatom[k][1] += v[1]; vatom[k][2] += v[2];
   vatom[k][3] += v[3]; vatom[k][4] += v[4]; vatom[k][5] += v[5];
   vatom[m][0] += v[0]; vatom[m][1] += v[1]; vatom[m][2] += v[2];
   vatom[m][3] += v[3]; vatom[m][4] += v[4]; vatom[m][5] += v[5];
 }
 
 /* ----------------------------------------------------------------------
    tally virial into global and per-atom accumulators
    called by pair lubricate potential with 6 tensor components
 ------------------------------------------------------------------------- */
 
 void Pair::v_tally_tensor(int i, int j, int nlocal, int newton_pair,
 			  double vxx, double vyy, double vzz,
 			  double vxy, double vxz, double vyz)
 {
   double v[6];
 
   v[0] = vxx;
   v[1] = vyy;
   v[2] = vzz;
   v[3] = vxy;
   v[4] = vxz;
   v[5] = vyz;
   
   if (vflag_global) {
     if (newton_pair) {
       virial[0] += v[0];
       virial[1] += v[1];
       virial[2] += v[2];
       virial[3] += v[3];
       virial[4] += v[4];
       virial[5] += v[5];
     } else {
       if (i < nlocal) {
 	virial[0] += 0.5*v[0];
 	virial[1] += 0.5*v[1];
 	virial[2] += 0.5*v[2];
 	virial[3] += 0.5*v[3];
 	virial[4] += 0.5*v[4];
 	virial[5] += 0.5*v[5];
       }
       if (j < nlocal) {
 	virial[0] += 0.5*v[0];
 	virial[1] += 0.5*v[1];
 	virial[2] += 0.5*v[2];
 	virial[3] += 0.5*v[3];
 	virial[4] += 0.5*v[4];
 	virial[5] += 0.5*v[5];
       }
     }
   }
 
   if (vflag_atom) {
     if (newton_pair || i < nlocal) {
       vatom[i][0] += 0.5*v[0];
       vatom[i][1] += 0.5*v[1];
       vatom[i][2] += 0.5*v[2];
       vatom[i][3] += 0.5*v[3];
       vatom[i][4] += 0.5*v[4];
       vatom[i][5] += 0.5*v[5];
     }
     if (newton_pair || j < nlocal) {
       vatom[j][0] += 0.5*v[0];
       vatom[j][1] += 0.5*v[1];
       vatom[j][2] += 0.5*v[2];
       vatom[j][3] += 0.5*v[3];
       vatom[j][4] += 0.5*v[4];
       vatom[j][5] += 0.5*v[5];
     }
   }
 }
 
 /* ----------------------------------------------------------------------
    compute global pair virial via summing F dot r over own & ghost atoms
    at this point, only pairwise forces have been accumulated in atom->f
 ------------------------------------------------------------------------- */
 
 void Pair::virial_fdotr_compute()
 {
   double **x = atom->x;
   double **f = atom->f;
 
   // sum over force on all particles including ghosts
 
   if (neighbor->includegroup == 0) {
     int nall = atom->nlocal + atom->nghost;
     for (int i = 0; i < nall; i++) {
       virial[0] += f[i][0]*x[i][0];
       virial[1] += f[i][1]*x[i][1];
       virial[2] += f[i][2]*x[i][2];
       virial[3] += f[i][1]*x[i][0];
       virial[4] += f[i][2]*x[i][0];
       virial[5] += f[i][2]*x[i][1];
     }
 
   // neighbor includegroup flag is set
   // sum over force on initial nfirst particles and ghosts
 
   } else {
     int nall = atom->nfirst;
     for (int i = 0; i < nall; i++) {
       virial[0] += f[i][0]*x[i][0];
       virial[1] += f[i][1]*x[i][1];
       virial[2] += f[i][2]*x[i][2];
       virial[3] += f[i][1]*x[i][0];
       virial[4] += f[i][2]*x[i][0];
       virial[5] += f[i][2]*x[i][1];
     }
 
     nall = atom->nlocal + atom->nghost;
     for (int i = atom->nlocal; i < nall; i++) {
       virial[0] += f[i][0]*x[i][0];
       virial[1] += f[i][1]*x[i][1];
       virial[2] += f[i][2]*x[i][2];
       virial[3] += f[i][1]*x[i][0];
       virial[4] += f[i][2]*x[i][0];
       virial[5] += f[i][2]*x[i][1];
     }
   }
 }
 
 /* ----------------------------------------------------------------------
    write a table of pair potential energy/force vs distance to a file
 ------------------------------------------------------------------------- */
 
 void Pair::write_file(int narg, char **arg)
 {
   if (narg < 8) error->all(FLERR,"Illegal pair_write command");
   if (single_enable == 0) 
     error->all(FLERR,"Pair style does not support pair_write");
 
   // parse arguments
 
   int itype = atoi(arg[0]);
   int jtype = atoi(arg[1]);
   if (itype < 1 || itype > atom->ntypes || jtype < 1 || jtype > atom->ntypes)
     error->all(FLERR,"Invalid atom types in pair_write command");
 
   int n = atoi(arg[2]);
 
   int style;
   if (strcmp(arg[3],"r") == 0) style = R;
   else if (strcmp(arg[3],"rsq") == 0) style = RSQ;
   else if (strcmp(arg[3],"bitmap") == 0) style = BMP;
   else error->all(FLERR,"Invalid style in pair_write command");
 
   double inner = atof(arg[4]);
   double outer = atof(arg[5]);
   if (inner <= 0.0 || inner >= outer)
     error->all(FLERR,"Invalid cutoffs in pair_write command");
 
   // open file in append mode
   // print header in format used by pair_style table
 
   int me;
   MPI_Comm_rank(world,&me);
   FILE *fp;
   if (me == 0) {
     fp = fopen(arg[6],"a");
     if (fp == NULL) error->one(FLERR,"Cannot open pair_write file");
     fprintf(fp,"# Pair potential %s for atom types %d %d: i,r,energy,force\n",
 	    force->pair_style,itype,jtype);
     if (style == R) 
       fprintf(fp,"\n%s\nN %d R %g %g\n\n",arg[7],n,inner,outer);
     if (style == RSQ) 
       fprintf(fp,"\n%s\nN %d RSQ %g %g\n\n",arg[7],n,inner,outer);
   }
 
   // initialize potentials before evaluating pair potential
   // insures all pair coeffs are set and force constants
 
   force->init();
 
   // if pair style = any of EAM, swap in dummy fp vector
 
   double eamfp[2];
   eamfp[0] = eamfp[1] = 0.0;
   double *eamfp_hold;
 
   Pair *epair = force->pair_match("eam",0);
   if (epair) epair->swap_eam(eamfp,&eamfp_hold);
 
   // if atom style defines charge, swap in dummy q vec
 
   double q[2];
   q[0] = q[1] = 1.0;
   if (narg == 10) {
     q[0] = atof(arg[8]);
     q[1] = atof(arg[9]);
   }
   double *q_hold;
 
   if (atom->q) {
     q_hold = atom->q;
     atom->q = q;
   }
 
   // evaluate energy and force at each of N distances
 
   int masklo,maskhi,nmask,nshiftbits;
   if (style == BMP) {
     init_bitmap(inner,outer,n,masklo,maskhi,nmask,nshiftbits);
     int ntable = 1 << n;
     if (me == 0)
       fprintf(fp,"\n%s\nN %d BITMAP %g %g\n\n",arg[7],ntable,inner,outer);
     n = ntable;
   }
 
   double r,e,f,rsq;  
   union_int_float_t rsq_lookup;
 
   for (int i = 0; i < n; i++) {
     if (style == R) {
       r = inner + (outer-inner) * i/(n-1);
       rsq = r*r;
     } else if (style == RSQ) {
       rsq = inner*inner + (outer*outer - inner*inner) * i/(n-1);
       r = sqrt(rsq);
     } else if (style == BMP) {
       rsq_lookup.i = i << nshiftbits;
       rsq_lookup.i |= masklo;
       if (rsq_lookup.f < inner*inner) {
         rsq_lookup.i = i << nshiftbits;
         rsq_lookup.i |= maskhi;
       }
       rsq = rsq_lookup.f;
       r = sqrt(rsq);
     }
 
     if (rsq < cutsq[itype][jtype]) {
       e = single(0,1,itype,jtype,rsq,1.0,1.0,f);
       f *= r;
     } else e = f = 0.0;
     if (me == 0) fprintf(fp,"%d %g %g %g\n",i+1,r,e,f);
   }
 
   // restore original vecs that were swapped in for
 
   double *tmp;
   if (epair) epair->swap_eam(eamfp_hold,&tmp);
   if (atom->q) atom->q = q_hold;
   
   if (me == 0) fclose(fp);
 }
 
 /* ----------------------------------------------------------------------
    define bitmap parameters based on inner and outer cutoffs
 ------------------------------------------------------------------------- */
 
 void Pair::init_bitmap(double inner, double outer, int ntablebits, 
              int &masklo, int &maskhi, int &nmask, int &nshiftbits)
 {
   if (sizeof(int) != sizeof(float))
     error->all(FLERR,"Bitmapped lookup tables require int/float be same size");
   
   if (ntablebits > sizeof(float)*CHAR_BIT) 
     error->all(FLERR,"Too many total bits for bitmapped lookup table");
           
   if (inner >= outer) error->warning(FLERR,"Table inner cutoff >= outer cutoff");
     
   int nlowermin = 1;
   while (!((pow(double(2),nlowermin) <= inner*inner) && 
            (pow(double(2),nlowermin+1) > inner*inner))) {
     if (pow(double(2),nlowermin) <= inner*inner) nlowermin++;
     else nlowermin--;
   }
 
   int nexpbits = 0;
   double required_range = outer*outer / pow(double(2),nlowermin);
   double available_range = 2.0;
   
   while (available_range < required_range) {
     nexpbits++;
     available_range = pow(double(2),pow(double(2),nexpbits));
   }
      
   int nmantbits = ntablebits - nexpbits;
 
   if (nexpbits > sizeof(float)*CHAR_BIT - FLT_MANT_DIG) 
     error->all(FLERR,"Too many exponent bits for lookup table");
   if (nmantbits+1 > FLT_MANT_DIG)
     error->all(FLERR,"Too many mantissa bits for lookup table");
   if (nmantbits < 3) error->all(FLERR,"Too few bits for lookup table");
 
   nshiftbits = FLT_MANT_DIG - (nmantbits+1);
 
   nmask = 1;
   for (int j = 0; j < ntablebits+nshiftbits; j++) nmask *= 2;
   nmask -= 1;
 
   union_int_float_t rsq_lookup;
   rsq_lookup.f = outer*outer;
   maskhi = rsq_lookup.i & ~(nmask);
   rsq_lookup.f = inner*inner;
   masklo = rsq_lookup.i & ~(nmask);
 }
 
 /* ---------------------------------------------------------------------- */
 
 double Pair::memory_usage()
 {
   double bytes = comm->nthreads*maxeatom * sizeof(double);
   bytes += comm->nthreads*maxvatom*6 * sizeof(double);
   return bytes;
 }
diff --git a/src/pair.h b/src/pair.h
index 53fa3e9c4..d86b7005d 100644
--- a/src/pair.h
+++ b/src/pair.h
@@ -1,255 +1,258 @@
 /* -*- c++ -*- ----------------------------------------------------------
    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_PAIR_H
 #define LMP_PAIR_H
 
 #include "pointers.h"
 
 namespace LAMMPS_NS {
 
 class Pair : protected Pointers {
   friend class AngleSDK;
   friend class AngleSDKOMP;
   friend class BondQuartic;
   friend class BondQuarticOMP;
   friend class DihedralCharmm;
   friend class DihedralCharmmOMP;
   friend class FixGPU;
   friend class FixOMP;
   friend class ThrOMP;
 
  public:
   double eng_vdwl,eng_coul;      // accumulated energies
   double virial[6];              // accumulated virial
   double *eatom,**vatom;         // accumulated per-atom energy/virial
 
   double cutforce;               // max cutoff for all atom pairs
   double **cutsq;                // cutoff sq for each atom pair
   int **setflag;                 // 0/1 = whether each i,j has been set
 
   int comm_forward;              // size of forward communication (0 if none)
   int comm_reverse;              // size of reverse communication (0 if none)
   int comm_reverse_off;          // size of reverse comm even if newton off
 
   int single_enable;             // 1 if single() routine exists
   int restartinfo;               // 1 if pair style writes restart info
   int respa_enable;              // 1 if inner/middle/outer rRESPA routines
   int one_coeff;                 // 1 if allows only one coeff * * call
   int no_virial_fdotr_compute;   // 1 if does not invoke virial_fdotr_compute()
   int ghostneigh;                // 1 if pair style needs neighbors of ghosts
   double **cutghost;             // cutoff for each ghost pair
 
   int tail_flag;                 // pair_modify flag for LJ tail correction
   double etail,ptail;            // energy/pressure tail corrections
   double etail_ij,ptail_ij;
 
   int evflag;                    // energy,virial settings
   int eflag_either,eflag_global,eflag_atom;
   int vflag_either,vflag_global,vflag_atom;
 
   int nextra;                    // # of extra quantities pair style calculates
   double *pvector;               // vector of extra pair quantities
 
   int single_extra;              // number of extra single values calculated
   double *svector;               // vector of extra single quantities
   
   class NeighList *list;         // standard neighbor list used by most pairs
   class NeighList *listhalf;     // half list used by some pairs
   class NeighList *listfull;     // full list used by some pairs
   class NeighList *listgranhistory;  // granular history list used by some pairs
   class NeighList *listinner;    // rRESPA lists used by some pairs
   class NeighList *listmiddle;
   class NeighList *listouter;
 
+  int compute_flag;              // 0 if skip compute()
+
   Pair(class LAMMPS *);
   virtual ~Pair();
 
   // top-level Pair methods
 
   void init();
   void reinit();
   double mix_energy(double, double, double, double);
   double mix_distance(double, double);
   void write_file(int, char **);
   void init_bitmap(double, double, int, int &, int &, int &, int &);
   virtual void modify_params(int, char **);
+  void compute_dummy(int, int);
 
   // need to be public, so can be called by pair_style reaxc
 
   void ev_tally(int, int, int, int, double, double, double,
 		double, double, double);
   void ev_tally3(int, int, int, double, double,
 		 double *, double *, double *, double *);
   void v_tally3(int, int, int, double *, double *, double *, double *);
   void v_tally4(int, int, int, int, double *, double *, double *,
 		double *, double *, double *);
   void ev_tally_xyz(int, int, int, int, double, double,
 		    double, double, double, double, double, double);
 
   // general child-class methods
 
   virtual void compute(int, int) = 0;
   virtual void compute_inner() {}
   virtual void compute_middle() {}
   virtual void compute_outer(int, int) {}
 
   virtual double single(int, int, int, int,
 			double, double, double, double &) {return 0.0;}
 
   virtual void settings(int, char **) = 0;
   virtual void coeff(int, char **) = 0;
 
   virtual void init_style();
   virtual void init_list(int, class NeighList *);
   virtual double init_one(int, int) {return 0.0;}
 
   virtual void write_restart(FILE *) {}
   virtual void read_restart(FILE *) {}
   virtual void write_restart_settings(FILE *) {}
   virtual void read_restart_settings(FILE *) {}
 
   virtual int pack_comm(int, int *, double *, int, int *) {return 0;}
   virtual void unpack_comm(int, int, double *) {}
   virtual int pack_reverse_comm(int, int, double *) {return 0;}
   virtual void unpack_reverse_comm(int, int *, double *) {}
   virtual double memory_usage();
 
   // specific child-class methods for certain Pair styles
   
   virtual void *extract(const char *, int &) {return NULL;}
   virtual void swap_eam(double *, double **) {}
   virtual void reset_dt() {}
   virtual void min_xf_pointers(int, double **, double **) {}
   virtual void min_xf_get(int) {}
   virtual void min_x_set(int) {}
 
  protected:
   int allocated;               // 0/1 = whether arrays are allocated
   int suffix_flag;             // suffix compatibility flag
 
                                        // pair_modify settings
   int offset_flag,mix_flag;            // flags for offset and mixing
   int ncoultablebits;                  // size of Coulomb table
   double tabinner;                     // inner cutoff for Coulomb table
 
   // custom data type for accessing Coulomb tables
 
   typedef union {int i; float f;} union_int_float_t;
 
   double THIRD;
 
   int vflag_fdotr;
   int maxeatom,maxvatom;
 
   virtual void ev_setup(int, int);
   void ev_tally_full(int, double, double, double, double, double, double);
   void ev_tally_xyz_full(int, double, double,
 			 double, double, double, double, double, double);
   void ev_tally4(int, int, int, int, double,
 		 double *, double *, double *, double *, double *, double *);
   void ev_tally_list(int, int *, double, double *);
   void v_tally2(int, int, double, double *);
   void v_tally_tensor(int, int, int, int,
 		      double, double, double, double, double, double);
   void virial_fdotr_compute();
 
   inline int sbmask(int j) {
     return j >> SBBITS & 3;
   }
 };
 
 }
 
 #endif
 
 /* ERROR/WARNING messages:
 
 E: Illegal ... command
 
 Self-explanatory.  Check the input script syntax and compare to the
 documentation for the command.  You can use -echo screen as a
 command-line option when running LAMMPS to see the offending line.
 
 E: Too many total bits for bitmapped lookup table
 
 Table size specified via pair_modify command is too large.  Note that
 a value of N generates a 2^N size table.
 
 E: Cannot have both pair_modify shift and tail set to yes
 
 These 2 options are contradictory.
 
 E: Cannot use pair tail corrections with 2d simulations
 
 The correction factors are only currently defined for 3d systems.
 
 W: Using pair tail corrections with nonperiodic system
 
 This is probably a bogus thing to do, since tail corrections are
 computed by integrating the density of a periodic system out to
 infinity.
 
 E: All pair coeffs are not set
 
 All pair coefficients must be set in the data file or by the
 pair_coeff command before running a simulation.
 
 E: Pair style does not support pair_write
 
 The pair style does not have a single() function, so it can
 not be invoked by pair write.
 
 E: Invalid atom types in pair_write command
 
 Atom types must range from 1 to Ntypes inclusive.
 
 E: Invalid style in pair_write command
 
 Self-explanatory.  Check the input script.
 
 E: Invalid cutoffs in pair_write command
 
 Inner cutoff must be larger than 0.0 and less than outer cutoff.
 
 E: Cannot open pair_write file
 
 The specified output file for pair energies and forces cannot be
 opened.  Check that the path and name are correct.
 
 E: Bitmapped lookup tables require int/float be same size
 
 Cannot use pair tables on this machine, because of word sizes.  Use
 the pair_modify command with table 0 instead.
 
 W: Table inner cutoff >= outer cutoff
 
 You specified an inner cutoff for a Coulombic table that is longer
 than the global cutoff.  Probably not what you wanted.
 
 E: Too many exponent bits for lookup table
 
 Table size specified via pair_modify command does not work with your
 machine's floating point representation.
 
 E: Too many mantissa bits for lookup table
 
 Table size specified via pair_modify command does not work with your
 machine's floating point representation.
 
 E: Too few bits for lookup table
 
 Table size specified via pair_modify command does not work with your
 machine's floating point representation.
 
 */
diff --git a/src/respa.cpp b/src/respa.cpp
index 97ad3291d..013b25db6 100644
--- a/src/respa.cpp
+++ b/src/respa.cpp
@@ -1,699 +1,701 @@
 /* ----------------------------------------------------------------------
    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 authors: Mark Stevens (SNL), Paul Crozier (SNL)
 ------------------------------------------------------------------------- */
 
 #include "stdlib.h"
 #include "string.h"
 #include "respa.h"
 #include "neighbor.h"
 #include "atom.h"
 #include "domain.h"
 #include "comm.h"
 #include "atom.h"
 #include "force.h"
 #include "pair.h"
 #include "bond.h"
 #include "angle.h"
 #include "dihedral.h"
 #include "improper.h"
 #include "kspace.h"
 #include "output.h"
 #include "update.h"
 #include "modify.h"
 #include "compute.h"
 #include "fix_respa.h"
 #include "timer.h"
 #include "memory.h"
 #include "error.h"
 
 using namespace LAMMPS_NS;
 
 /* ---------------------------------------------------------------------- */
 
 Respa::Respa(LAMMPS *lmp, int narg, char **arg) : Integrate(lmp, narg, arg)
 {
   if (narg < 1) error->all(FLERR,"Illegal run_style respa command");
 
   nlevels = atoi(arg[0]);
   if (nlevels < 1) error->all(FLERR,"Respa levels must be >= 1");
 
   if (narg < nlevels) error->all(FLERR,"Illegal run_style respa command");
   loop = new int[nlevels];
   for (int iarg = 1; iarg < nlevels; iarg++) {
     loop[iarg-1] = atoi(arg[iarg]);
     if (loop[iarg-1] <= 0) error->all(FLERR,"Illegal run_style respa command");
   }
   loop[nlevels-1] = 1;
 
   // set level at which each force is computed
   // argument settings override defaults
 
   level_bond = level_angle = level_dihedral = level_improper = -1;
   level_pair = level_kspace = -1;
   level_inner = level_middle = level_outer = -1;
 
   int iarg = nlevels;
   while (iarg < narg) {
     if (strcmp(arg[iarg],"bond") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal run_style respa command");
       level_bond = atoi(arg[iarg+1]) - 1;
       iarg += 2;
     } else if (strcmp(arg[iarg],"angle") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal run_style respa command");
       level_angle = atoi(arg[iarg+1]) - 1;
       iarg += 2;
     } else if (strcmp(arg[iarg],"dihedral") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal run_style respa command");
       level_dihedral = atoi(arg[iarg+1]) - 1;
       iarg += 2;
     } else if (strcmp(arg[iarg],"improper") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal run_style respa command");
       level_improper = atoi(arg[iarg+1]) - 1;
       iarg += 2;
     } else if (strcmp(arg[iarg],"pair") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal run_style respa command");
       level_pair = atoi(arg[iarg+1]) - 1;
       iarg += 2;
     } else if (strcmp(arg[iarg],"inner") == 0) {
       if (iarg+4 > narg) error->all(FLERR,"Illegal run_style respa command");
       level_inner = atoi(arg[iarg+1]) - 1;
       cutoff[0] = atof(arg[iarg+2]);
       cutoff[1] = atof(arg[iarg+3]);
       iarg += 4;
     } else if (strcmp(arg[iarg],"middle") == 0) {
       if (iarg+4 > narg) error->all(FLERR,"Illegal run_style respa command");
       level_middle = atoi(arg[iarg+1]) - 1;
       cutoff[2] = atof(arg[iarg+2]);
       cutoff[3] = atof(arg[iarg+3]);
       iarg += 4;
     } else if (strcmp(arg[iarg],"outer") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal run_style respa command");
       level_outer = atoi(arg[iarg+1]) - 1;
       iarg += 2;
     } else if (strcmp(arg[iarg],"kspace") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal run_style respa command");
       level_kspace = atoi(arg[iarg+1]) - 1;
       iarg += 2;
     } else error->all(FLERR,"Illegal run_style respa command");
   }
 
   // cannot specify both pair and inner/middle/outer
 
   if (level_pair >= 0 && 
       (level_inner >= 0 || level_middle >= 0 || level_outer >= 0))
     error->all(FLERR,"Cannot set both respa pair and inner/middle/outer");
 
   // if either inner and outer is specified, then both must be
 
   if ((level_inner >= 0 && level_outer == -1) || 
       (level_outer >= 0 && level_inner == -1))
     error->all(FLERR,"Must set both respa inner and outer");
 
   // middle cannot be set without inner/outer
 
   if (level_middle >= 0 && level_inner == -1)
     error->all(FLERR,"Cannot set respa middle without inner/outer");
 
   // set defaults if user did not specify level
   // bond to innermost level
   // angle same as bond, dihedral same as angle, improper same as dihedral
   // pair to outermost level if no inner/middle/outer
   // inner/middle/outer have no defaults
   // kspace same as pair or outer
 
   if (level_bond == -1) level_bond = 0;
   if (level_angle == -1) level_angle = level_bond;
   if (level_dihedral == -1) level_dihedral = level_angle;
   if (level_improper == -1) level_improper = level_dihedral;
   if (level_pair == -1 && level_inner == -1) level_pair = nlevels-1;
   if (level_kspace == -1 && level_pair >= 0) level_kspace = level_pair;
   if (level_kspace == -1 && level_pair == -1) level_kspace = level_outer;
 
   // print respa levels
 
   if (comm->me == 0) {
     if (screen) {
       fprintf(screen,"Respa levels:\n");
       for (int i = 0; i < nlevels; i++) {
 	fprintf(screen,"  %d =",i);
 	if (level_bond == i) fprintf(screen," bond");
 	if (level_angle == i) fprintf(screen," angle");
 	if (level_dihedral == i) fprintf(screen," dihedral");
 	if (level_improper == i) fprintf(screen," improper");
 	if (level_pair == i) fprintf(screen," pair");
 	if (level_inner == i) fprintf(screen," pair-inner");
 	if (level_middle == i) fprintf(screen," pair-middle");
 	if (level_outer == i) fprintf(screen," pair-outer");
 	if (level_kspace == i) fprintf(screen," kspace");
 	fprintf(screen,"\n");
       }
     }
     if (logfile) {
       fprintf(logfile,"Respa levels:\n");
       for (int i = 0; i < nlevels; i++) {
 	fprintf(logfile,"  %d =",i);
 	if (level_bond == i) fprintf(logfile," bond");
 	if (level_angle == i) fprintf(logfile," angle");
 	if (level_dihedral == i) fprintf(logfile," dihedral");
 	if (level_improper == i) fprintf(logfile," improper");
 	if (level_pair == i) fprintf(logfile," pair");
 	if (level_inner == i) fprintf(logfile," pair-inner");
 	if (level_middle == i) fprintf(logfile," pair-middle");
 	if (level_outer == i) fprintf(logfile," pair-outer");
 	if (level_kspace == i) fprintf(logfile," kspace");
 	fprintf(logfile,"\n");
       }
     }
   }
 
   // check that levels are in correct order
   
   if (level_angle < level_bond || level_dihedral < level_angle ||
       level_improper < level_dihedral)
     error->all(FLERR,"Invalid order of forces within respa levels");
   if (level_pair >= 0) {
     if (level_pair < level_improper || level_kspace < level_pair)
       error->all(FLERR,"Invalid order of forces within respa levels");
   }
   if (level_pair == -1 && level_middle == -1) {
     if (level_inner < level_improper || level_outer < level_inner ||
 	level_kspace != level_outer)
       error->all(FLERR,"Invalid order of forces within respa levels");
   }
   if (level_pair == -1 && level_middle >= 0) {
     if (level_inner < level_improper || level_middle < level_inner ||
 	level_outer < level_inner || level_kspace != level_outer)
       error->all(FLERR,"Invalid order of forces within respa levels");
   }
 
   // warn if any levels are devoid of forces
 
   int flag = 0;
   for (int i = 0; i < nlevels; i++)
     if (level_bond != i && level_angle != i && level_dihedral != i &&
 	level_improper != i && level_pair != i && level_inner != i &&
 	level_middle != i && level_outer != i && level_kspace != i) flag = 1;
   if (flag && comm->me == 0) 
     error->warning(FLERR,"One or more respa levels compute no forces");
 
   // check cutoff consistency if inner/middle/outer are enabled
 
   if (level_inner >= 0 && cutoff[1] < cutoff[0])
     error->all(FLERR,"Respa inner cutoffs are invalid");
   if (level_middle >= 0 && (cutoff[3] < cutoff[2] || cutoff[2] < cutoff[1]))
     error->all(FLERR,"Respa middle cutoffs are invalid");
 
   // set outer pair of cutoffs to inner pair if middle is not enabled
 
   if (level_inner >= 0 && level_middle < 0) {
     cutoff[2] = cutoff[0];
     cutoff[3] = cutoff[1];
   }
 
   // allocate other needed arrays
 
   newton = new int[nlevels];
   step = new double[nlevels];
 }
 
 /* ---------------------------------------------------------------------- */
 
 Respa::~Respa()
 {
   delete [] loop;
   delete [] newton;
   delete [] step;
 }
 
 /* ----------------------------------------------------------------------
    initialization before run
 ------------------------------------------------------------------------- */
 
 void Respa::init()
 {
+  Integrate::init();
+
   // warn if no fixes
 
   if (modify->nfix == 0 && comm->me == 0)
     error->warning(FLERR,"No fixes defined, atoms won't move");
 
   // create fix needed for storing atom-based respa level forces
   // will delete it at end of run
 
   char **fixarg = new char*[4];
   fixarg[0] = (char *) "RESPA";
   fixarg[1] = (char *) "all";
   fixarg[2] = (char *) "RESPA";
   fixarg[3] = new char[8];
   sprintf(fixarg[3],"%d",nlevels);
   modify->add_fix(4,fixarg);
   delete [] fixarg[3];
   delete [] fixarg;
   fix_respa = (FixRespa *) modify->fix[modify->nfix-1];
 
   // insure respa inner/middle/outer is using Pair class that supports it
 
   if (level_inner >= 0)
     if (force->pair && force->pair->respa_enable == 0)
       error->all(FLERR,"Pair style does not support rRESPA inner/middle/outer");
 
   // virial_style = 1 (explicit) since never computed implicitly like Verlet
 
   virial_style = 1;
 
   // setup lists of computes for global and per-atom PE and pressure
 
   ev_setup();
 
   // detect if fix omp is present and will clear force arrays for us
   int ifix = modify->find_fix("package_omp");
   if (ifix >= 0) external_force_clear = 1;
 
   // set flags for what arrays to clear in force_clear()
   // need to clear additionals arrays if they exist
 
   torqueflag = 0;
   if (atom->torque_flag) torqueflag = 1;
   erforceflag = 0;
   if (atom->erforce_flag) erforceflag = 1;
   e_flag = 0;
   if (atom->e_flag) e_flag = 1;
   rho_flag = 0;
   if (atom->rho_flag) rho_flag = 1;
 
   // step[] = timestep for each level
 
   step[nlevels-1] = update->dt;
   for (int ilevel = nlevels-2; ilevel >= 0; ilevel--) 
     step[ilevel] = step[ilevel+1]/loop[ilevel];
 
   // set newton flag for each level
 
   for (int ilevel = 0; ilevel < nlevels; ilevel++) {
     newton[ilevel] = 0;
     if (force->newton_bond) {
       if (level_bond == ilevel || level_angle == ilevel || 
 	  level_dihedral == ilevel || level_improper == ilevel)
 	newton[ilevel] = 1;
     }
     if (force->newton_pair) {
       if (level_pair == ilevel || level_inner == ilevel || 
 	  level_middle == ilevel || level_outer == ilevel)
 	newton[ilevel] = 1;
     }
   }
 
   // orthogonal vs triclinic simulation box
 
   triclinic = domain->triclinic;
 }
 
 /* ----------------------------------------------------------------------
    setup before run
 ------------------------------------------------------------------------- */
 
 void Respa::setup()
 {
   if (comm->me == 0 && screen) fprintf(screen,"Setting up run ...\n");
 
   update->setupflag = 1;
 
   // setup domain, communication and neighboring
   // acquire ghosts
   // build neighbor lists
 
   atom->setup();
   modify->setup_pre_exchange();
   if (triclinic) domain->x2lamda(atom->nlocal);
   domain->pbc();
   domain->reset_box();
   comm->setup();
   if (neighbor->style) neighbor->setup_bins();
   comm->exchange();
   if (atom->sortfreq > 0) atom->sort();
   comm->borders();
   if (triclinic) domain->lamda2x(atom->nlocal+atom->nghost);
   neighbor->build();
   neighbor->ncalls = 0;
 
   // compute all forces
 
   ev_set(update->ntimestep);
 
   for (int ilevel = 0; ilevel < nlevels; ilevel++) {
     force_clear(newton[ilevel]);
     modify->setup_pre_force_respa(vflag,ilevel);
     if (level_bond == ilevel && force->bond)
       force->bond->compute(eflag,vflag);
     if (level_angle == ilevel && force->angle) 
       force->angle->compute(eflag,vflag);
     if (level_dihedral == ilevel && force->dihedral) 
       force->dihedral->compute(eflag,vflag);
     if (level_improper == ilevel && force->improper) 
       force->improper->compute(eflag,vflag);
-    if (level_pair == ilevel && force->pair)
+    if (level_pair == ilevel && pair_compute_flag)
       force->pair->compute(eflag,vflag);
-    if (level_inner == ilevel && force->pair)
+    if (level_inner == ilevel && pair_compute_flag)
       force->pair->compute_inner();
-    if (level_middle == ilevel && force->pair)
+    if (level_middle == ilevel && pair_compute_flag)
       force->pair->compute_middle();
-    if (level_outer == ilevel && force->pair)
+    if (level_outer == ilevel && pair_compute_flag)
       force->pair->compute_outer(eflag,vflag);
     if (level_kspace == ilevel && force->kspace) {
       force->kspace->setup();
-      force->kspace->compute(eflag,vflag);
+      if (kspace_compute_flag) force->kspace->compute(eflag,vflag);
     }
     if (newton[ilevel]) comm->reverse_comm();
     copy_f_flevel(ilevel);
   }
   
   modify->setup(vflag);
   sum_flevel_f();
   output->setup(1);
   update->setupflag = 0;
 }
 
 /* ----------------------------------------------------------------------
    setup without output
    flag = 0 = just force calculation
    flag = 1 = reneighbor and force calculation
 ------------------------------------------------------------------------- */
 
 void Respa::setup_minimal(int flag)
 {
   update->setupflag = 1;
 
   // setup domain, communication and neighboring
   // acquire ghosts
   // build neighbor lists
 
   if (flag) {
     if (triclinic) domain->x2lamda(atom->nlocal);
     domain->pbc();
     domain->reset_box();
     comm->setup();
     if (neighbor->style) neighbor->setup_bins();
     comm->exchange();
     comm->borders();
     if (triclinic) domain->lamda2x(atom->nlocal+atom->nghost);
     neighbor->build();
     neighbor->ncalls = 0;
   }
 
   // compute all forces
 
   ev_set(update->ntimestep);
 
   for (int ilevel = 0; ilevel < nlevels; ilevel++) {
     force_clear(newton[ilevel]);
     modify->setup_pre_force_respa(vflag,ilevel);
     if (level_bond == ilevel && force->bond)
       force->bond->compute(eflag,vflag);
     if (level_angle == ilevel && force->angle) 
       force->angle->compute(eflag,vflag);
     if (level_dihedral == ilevel && force->dihedral) 
       force->dihedral->compute(eflag,vflag);
     if (level_improper == ilevel && force->improper) 
       force->improper->compute(eflag,vflag);
-    if (level_pair == ilevel && force->pair)
+    if (level_pair == ilevel && pair_compute_flag)
       force->pair->compute(eflag,vflag);
-    if (level_inner == ilevel && force->pair)
+    if (level_inner == ilevel && pair_compute_flag)
       force->pair->compute_inner();
-    if (level_middle == ilevel && force->pair)
+    if (level_middle == ilevel && pair_compute_flag)
       force->pair->compute_middle();
-    if (level_outer == ilevel && force->pair)
+    if (level_outer == ilevel && pair_compute_flag)
       force->pair->compute_outer(eflag,vflag);
     if (level_kspace == ilevel && force->kspace) {
       force->kspace->setup();
-      force->kspace->compute(eflag,vflag);
+      if (kspace_compute_flag) force->kspace->compute(eflag,vflag);
     }
     if (newton[ilevel]) comm->reverse_comm();
     copy_f_flevel(ilevel);
   }
   
   modify->setup(vflag);
   sum_flevel_f();
   update->setupflag = 0;
 }
 
 /* ----------------------------------------------------------------------
    run for N steps
 ------------------------------------------------------------------------- */
 
 void Respa::run(int n)
 {
   bigint ntimestep;
 
   for (int i = 0; i < n; i++) {
 
     ntimestep = ++update->ntimestep;
     ev_set(ntimestep);
 
     recurse(nlevels-1);
 
     if (modify->n_end_of_step) {
       timer->stamp();
       modify->end_of_step();
       timer->stamp(Timer::MODIFY);
     }
 
     if (ntimestep == output->next) {
       timer->stamp();
       sum_flevel_f();
       output->write(update->ntimestep);
       timer->stamp(Timer::OUTPUT);
     }
   }
 }
 
 /* ----------------------------------------------------------------------
    delete rRESPA fix at end of run, so its atom arrays won't persist
 ------------------------------------------------------------------------- */
 
 void Respa::cleanup()
 {
   modify->post_run();
   modify->delete_fix("RESPA");
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Respa::reset_dt()
 {
   step[nlevels-1] = update->dt;
   for (int ilevel = nlevels-2; ilevel >= 0; ilevel--) 
     step[ilevel] = step[ilevel+1]/loop[ilevel];
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Respa::recurse(int ilevel)
 {
   copy_flevel_f(ilevel);
 
   for (int iloop = 0; iloop < loop[ilevel]; iloop++) {
 
 	timer->stamp();
     modify->initial_integrate_respa(vflag,ilevel,iloop);
     if (modify->n_post_integrate_respa)
       modify->post_integrate_respa(ilevel,iloop);
 	timer->stamp(Timer::MODIFY);
 
     if (ilevel) recurse(ilevel-1);
 
     // at outermost level, check on rebuilding neighbor list
     // at innermost level, communicate
     // at middle levels, do nothing
 
     if (ilevel == nlevels-1) {
       int nflag = neighbor->decide();
       if (nflag) {
 	if (modify->n_pre_exchange) {
       timer->stamp();
       modify->pre_exchange();
 	  timer->stamp(Timer::MODIFY);
     }
 	if (triclinic) domain->x2lamda(atom->nlocal);
 	domain->pbc();
 	if (domain->box_change) {
 	  domain->reset_box();
 	  comm->setup();
 	  if (neighbor->style) neighbor->setup_bins();
 	}
 	timer->stamp();
 	comm->exchange();
 	if (atom->sortfreq > 0 && 
 	    update->ntimestep >= atom->nextsort) atom->sort();
 	comm->borders();
 	if (triclinic) domain->lamda2x(atom->nlocal+atom->nghost);
 	timer->stamp(Timer::COMM);
 	if (modify->n_pre_neighbor) {
       modify->pre_neighbor();
 	  timer->stamp(Timer::MODIFY);
     }
 	neighbor->build();
 	timer->stamp(Timer::NEIGHBOR);
       }
 
     } else if (ilevel == 0) {
       timer->stamp();
       comm->forward_comm();
       timer->stamp(Timer::COMM);
     }
 
     force_clear(newton[ilevel]);
     if (modify->n_pre_force_respa) {
 	  timer->stamp();
       modify->pre_force_respa(vflag,ilevel,iloop);
 	  timer->stamp(Timer::MODIFY);
     }
 
     timer->stamp();
     if (level_bond == ilevel && force->bond) {
       force->bond->compute(eflag,vflag);
       timer->stamp(Timer::BOND);
     }
     if (level_angle == ilevel && force->angle) {
       force->angle->compute(eflag,vflag);
       timer->stamp(Timer::BOND);
     }
     if (level_dihedral == ilevel && force->dihedral) {
       force->dihedral->compute(eflag,vflag);
       timer->stamp(Timer::BOND);
     }
     if (level_improper == ilevel && force->improper) {
       force->improper->compute(eflag,vflag);
       timer->stamp(Timer::BOND);
     }
-    if (level_pair == ilevel && force->pair) {
+    if (level_pair == ilevel && pair_compute_flag) {
       force->pair->compute(eflag,vflag);
       timer->stamp(Timer::PAIR);
     }
-    if (level_inner == ilevel && force->pair) {
+    if (level_inner == ilevel && pair_compute_flag) {
       force->pair->compute_inner();
       timer->stamp(Timer::PAIR);
     }
-    if (level_middle == ilevel && force->pair) {
+    if (level_middle == ilevel && pair_compute_flag) {
       force->pair->compute_middle();
       timer->stamp(Timer::PAIR);
     }
-    if (level_outer == ilevel && force->pair) {
+    if (level_outer == ilevel && pair_compute_flag) {
       force->pair->compute_outer(eflag,vflag);
       timer->stamp(Timer::PAIR);
     }
-    if (level_kspace == ilevel && force->kspace) {
+    if (level_kspace == ilevel && kspace_compute_flag) {
       force->kspace->compute(eflag,vflag);
       timer->stamp(Timer::KSPACE);
     }
 
     if (newton[ilevel]) {
       comm->reverse_comm();
       timer->stamp(Timer::COMM);
     }
   
     timer->stamp();
     if (modify->n_post_force_respa)
       modify->post_force_respa(vflag,ilevel,iloop);
     modify->final_integrate_respa(ilevel,iloop);
     timer->stamp(Timer::MODIFY);
   }
 
   copy_f_flevel(ilevel);
 }
 
 /* ----------------------------------------------------------------------
    clear force on own & ghost atoms
 ------------------------------------------------------------------------- */
 
 void Respa::force_clear(int newtonflag)
 {
   if (external_force_clear) return;
 
   int i;
 
   if (external_force_clear) return;
 
   // clear global force array
   // nall includes ghosts only if newton flag is set
 
   int nall;
   if (newtonflag) nall = atom->nlocal + atom->nghost;
   else nall = atom->nlocal;
 
   size_t nbytes = sizeof(double) * nall;
 
   if (nbytes > 0 ) {
     memset(&(atom->f[0][0]),0,3*nbytes);
     if (torqueflag)  memset(&(atom->torque[0][0]),0,3*nbytes);
     if (erforceflag) memset(&(atom->erforce[0]),  0,  nbytes);
     if (e_flag)      memset(&(atom->de[0]),       0,  nbytes);
     if (rho_flag)    memset(&(atom->drho[0]),     0,  nbytes);
   }
 }
 
 /* ----------------------------------------------------------------------
    copy force components from atom->f to FixRespa->f_level
 ------------------------------------------------------------------------- */
 
 void Respa::copy_f_flevel(int ilevel)
 {
   double ***f_level = fix_respa->f_level;
   double **f = atom->f;
   int n = atom->nlocal;
 
   for (int i = 0; i < n; i++) {
     f_level[i][ilevel][0] = f[i][0];
     f_level[i][ilevel][1] = f[i][1];
     f_level[i][ilevel][2] = f[i][2];
   }
 }
 
 /* ----------------------------------------------------------------------
    copy force components from FixRespa->f_level to atom->f
 ------------------------------------------------------------------------- */
 
 void Respa::copy_flevel_f(int ilevel)
 {
   double ***f_level = fix_respa->f_level;
   double **f = atom->f;
   int n = atom->nlocal;
 
   for (int i = 0; i < n; i++) {
     f[i][0] = f_level[i][ilevel][0];
     f[i][1] = f_level[i][ilevel][1];
     f[i][2] = f_level[i][ilevel][2];
   }
 }
 
 /* ----------------------------------------------------------------------
    sum all force components from FixRespa->f_level to create full atom->f
 ------------------------------------------------------------------------- */
 
 void Respa::sum_flevel_f()
 {
   copy_flevel_f(0);
 
   double ***f_level = fix_respa->f_level;
   double **f = atom->f;
   int n = atom->nlocal;
 
   for (int ilevel = 1; ilevel < nlevels; ilevel++) {
     for (int i = 0; i < n; i++) {
       f[i][0] += f_level[i][ilevel][0];
       f[i][1] += f_level[i][ilevel][1];
       f[i][2] += f_level[i][ilevel][2];
     }
   }
 }
diff --git a/src/verlet.cpp b/src/verlet.cpp
index 82b661283..8632b0fc2 100644
--- a/src/verlet.cpp
+++ b/src/verlet.cpp
@@ -1,425 +1,431 @@
 /* ----------------------------------------------------------------------
    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 "verlet.h"
 #include "neighbor.h"
 #include "domain.h"
 #include "comm.h"
 #include "atom.h"
 #include "force.h"
 #include "pair.h"
 #include "bond.h"
 #include "angle.h"
 #include "dihedral.h"
 #include "improper.h"
 #include "kspace.h"
 #include "output.h"
 #include "update.h"
 #include "modify.h"
 #include "compute.h"
 #include "fix.h"
 #include "timer.h"
 #include "memory.h"
 #include "error.h"
 
 using namespace LAMMPS_NS;
 
 /* ---------------------------------------------------------------------- */
 
 Verlet::Verlet(LAMMPS *lmp, int narg, char **arg) :
   Integrate(lmp, narg, arg) {}
 
 /* ----------------------------------------------------------------------
    initialization before run
 ------------------------------------------------------------------------- */
 
 void Verlet::init()
 {
+  Integrate::init();
+
   // warn if no fixes
 
   if (modify->nfix == 0 && comm->me == 0)
     error->warning(FLERR,"No fixes defined, atoms won't move");
 
   // virial_style:
   // 1 if computed explicitly by pair->compute via sum over pair interactions
   // 2 if computed implicitly by pair->virial_fdotr_compute via sum over ghosts
 
   if (force->newton_pair) virial_style = 2;
   else virial_style = 1;
 
   // setup lists of computes for global and per-atom PE and pressure
 
   ev_setup();
 
   // detect if fix omp is present for clearing force arrays
 
   int ifix = modify->find_fix("package_omp");
   if (ifix >= 0) external_force_clear = 1;
 
   // set flags for what arrays to clear in force_clear()
   // need to clear additionals arrays if they exist
 
   torqueflag = 0;
   if (atom->torque_flag) torqueflag = 1;
   erforceflag = 0;
   if (atom->erforce_flag) erforceflag = 1;
   e_flag = 0;
   if (atom->e_flag) e_flag = 1;
   rho_flag = 0;
   if (atom->rho_flag) rho_flag = 1;
 
   // orthogonal vs triclinic simulation box
 
   triclinic = domain->triclinic;
 }
 
 /* ----------------------------------------------------------------------
    setup before run
 ------------------------------------------------------------------------- */
 
 void Verlet::setup()
 {
   if (comm->me == 0 && screen) fprintf(screen,"Setting up run ...\n");
 
   update->setupflag = 1;
 
   // setup domain, communication and neighboring
   // acquire ghosts
   // build neighbor lists
 
   atom->setup();
   modify->setup_pre_exchange();
   if (triclinic) domain->x2lamda(atom->nlocal);
   domain->pbc();
   domain->reset_box();
   comm->setup();
   if (neighbor->style) neighbor->setup_bins();
   comm->exchange();
   if (atom->sortfreq > 0) atom->sort();
   comm->borders();
   if (triclinic) domain->lamda2x(atom->nlocal+atom->nghost);
   neighbor->build();
   neighbor->ncalls = 0;
 
   // compute all forces
 
   ev_set(update->ntimestep);
   force_clear();
   modify->setup_pre_force(vflag);
 
-  if (force->pair) force->pair->compute(eflag,vflag);
+  if (pair_compute_flag) force->pair->compute(eflag,vflag);
+  else if (force->pair) force->pair->compute_dummy(eflag,vflag);
 
   if (atom->molecular) {
     if (force->bond) force->bond->compute(eflag,vflag);
     if (force->angle) force->angle->compute(eflag,vflag);
     if (force->dihedral) force->dihedral->compute(eflag,vflag);
     if (force->improper) force->improper->compute(eflag,vflag);
   }
 
   if (force->kspace) {
     force->kspace->setup();
-    force->kspace->compute(eflag,vflag);
+    if (kspace_compute_flag) force->kspace->compute(eflag,vflag);
+    else force->kspace->compute_dummy(eflag,vflag);
   }
 
   if (force->newton) comm->reverse_comm();
 
   modify->setup(vflag);
   output->setup(1);
   update->setupflag = 0;
 }
 
 /* ----------------------------------------------------------------------
    setup without output
    flag = 0 = just force calculation
    flag = 1 = reneighbor and force calculation
 ------------------------------------------------------------------------- */
 
 void Verlet::setup_minimal(int flag)
 {
   update->setupflag = 1;
 
   // setup domain, communication and neighboring
   // acquire ghosts
   // build neighbor lists
 
   if (flag) {
     if (triclinic) domain->x2lamda(atom->nlocal);
     domain->pbc();
     domain->reset_box();
     comm->setup();
     if (neighbor->style) neighbor->setup_bins();
     comm->exchange();
     comm->borders();
     if (triclinic) domain->lamda2x(atom->nlocal+atom->nghost);
     neighbor->build();
     neighbor->ncalls = 0;
   }
 
   // compute all forces
 
   ev_set(update->ntimestep);
   force_clear();
   modify->setup_pre_force(vflag);
 
-  if (force->pair) force->pair->compute(eflag,vflag);
+  if (pair_compute_flag) force->pair->compute(eflag,vflag);
+  else if (force->pair) force->pair->compute_dummy(eflag,vflag);
 
   if (atom->molecular) {
     if (force->bond) force->bond->compute(eflag,vflag);
     if (force->angle) force->angle->compute(eflag,vflag);
     if (force->dihedral) force->dihedral->compute(eflag,vflag);
     if (force->improper) force->improper->compute(eflag,vflag);
   }
 
   if (force->kspace) {
     force->kspace->setup();
-    force->kspace->compute(eflag,vflag);
+    if (kspace_compute_flag) force->kspace->compute(eflag,vflag);
+    else force->kspace->compute_dummy(eflag,vflag);
   }
 
   if (force->newton) comm->reverse_comm();
 
   modify->setup(vflag);
   update->setupflag = 0;
 }
 
 /* ----------------------------------------------------------------------
    run for N steps
 ------------------------------------------------------------------------- */
 
 void Verlet::run(int n)
 {
   bigint ntimestep;
   int nflag,sortflag;
 
   int n_post_integrate = modify->n_post_integrate;
   int n_pre_exchange = modify->n_pre_exchange;
   int n_pre_neighbor = modify->n_pre_neighbor;
   int n_pre_force = modify->n_pre_force;
   int n_post_force = modify->n_post_force;
   int n_end_of_step = modify->n_end_of_step;
 
   if (atom->sortfreq > 0) sortflag = 1;
   else sortflag = 0;
 
   for (int i = 0; i < n; i++) {
 
     ntimestep = ++update->ntimestep;
     ev_set(ntimestep);
 
     // initial time integration
 
     timer->stamp();
     modify->initial_integrate(vflag);
     if (n_post_integrate) modify->post_integrate();
     timer->stamp(Timer::MODIFY);
 
     // regular communication vs neighbor list rebuild
 
     nflag = neighbor->decide();
 
     if (nflag == 0) {
       timer->stamp();
       comm->forward_comm();
       timer->stamp(Timer::COMM);
     } else {
       if (n_pre_exchange) {
 	timer->stamp();
 	modify->pre_exchange();
 	timer->stamp(Timer::MODIFY);
       }
       if (triclinic) domain->x2lamda(atom->nlocal);
       domain->pbc();
       if (domain->box_change) {
 	domain->reset_box();
 	comm->setup();
 	if (neighbor->style) neighbor->setup_bins();
       }
       timer->stamp();
       comm->exchange();
       if (sortflag && ntimestep >= atom->nextsort) atom->sort();
       comm->borders();
       if (triclinic) domain->lamda2x(atom->nlocal+atom->nghost);
       timer->stamp(Timer::COMM);
       if (n_pre_neighbor) {
 	modify->pre_neighbor();
 	timer->stamp(Timer::MODIFY);
       }
       neighbor->build();
       timer->stamp(Timer::NEIGHBOR);
     }
 
     // force computations
 
     force_clear();
 
     timer->stamp();
 
     if (n_pre_force) {
       modify->pre_force(vflag);
       timer->stamp(Timer::MODIFY);
     }
 
 
-    if (force->pair) {
+    if (pair_compute_flag) {
       force->pair->compute(eflag,vflag);
       timer->stamp(Timer::PAIR);
     }
 
     if (atom->molecular) {
       if (force->bond) force->bond->compute(eflag,vflag);
       if (force->angle) force->angle->compute(eflag,vflag);
       if (force->dihedral) force->dihedral->compute(eflag,vflag);
       if (force->improper) force->improper->compute(eflag,vflag);
       timer->stamp(Timer::BOND);
     }
 
-    if (force->kspace) {
+    if (kspace_compute_flag) {
       force->kspace->compute(eflag,vflag);
       timer->stamp(Timer::KSPACE);
     }
 
     // reverse communication of forces
 
     if (force->newton) {
       comm->reverse_comm();
       timer->stamp(Timer::COMM);
     }
 
     // force modifications, final time integration, diagnostics
 
     if (n_post_force) modify->post_force(vflag);
     modify->final_integrate();
     if (n_end_of_step) modify->end_of_step();
     timer->stamp(Timer::MODIFY);
 
     // all output
 
     if (ntimestep == output->next) {
       timer->stamp();
       output->write(ntimestep);
       timer->stamp(Timer::OUTPUT);
     }
   }
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Verlet::cleanup()
 {
   modify->post_run();
 }
 
 /* ----------------------------------------------------------------------
    clear force on own & ghost atoms
    setup and clear other arrays as needed
 ------------------------------------------------------------------------- */
 
 void Verlet::force_clear()
 {
   if (external_force_clear) return;
   int i;
 
   if (external_force_clear) return;
 
   // clear force on all particles
   // if either newton flag is set, also include ghosts
   // when using threads always clear all forces.
 
   if (neighbor->includegroup == 0) {
     int nall;
     if (force->newton) nall = atom->nlocal + atom->nghost;
     else nall = atom->nlocal;
 
     size_t nbytes = sizeof(double) * nall;
 
     if (nbytes > 0) {
       memset(&(atom->f[0][0]),0,3*nbytes);
       if (torqueflag)  memset(&(atom->torque[0][0]),0,3*nbytes);
       if (erforceflag) memset(&(atom->erforce[0]),  0,  nbytes);
       if (e_flag)      memset(&(atom->de[0]),       0,  nbytes);
       if (rho_flag)    memset(&(atom->drho[0]),     0,  nbytes);
     }
 
   // neighbor includegroup flag is set
   // clear force only on initial nfirst particles
   // if either newton flag is set, also include ghosts
 
   } else {
     int nall = atom->nfirst;
 
     double **f = atom->f;
     for (i = 0; i < nall; i++) {
       f[i][0] = 0.0;
       f[i][1] = 0.0;
       f[i][2] = 0.0;
     }
     
     if (torqueflag) {
       double **torque = atom->torque;
       for (i = 0; i < nall; i++) {
 	torque[i][0] = 0.0;
 	torque[i][1] = 0.0;
 	torque[i][2] = 0.0;
       }
     }
 
     if (erforceflag) {
       double *erforce = atom->erforce;
       for (i = 0; i < nall; i++) erforce[i] = 0.0;
     }
 
     if (e_flag) {
       double *de = atom->de;
       for (i = 0; i < nall; i++) de[i] = 0.0;
     }
 
     if (rho_flag) {
       double *drho = atom->drho;
       for (i = 0; i < nall; i++) drho[i] = 0.0;
     }
 
     if (force->newton) {
       nall = atom->nlocal + atom->nghost;
 
       for (i = atom->nlocal; i < nall; i++) {
 	f[i][0] = 0.0;
 	f[i][1] = 0.0;
 	f[i][2] = 0.0;
       }
     
       if (torqueflag) {
 	double **torque = atom->torque;
 	for (i = atom->nlocal; i < nall; i++) {
 	  torque[i][0] = 0.0;
 	  torque[i][1] = 0.0;
 	  torque[i][2] = 0.0;
 	}
       }
 
       if (erforceflag) {
 	double *erforce = atom->erforce;
 	for (i = atom->nlocal; i < nall; i++) erforce[i] = 0.0;
       }
 
       if (e_flag) {
 	double *de = atom->de;
 	for (i = 0; i < nall; i++) de[i] = 0.0;
       }
 
       if (rho_flag) {
 	double *drho = atom->drho;
 	for (i = 0; i < nall; i++) drho[i] = 0.0;
       }
     }
   }
 }
diff --git a/src/version.h b/src/version.h
index 4412c3a44..05cb579ab 100644
--- a/src/version.h
+++ b/src/version.h
@@ -1 +1 @@
-#define LAMMPS_VERSION "10 Apr 2012"
+#define LAMMPS_VERSION "12 Apr 2012"