diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
index bf57398c71b851d45848e90a6b8e1b1dbe8a8dcd..60a0f5d48fb7ea425858504105e1cce5f9c3e244 100644
--- a/cmake/CMakeLists.txt
+++ b/cmake/CMakeLists.txt
@@ -332,7 +332,7 @@ if(PKG_LATTE)
     include(ExternalProject)
     ExternalProject_Add(latte_build
       URL https://github.com/lanl/LATTE/archive/v1.2.1.tar.gz
-      URL_MD5 bed76e7e76c545c36dd848a8f1fd35eb
+      URL_MD5 85ac414fdada2d04619c8f936344df14
       SOURCE_SUBDIR cmake
       CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=<INSTALL_DIR> -DCMAKE_POSITION_INDEPENDENT_CODE=${CMAKE_POSITION_INDEPENDENT_CODE}
       )
diff --git a/doc/Makefile b/doc/Makefile
index c8cc8bc1bd027947165d30d79df3a0a8f3c0d73b..c4bc80e7bd5de665a857a5488842cd8be63e51cf 100644
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -49,11 +49,11 @@ help:
 
 # ------------------------------------------
 
-clean-all:
+clean-all: clean
 	rm -rf $(BUILDDIR)/* utils/txt2html/txt2html.exe
 
 clean:
-	rm -rf $(RSTDIR) html
+	rm -rf $(RSTDIR) html old epub
 	rm -rf spelling
 
 clean-spelling:
diff --git a/doc/src/Eqs/pair_body_rounded.jpg b/doc/src/Eqs/pair_body_rounded.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..e7136ddd20c2acea0e89fa8412497333f15cb541
Binary files /dev/null and b/doc/src/Eqs/pair_body_rounded.jpg differ
diff --git a/doc/src/Eqs/pair_body_rounded.tex b/doc/src/Eqs/pair_body_rounded.tex
new file mode 100644
index 0000000000000000000000000000000000000000..54e095340f1ab3ae13d672d35797a56faeee927a
--- /dev/null
+++ b/doc/src/Eqs/pair_body_rounded.tex
@@ -0,0 +1,13 @@
+\documentstyle[12pt]{article}
+
+\begin{document}
+
+\begin{eqnarray*}
+ F_n &=& k_n \delta_n - c_n v_n, \qquad \delta_n \le 0 \\
+     &=& -k_{na} \delta_n - c_n v_n, \qquad 0 < \delta_n \le r_c \\
+     &=& 0 \qquad \qquad \qquad \qquad \delta_n > r_c \\
+ F_t &=& \mu k_n \delta_n - c_t v_t, \qquad \delta_n \le 0 \\
+     &=& 0 \qquad \qquad \qquad \qquad \delta_n > 0
+\end{eqnarray*}
+
+\end{document}
diff --git a/doc/src/Errors.txt b/doc/src/Errors.txt
new file mode 100644
index 0000000000000000000000000000000000000000..7bc520c19dbacc86aaa7a1bd4083f884bde53752
--- /dev/null
+++ b/doc/src/Errors.txt
@@ -0,0 +1,37 @@
+"Previous Section"_Python.html - "LAMMPS WWW Site"_lws -
+"LAMMPS Documentation"_ld - "LAMMPS Commands"_lc - "Next
+Section"_Section_history.html :c
+
+:link(lws,http://lammps.sandia.gov)
+:link(ld,Manual.html)
+:link(lc,Section_commands.html#comm)
+
+:line
+
+Errors :h2
+
+These doc pages describe the errors you can encounter when using
+LAMMPS.  The common problems include conceptual issues.  The messages
+and warnings doc pages give complete lists of all the messages the
+code may generate (except those generated by USER packages), with
+additional details for many of them.
+
+<!-- RST
+
+.. toctree::
+
+   Errors_common
+   Errors_bugs
+   Errors_messages
+   Errors_warnings
+
+END_RST -->
+
+<!-- HTML_ONLY -->
+
+"Common problems"_Errors_common.html
+"Reporting bugs"_Errors_bugs.html
+"Error messages"_Errors_messages.html 
+"Warning messages"_Errors_warnings.html :all(b)
+
+<!-- END_HTML_ONLY -->
diff --git a/doc/src/Errors_bugs.txt b/doc/src/Errors_bugs.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c0a94c7a44b124bc6d987b40d9f0b25ca9b520b5
--- /dev/null
+++ b/doc/src/Errors_bugs.txt
@@ -0,0 +1,35 @@
+"Higher level section"_Errors.html - "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
+
+Reporting bugs :h3
+
+If you are confident that you have found a bug in LAMMPS, follow these
+steps.
+
+Check the "New features and bug
+fixes"_http://lammps.sandia.gov/bug.html section of the "LAMMPS WWW
+site"_lws to see if the bug has already been reported or fixed or the
+"Unfixed bug"_http://lammps.sandia.gov/unbug.html to see if a fix is
+pending.
+
+Check the "mailing list"_http://lammps.sandia.gov/mail.html to see if
+it has been discussed before.
+
+If not, send an email to the mailing list describing the problem with
+any ideas you have as to what is causing it or where in the code the
+problem might be.  The developers will ask for more info if needed,
+such as an input script or data files.
+
+The most useful thing you can do to help us fix the bug is to isolate
+the problem.  Run it on the smallest number of atoms and fewest number
+of processors and with the simplest input script that reproduces the
+bug and try to identify what command or combination of commands is
+causing the problem.
+
+NOTE: this page needs to have GitHub issues info added
diff --git a/doc/src/Errors_common.txt b/doc/src/Errors_common.txt
new file mode 100644
index 0000000000000000000000000000000000000000..86a25f7e7d4b262fc4e730b42a5584ce76133d12
--- /dev/null
+++ b/doc/src/Errors_common.txt
@@ -0,0 +1,123 @@
+"Higher level section"_Errors.html - "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
+
+Common problems :h3
+
+If two LAMMPS runs do not produce the exact same answer on different
+machines or different numbers of processors, this is typically not a
+bug.  In theory you should get identical answers on any number of
+processors and on any machine.  In practice, numerical round-off can
+cause slight differences and eventual divergence of molecular dynamics
+phase space trajectories within a few 100s or few 1000s of timesteps.
+However, the statistical properties of the two runs (e.g. average
+energy or temperature) should still be the same.
+
+If the "velocity"_velocity.html command is used to set initial atom
+velocities, a particular atom can be assigned a different velocity
+when the problem is run on a different number of processors or on
+different machines.  If this happens, the phase space trajectories of
+the two simulations will rapidly diverge.  See the discussion of the
+{loop} option in the "velocity"_velocity.html command for details and
+options that avoid this issue.
+
+Similarly, the "create_atoms"_create_atoms.html command generates a
+lattice of atoms.  For the same physical system, the ordering and
+numbering of atoms by atom ID may be different depending on the number
+of processors.
+
+Some commands use random number generators which may be setup to
+produce different random number streams on each processor and hence
+will produce different effects when run on different numbers of
+processors.  A commonly-used example is the "fix
+langevin"_fix_langevin.html command for thermostatting.
+
+A LAMMPS simulation typically has two stages, setup and run.  Most
+LAMMPS errors are detected at setup time; others like a bond
+stretching too far may not occur until the middle of a run.
+
+LAMMPS tries to flag errors and print informative error messages so
+you can fix the problem.  For most errors it will also print the last
+input script command that it was processing.  Of course, LAMMPS cannot
+figure out your physics or numerical mistakes, like choosing too big a
+timestep, specifying erroneous force field coefficients, or putting 2
+atoms on top of each other!  If you run into errors that LAMMPS
+doesn't catch that you think it should flag, please send an email to
+the "developers"_http://lammps.sandia.gov/authors.html.
+
+If you get an error message about an invalid command in your input
+script, you can determine what command is causing the problem by
+looking in the log.lammps file or using the "echo command"_echo.html
+to see it on the screen.  If you get an error like "Invalid ...
+style", with ... being fix, compute, pair, etc, it means that you
+mistyped the style name or that the command is part of an optional
+package which was not compiled into your executable.  The list of
+available styles in your executable can be listed by using "the -h
+command-line argument"_Section_start.html#start_6.  The installation
+and compilation of optional packages is explained in the "installation
+instructions"_Section_start.html#start_3.
+
+For a given command, LAMMPS expects certain arguments in a specified
+order.  If you mess this up, LAMMPS will often flag the error, but it
+may also simply read a bogus argument and assign a value that is
+valid, but not what you wanted.  E.g. trying to read the string "abc"
+as an integer value of 0.  Careful reading of the associated doc page
+for the command should allow you to fix these problems. In most cases,
+where LAMMPS expects to read a number, either integer or floating point,
+it performs a stringent test on whether the provided input actually
+is an integer or floating-point number, respectively, and reject the
+input with an error message (for instance, when an integer is required,
+but a floating-point number 1.0 is provided):
+
+ERROR: Expected integer parameter in input script or data file :pre
+
+Some commands allow for using variable references in place of numeric
+constants so that the value can be evaluated and may change over the
+course of a run.  This is typically done with the syntax {v_name} for a
+parameter, where name is the name of the variable. On the other hand,
+immediate variable expansion with the syntax ${name} is performed while
+reading the input and before parsing commands,
+
+NOTE: Using a variable reference (i.e. {v_name}) is only allowed if
+the documentation of the corresponding command explicitly says it is.
+
+Generally, LAMMPS will print a message to the screen and logfile and
+exit gracefully when it encounters a fatal error.  Sometimes it will
+print a WARNING to the screen and logfile and continue on; you can
+decide if the WARNING is important or not.  A WARNING message that is
+generated in the middle of a run is only printed to the screen, not to
+the logfile, to avoid cluttering up thermodynamic output.  If LAMMPS
+crashes or hangs without spitting out an error message first then it
+could be a bug (see "this section"_#err_2) or one of the following
+cases:
+
+LAMMPS runs in the available memory a processor allows to be
+allocated.  Most reasonable MD runs are compute limited, not memory
+limited, so this shouldn't be a bottleneck on most platforms.  Almost
+all large memory allocations in the code are done via C-style malloc's
+which will generate an error message if you run out of memory.
+Smaller chunks of memory are allocated via C++ "new" statements.  If
+you are unlucky you could run out of memory just when one of these
+small requests is made, in which case the code will crash or hang (in
+parallel), since LAMMPS doesn't trap on those errors.
+
+Illegal arithmetic can cause LAMMPS to run slow or crash.  This is
+typically due to invalid physics and numerics that your simulation is
+computing.  If you see wild thermodynamic values or NaN values in your
+LAMMPS output, something is wrong with your simulation.  If you
+suspect this is happening, it is a good idea to print out
+thermodynamic info frequently (e.g. every timestep) via the
+"thermo"_thermo.html so you can monitor what is happening.
+Visualizing the atom movement is also a good idea to insure your model
+is behaving as you expect.
+
+In parallel, one way LAMMPS can hang is due to how different MPI
+implementations handle buffering of messages.  If the code hangs
+without an error message, it may be that you need to specify an MPI
+setting or two (usually via an environment variable) to enable
+buffering or boost the sizes of messages that can be buffered.
diff --git a/doc/src/Section_errors.txt b/doc/src/Errors_messages.txt
similarity index 87%
rename from doc/src/Section_errors.txt
rename to doc/src/Errors_messages.txt
index 95482b06dc5bc1d768a0e4c355d8aad5e5e08821..1563e029014e2d118fa3c9ae139b656597ced62d 100644
--- a/doc/src/Section_errors.txt
+++ b/doc/src/Errors_messages.txt
@@ -1,6 +1,5 @@
-"Previous Section"_Section_python.html - "LAMMPS WWW Site"_lws -
-"LAMMPS Documentation"_ld - "LAMMPS Commands"_lc - "Next
-Section"_Section_history.html :c
+"Higher level section"_Errors.html - "LAMMPS WWW Site"_lws - "LAMMPS
+Documentation"_ld - "LAMMPS Commands"_lc :c
 
 :link(lws,http://lammps.sandia.gov)
 :link(ld,Manual.html)
@@ -8,185 +7,27 @@ Section"_Section_history.html :c
 
 :line
 
-12. Errors :h2
+Error messages :h3
 
-This section describes the errors you can encounter when using LAMMPS,
-either conceptually, or as printed out by the program.
+This is an alphabetic list of the ERROR messages LAMMPS prints out and
+the reason why.  If the explanation here is not sufficient, the
+documentation for the offending command may help.  Error messages also
+list the source file and line number where the error was generated.
+For example, a message like this:
 
-12.1 "Common problems"_#err_1
-12.2 "Reporting bugs"_#err_2
-12.3 "Error & warning messages"_#err_3 :all(b)
-
-:line
-:line
-
-12.1 Common problems :link(err_1),h4
-
-If two LAMMPS runs do not produce the exact same answer on different
-machines or different numbers of processors, this is typically not a
-bug.  In theory you should get identical answers on any number of
-processors and on any machine.  In practice, numerical round-off can
-cause slight differences and eventual divergence of molecular dynamics
-phase space trajectories within a few 100s or few 1000s of timesteps.
-However, the statistical properties of the two runs (e.g. average
-energy or temperature) should still be the same.
-
-If the "velocity"_velocity.html command is used to set initial atom
-velocities, a particular atom can be assigned a different velocity
-when the problem is run on a different number of processors or on
-different machines.  If this happens, the phase space trajectories of
-the two simulations will rapidly diverge.  See the discussion of the
-{loop} option in the "velocity"_velocity.html command for details and
-options that avoid this issue.
-
-Similarly, the "create_atoms"_create_atoms.html command generates a
-lattice of atoms.  For the same physical system, the ordering and
-numbering of atoms by atom ID may be different depending on the number
-of processors.
-
-Some commands use random number generators which may be setup to
-produce different random number streams on each processor and hence
-will produce different effects when run on different numbers of
-processors.  A commonly-used example is the "fix
-langevin"_fix_langevin.html command for thermostatting.
-
-A LAMMPS simulation typically has two stages, setup and run.  Most
-LAMMPS errors are detected at setup time; others like a bond
-stretching too far may not occur until the middle of a run.
-
-LAMMPS tries to flag errors and print informative error messages so
-you can fix the problem.  For most errors it will also print the last
-input script command that it was processing.  Of course, LAMMPS cannot
-figure out your physics or numerical mistakes, like choosing too big a
-timestep, specifying erroneous force field coefficients, or putting 2
-atoms on top of each other!  If you run into errors that LAMMPS
-doesn't catch that you think it should flag, please send an email to
-the "developers"_http://lammps.sandia.gov/authors.html.
-
-If you get an error message about an invalid command in your input
-script, you can determine what command is causing the problem by
-looking in the log.lammps file or using the "echo command"_echo.html
-to see it on the screen.  If you get an error like "Invalid ...
-style", with ... being fix, compute, pair, etc, it means that you
-mistyped the style name or that the command is part of an optional
-package which was not compiled into your executable.  The list of
-available styles in your executable can be listed by using "the -h
-command-line argument"_Section_start.html#start_6.  The installation
-and compilation of optional packages is explained in the "installation
-instructions"_Section_start.html#start_3.
-
-For a given command, LAMMPS expects certain arguments in a specified
-order.  If you mess this up, LAMMPS will often flag the error, but it
-may also simply read a bogus argument and assign a value that is
-valid, but not what you wanted.  E.g. trying to read the string "abc"
-as an integer value of 0.  Careful reading of the associated doc page
-for the command should allow you to fix these problems. In most cases,
-where LAMMPS expects to read a number, either integer or floating point,
-it performs a stringent test on whether the provided input actually
-is an integer or floating-point number, respectively, and reject the
-input with an error message (for instance, when an integer is required,
-but a floating-point number 1.0 is provided):
-
-ERROR: Expected integer parameter in input script or data file :pre
-
-Some commands allow for using variable references in place of numeric
-constants so that the value can be evaluated and may change over the
-course of a run.  This is typically done with the syntax {v_name} for a
-parameter, where name is the name of the variable. On the other hand,
-immediate variable expansion with the syntax ${name} is performed while
-reading the input and before parsing commands,
-
-NOTE: Using a variable reference (i.e. {v_name}) is only allowed if
-the documentation of the corresponding command explicitly says it is.
-
-Generally, LAMMPS will print a message to the screen and logfile and
-exit gracefully when it encounters a fatal error.  Sometimes it will
-print a WARNING to the screen and logfile and continue on; you can
-decide if the WARNING is important or not.  A WARNING message that is
-generated in the middle of a run is only printed to the screen, not to
-the logfile, to avoid cluttering up thermodynamic output.  If LAMMPS
-crashes or hangs without spitting out an error message first then it
-could be a bug (see "this section"_#err_2) or one of the following
-cases:
-
-LAMMPS runs in the available memory a processor allows to be
-allocated.  Most reasonable MD runs are compute limited, not memory
-limited, so this shouldn't be a bottleneck on most platforms.  Almost
-all large memory allocations in the code are done via C-style malloc's
-which will generate an error message if you run out of memory.
-Smaller chunks of memory are allocated via C++ "new" statements.  If
-you are unlucky you could run out of memory just when one of these
-small requests is made, in which case the code will crash or hang (in
-parallel), since LAMMPS doesn't trap on those errors.
-
-Illegal arithmetic can cause LAMMPS to run slow or crash.  This is
-typically due to invalid physics and numerics that your simulation is
-computing.  If you see wild thermodynamic values or NaN values in your
-LAMMPS output, something is wrong with your simulation.  If you
-suspect this is happening, it is a good idea to print out
-thermodynamic info frequently (e.g. every timestep) via the
-"thermo"_thermo.html so you can monitor what is happening.
-Visualizing the atom movement is also a good idea to insure your model
-is behaving as you expect.
-
-In parallel, one way LAMMPS can hang is due to how different MPI
-implementations handle buffering of messages.  If the code hangs
-without an error message, it may be that you need to specify an MPI
-setting or two (usually via an environment variable) to enable
-buffering or boost the sizes of messages that can be buffered.
-
-:line
-
-12.2 Reporting bugs :link(err_2),h4
-
-If you are confident that you have found a bug in LAMMPS, follow these
-steps.
-
-Check the "New features and bug
-fixes"_http://lammps.sandia.gov/bug.html section of the "LAMMPS WWW
-site"_lws to see if the bug has already been reported or fixed or the
-"Unfixed bug"_http://lammps.sandia.gov/unbug.html to see if a fix is
-pending.
-
-Check the "mailing list"_http://lammps.sandia.gov/mail.html
-to see if it has been discussed before.
-
-If not, send an email to the mailing list describing the problem with
-any ideas you have as to what is causing it or where in the code the
-problem might be.  The developers will ask for more info if needed,
-such as an input script or data files.
-
-The most useful thing you can do to help us fix the bug is to isolate
-the problem.  Run it on the smallest number of atoms and fewest number
-of processors and with the simplest input script that reproduces the
-bug and try to identify what command or combination of commands is
-causing the problem.
-
-As a last resort, you can send an email directly to the
-"developers"_http://lammps.sandia.gov/authors.html.
-
-:line
-
-12.3 Error & warning messages :h3,link(err_3)
-
-These are two alphabetic lists of the "ERROR"_#error and
-"WARNING"_#warn messages LAMMPS prints out and the reason why.  If the
-explanation here is not sufficient, the documentation for the
-offending command may help.
-Error and warning messages also list the source file and line number
-where the error was generated.  For example, this message
-
-ERROR: Illegal velocity command (velocity.cpp:78)
+ERROR: Illegal velocity command (velocity.cpp:78) :pre
 
 means that line #78 in the file src/velocity.cpp generated the error.
 Looking in the source code may help you figure out what went wrong.
 
 Note that error messages from "user-contributed
-packages"_Section_start.html#start_3 are not listed here.  If such an
-error occurs and is not self-explanatory, you'll need to look in the
-source code or contact the author of the package.
+packages"_Section_package.html#table_user are not listed here.  If
+such an error occurs and is not self-explanatory, you'll need to look
+in the source code or contact the author of the package.
+
+Doc page with "WARNING messages"_Errors_warnings.html
 
-Errors: :h3,link(error)
+:line
 
 :dlb
 
@@ -803,13 +644,6 @@ lo value must be less than the hi value for all 3 dimensions. :dd
 The box command cannot be used after a read_data, read_restart, or
 create_box command. :dd
 
-{BUG: restartinfo=1 but no restart support in pair style} :dt
-
-The pair style has a bug, where it does not support reading
-and writing information to a restart file, but does not set
-the member variable restartinfo to 0 as required in that case. :dd
-
-
 {CPU neighbor lists must be used for ellipsoid/sphere mix.} :dt
 
 When using Gay-Berne or RE-squared pair styles with both ellipsoidal and
@@ -11003,904 +10837,3 @@ Self-explanatory. :dd
 Self-explanatory. :dd
 
 :dle
-
-Warnings: :h3,link(warn)
-
-:dlb
-
-{Adjusting Coulombic cutoff for MSM, new cutoff = %g} :dt
-
-The adjust/cutoff command is turned on and the Coulombic cutoff has been
-adjusted to match the user-specified accuracy. :dd
-
-{Angle atoms missing at step %ld} :dt
-
-One or more of 3 atoms needed to compute a particular angle are
-missing on this processor.  Typically this is because the pairwise
-cutoff is set too short or the angle has blown apart and an atom is
-too far away. :dd
-
-{Angle style in data file differs from currently defined angle style} :dt
-
-Self-explanatory. :dd
-
-{Atom style in data file differs from currently defined atom style} :dt
-
-Self-explanatory. :dd
-
-{Bond atom missing in box size check} :dt
-
-The 2nd atoms needed to compute a particular bond is missing on this
-processor.  Typically this is because the pairwise cutoff is set too
-short or the bond has blown apart and an atom is too far away. :dd
-
-{Bond atom missing in image check} :dt
-
-The 2nd atom in a particular bond is missing on this processor.
-Typically this is because the pairwise cutoff is set too short or the
-bond has blown apart and an atom is too far away. :dd
-
-{Bond atoms missing at step %ld} :dt
-
-The 2nd atom needed to compute a particular bond is missing on this
-processor.  Typically this is because the pairwise cutoff is set too
-short or the bond has blown apart and an atom is too far away. :dd
-
-{Bond style in data file differs from currently defined bond style} :dt
-
-Self-explanatory. :dd
-
-{Bond/angle/dihedral extent > half of periodic box length} :dt
-
-This is a restriction because LAMMPS can be confused about which image
-of an atom in the bonded interaction is the correct one to use.
-"Extent" in this context means the maximum end-to-end length of the
-bond/angle/dihedral.  LAMMPS computes this by taking the maximum bond
-length, multiplying by the number of bonds in the interaction (e.g. 3
-for a dihedral) and adding a small amount of stretch. :dd
-
-{Both groups in compute group/group have a net charge; the Kspace boundary correction to energy will be non-zero} :dt
-
-Self-explanatory. :dd
-
-{Calling write_dump before a full system init.} :dt
-
-The write_dump command is used before the system has been fully
-initialized as part of a 'run' or 'minimize' command. Not all dump
-styles and features are fully supported at this point and thus the
-command may fail or produce incomplete or incorrect output. Insert
-a "run 0" command, if a full system init is required. :dd
-
-{Cannot count rigid body degrees-of-freedom before bodies are fully initialized} :dt
-
-This means the temperature associated with the rigid bodies may be
-incorrect on this timestep. :dd
-
-{Cannot count rigid body degrees-of-freedom before bodies are initialized} :dt
-
-This means the temperature associated with the rigid bodies may be
-incorrect on this timestep. :dd
-
-{Cannot include log terms without 1/r terms; setting flagHI to 1} :dt
-
-Self-explanatory. :dd
-
-{Cannot include log terms without 1/r terms; setting flagHI to 1.} :dt
-
-Self-explanatory. :dd
-
-{Charges are set, but coulombic solver is not used} :dt
-
-Self-explanatory. :dd
-
-{Charges did not converge at step %ld: %lg} :dt
-
-Self-explanatory. :dd
-
-{Communication cutoff is too small for SNAP micro load balancing, increased to %lf} :dt
-
-Self-explanatory. :dd
-
-{Compute cna/atom cutoff may be too large to find ghost atom neighbors} :dt
-
-The neighbor cutoff used may not encompass enough ghost atoms
-to perform this operation correctly. :dd
-
-{Computing temperature of portions of rigid bodies} :dt
-
-The group defined by the temperature compute does not encompass all
-the atoms in one or more rigid bodies, so the change in
-degrees-of-freedom for the atoms in those partial rigid bodies will
-not be accounted for. :dd
-
-{Create_bonds max distance > minimum neighbor cutoff} :dt
-
-This means atom pairs for some atom types may not be in the neighbor
-list and thus no bond can be created between them. :dd
-
-{Delete_atoms cutoff > minimum neighbor cutoff} :dt
-
-This means atom pairs for some atom types may not be in the neighbor
-list and thus an atom in that pair cannot be deleted. :dd
-
-{Dihedral atoms missing at step %ld} :dt
-
-One or more of 4 atoms needed to compute a particular dihedral are
-missing on this processor.  Typically this is because the pairwise
-cutoff is set too short or the dihedral has blown apart and an atom is
-too far away. :dd
-
-{Dihedral problem} :dt
-
-Conformation of the 4 listed dihedral atoms is extreme; you may want
-to check your simulation geometry. :dd
-
-{Dihedral problem: %d %ld %d %d %d %d} :dt
-
-Conformation of the 4 listed dihedral atoms is extreme; you may want
-to check your simulation geometry. :dd
-
-{Dihedral style in data file differs from currently defined dihedral style} :dt
-
-Self-explanatory. :dd
-
-{Dump dcd/xtc timestamp may be wrong with fix dt/reset} :dt
-
-If the fix changes the timestep, the dump dcd file will not
-reflect the change. :dd
-
-{Energy due to X extra global DOFs will be included in minimizer energies} :dt
-
-When using fixes like box/relax, the potential energy used by the minimizer
-is augmented by an additional energy provided by the fix. Thus the printed
-converged energy may be different from the total potential energy. :dd
-
-{Energy tally does not account for 'zero yes'} :dt
-
-The energy removed by using the 'zero yes' flag is not accounted
-for in the energy tally and thus energy conservation cannot be
-monitored in this case. :dd
-
-{Estimated error in splitting of dispersion coeffs is %g} :dt
-
-Error is greater than 0.0001 percent. :dd
-
-{Ewald/disp Newton solver failed, using old method to estimate g_ewald} :dt
-
-Self-explanatory. Choosing a different cutoff value may help. :dd
-
-{FENE bond too long} :dt
-
-A FENE bond has stretched dangerously far.  It's interaction strength
-will be truncated to attempt to prevent the bond from blowing up. :dd
-
-{FENE bond too long: %ld %d %d %g} :dt
-
-A FENE bond has stretched dangerously far.  It's interaction strength
-will be truncated to attempt to prevent the bond from blowing up. :dd
-
-{FENE bond too long: %ld %g} :dt
-
-A FENE bond has stretched dangerously far.  It's interaction strength
-will be truncated to attempt to prevent the bond from blowing up. :dd
-
-{Fix SRD walls overlap but fix srd overlap not set} :dt
-
-You likely want to set this in your input script. :dd
-
-{Fix bond/swap will ignore defined angles} :dt
-
-See the doc page for fix bond/swap for more info on this
-restriction. :dd
-
-{Fix deposit near setting < possible overlap separation %g} :dt
-
-This test is performed for finite size particles with a diameter, not
-for point particles.  The near setting is smaller than the particle
-diameter which can lead to overlaps. :dd
-
-{Fix evaporate may delete atom with non-zero molecule ID} :dt
-
-This is probably an error, since you should not delete only one atom
-of a molecule. :dd
-
-{Fix gcmc using full_energy option} :dt
-
-Fix gcmc has automatically turned on the full_energy option since it
-is required for systems like the one specified by the user. User input
-included one or more of the following: kspace, triclinic, a hybrid
-pair style, an eam pair style, or no "single" function for the pair
-style. :dd
-
-{Fix property/atom mol or charge w/out ghost communication} :dt
-
-A model typically needs these properties defined for ghost atoms. :dd
-
-{Fix qeq CG convergence failed (%g) after %d iterations at %ld step} :dt
-
-Self-explanatory. :dd
-
-{Fix qeq has non-zero lower Taper radius cutoff} :dt
-
-Absolute value must be <= 0.01. :dd
-
-{Fix qeq has very low Taper radius cutoff} :dt
-
-Value should typically be >= 5.0. :dd
-
-{Fix qeq/dynamic tolerance may be too small for damped dynamics} :dt
-
-Self-explanatory. :dd
-
-{Fix qeq/fire tolerance may be too small for damped fires} :dt
-
-Self-explanatory. :dd
-
-{Fix rattle should come after all other integration fixes} :dt
-
-This fix is designed to work after all other integration fixes change
-atom positions.  Thus it should be the last integration fix specified.
-If not, it will not satisfy the desired constraints as well as it
-otherwise would. :dd
-
-{Fix recenter should come after all other integration fixes} :dt
-
-Other fixes may change the position of the center-of-mass, so
-fix recenter should come last. :dd
-
-{Fix srd SRD moves may trigger frequent reneighboring} :dt
-
-This is because the SRD particles may move long distances. :dd
-
-{Fix srd grid size > 1/4 of big particle diameter} :dt
-
-This may cause accuracy problems. :dd
-
-{Fix srd particle moved outside valid domain} :dt
-
-This may indicate a problem with your simulation parameters. :dd
-
-{Fix srd particles may move > big particle diameter} :dt
-
-This may cause accuracy problems. :dd
-
-{Fix srd viscosity < 0.0 due to low SRD density} :dt
-
-This may cause accuracy problems. :dd
-
-{Fix thermal/conductivity comes before fix ave/spatial} :dt
-
-The order of these 2 fixes in your input script is such that fix
-thermal/conductivity comes first.  If you are using fix ave/spatial to
-measure the temperature profile induced by fix viscosity, then this
-may cause a glitch in the profile since you are averaging immediately
-after swaps have occurred.  Flipping the order of the 2 fixes
-typically helps. :dd
-
-{Fix viscosity comes before fix ave/spatial} :dt
-
-The order of these 2 fixes in your input script is such that
-fix viscosity comes first.  If you are using fix ave/spatial
-to measure the velocity profile induced by fix viscosity, then
-this may cause a glitch in the profile since you are averaging
-immediately after swaps have occurred.  Flipping the order
-of the 2 fixes typically helps. :dd
-
-{Fixes cannot send data in Kokkos communication, switching to classic communication} :dt
-
-This is current restriction with Kokkos. :dd
-
-{For better accuracy use 'pair_modify table 0'} :dt
-
-The user-specified force accuracy cannot be achieved unless the table
-feature is disabled by using 'pair_modify table 0'. :dd
-
-{Geometric mixing assumed for 1/r^6 coefficients} :dt
-
-Self-explanatory. :dd
-
-{Group for fix_modify temp != fix group} :dt
-
-The fix_modify command is specifying a temperature computation that
-computes a temperature on a different group of atoms than the fix
-itself operates on.  This is probably not what you want to do. :dd
-
-{H matrix size has been exceeded: m_fill=%d H.m=%d\n} :dt
-
-This is the size of the matrix. :dd
-
-{Ignoring unknown or incorrect info command flag} :dt
-
-Self-explanatory.  An unknown argument was given to the info command.
-Compare your input with the documentation. :dd
-
-{Improper atoms missing at step %ld} :dt
-
-One or more of 4 atoms needed to compute a particular improper are
-missing on this processor.  Typically this is because the pairwise
-cutoff is set too short or the improper has blown apart and an atom is
-too far away. :dd
-
-{Improper problem: %d %ld %d %d %d %d} :dt
-
-Conformation of the 4 listed improper atoms is extreme; you may want
-to check your simulation geometry. :dd
-
-{Improper style in data file differs from currently defined improper style} :dt
-
-Self-explanatory. :dd
-
-{Inconsistent image flags} :dt
-
-The image flags for a pair on bonded atoms appear to be inconsistent.
-Inconsistent means that when the coordinates of the two atoms are
-unwrapped using the image flags, the two atoms are far apart.
-Specifically they are further apart than half a periodic box length.
-Or they are more than a box length apart in a non-periodic dimension.
-This is usually due to the initial data file not having correct image
-flags for the 2 atoms in a bond that straddles a periodic boundary.
-They should be different by 1 in that case.  This is a warning because
-inconsistent image flags will not cause problems for dynamics or most
-LAMMPS simulations.  However they can cause problems when such atoms
-are used with the fix rigid or replicate commands.  Note that if you
-have an infinite periodic crystal with bonds then it is impossible to
-have fully consistent image flags, since some bonds will cross
-periodic boundaries and connect two atoms with the same image
-flag. :dd
-
-{KIM Model does not provide 'energy'; Potential energy will be zero} :dt
-
-Self-explanatory. :dd
-
-{KIM Model does not provide 'forces'; Forces will be zero} :dt
-
-Self-explanatory. :dd
-
-{KIM Model does not provide 'particleEnergy'; energy per atom will be zero} :dt
-
-Self-explanatory. :dd
-
-{KIM Model does not provide 'particleVirial'; virial per atom will be zero} :dt
-
-Self-explanatory. :dd
-
-{Kspace_modify slab param < 2.0 may cause unphysical behavior} :dt
-
-The kspace_modify slab parameter should be larger to insure periodic
-grids padded with empty space do not overlap. :dd
-
-{Less insertions than requested} :dt
-
-The fix pour command was unsuccessful at finding open space
-for as many particles as it tried to insert. :dd
-
-{Library error in lammps_gather_atoms} :dt
-
-This library function cannot be used if atom IDs are not defined
-or are not consecutively numbered. :dd
-
-{Library error in lammps_scatter_atoms} :dt
-
-This library function cannot be used if atom IDs are not defined or
-are not consecutively numbered, or if no atom map is defined.  See the
-atom_modify command for details about atom maps. :dd
-
-{Lost atoms via change_box: original %ld current %ld} :dt
-
-The command options you have used caused atoms to be lost. :dd
-
-{Lost atoms via displace_atoms: original %ld current %ld} :dt
-
-The command options you have used caused atoms to be lost. :dd
-
-{Lost atoms: original %ld current %ld} :dt
-
-Lost atoms are checked for each time thermo output is done.  See the
-thermo_modify lost command for options.  Lost atoms usually indicate
-bad dynamics, e.g. atoms have been blown far out of the simulation
-box, or moved further than one processor's sub-domain away before
-reneighboring. :dd
-
-{MSM mesh too small, increasing to 2 points in each direction} :dt
-
-Self-explanatory. :dd
-
-{Mismatch between velocity and compute groups} :dt
-
-The temperature computation used by the velocity command will not be
-on the same group of atoms that velocities are being set for. :dd
-
-{Mixing forced for lj coefficients} :dt
-
-Self-explanatory. :dd
-
-{Molecule attributes do not match system attributes} :dt
-
-An attribute is specified (e.g. diameter, charge) that is
-not defined for the specified atom style. :dd
-
-{Molecule has bond topology but no special bond settings} :dt
-
-This means the bonded atoms will not be excluded in pair-wise
-interactions. :dd
-
-{Molecule template for create_atoms has multiple molecules} :dt
-
-The create_atoms command will only create molecules of a single type,
-i.e. the first molecule in the template. :dd
-
-{Molecule template for fix gcmc has multiple molecules} :dt
-
-The fix gcmc command will only create molecules of a single type,
-i.e. the first molecule in the template. :dd
-
-{Molecule template for fix shake has multiple molecules} :dt
-
-The fix shake command will only recognize molecules of a single
-type, i.e. the first molecule in the template. :dd
-
-{More than one compute centro/atom} :dt
-
-It is not efficient to use compute centro/atom more than once. :dd
-
-{More than one compute cluster/atom} :dt
-
-It is not efficient to use compute cluster/atom  more than once. :dd
-
-{More than one compute cna/atom defined} :dt
-
-It is not efficient to use compute cna/atom  more than once. :dd
-
-{More than one compute contact/atom} :dt
-
-It is not efficient to use compute contact/atom more than once. :dd
-
-{More than one compute coord/atom} :dt
-
-It is not efficient to use compute coord/atom more than once. :dd
-
-{More than one compute damage/atom} :dt
-
-It is not efficient to use compute ke/atom more than once. :dd
-
-{More than one compute dilatation/atom} :dt
-
-Self-explanatory. :dd
-
-{More than one compute erotate/sphere/atom} :dt
-
-It is not efficient to use compute erorate/sphere/atom more than once. :dd
-
-{More than one compute hexorder/atom} :dt
-
-It is not efficient to use compute hexorder/atom more than once. :dd
-
-{More than one compute ke/atom} :dt
-
-It is not efficient to use compute ke/atom more than once. :dd
-
-{More than one compute orientorder/atom} :dt
-
-It is not efficient to use compute orientorder/atom more than once. :dd
-
-{More than one compute plasticity/atom} :dt
-
-Self-explanatory. :dd
-
-{More than one compute sna/atom} :dt
-
-Self-explanatory. :dd
-
-{More than one compute snad/atom} :dt
-
-Self-explanatory. :dd
-
-{More than one compute snav/atom} :dt
-
-Self-explanatory. :dd
-
-{More than one fix poems} :dt
-
-It is not efficient to use fix poems more than once. :dd
-
-{More than one fix rigid} :dt
-
-It is not efficient to use fix rigid more than once. :dd
-
-{Neighbor exclusions used with KSpace solver may give inconsistent Coulombic energies} :dt
-
-This is because excluding specific pair interactions also excludes
-them from long-range interactions which may not be the desired effect.
-The special_bonds command handles this consistently by insuring
-excluded (or weighted) 1-2, 1-3, 1-4 interactions are treated
-consistently by both the short-range pair style and the long-range
-solver.  This is not done for exclusions of charged atom pairs via the
-neigh_modify exclude command. :dd
-
-{New thermo_style command, previous thermo_modify settings will be lost} :dt
-
-If a thermo_style command is used after a thermo_modify command, the
-settings changed by the thermo_modify command will be reset to their
-default values.  This is because the thermo_modify command acts on
-the currently defined thermo style, and a thermo_style command creates
-a new style. :dd
-
-{No Kspace calculation with verlet/split} :dt
-
-The 2nd partition performs a kspace calculation so the kspace_style
-command must be used. :dd
-
-{No automatic unit conversion to XTC file format conventions possible for units lj} :dt
-
-This means no scaling will be performed. :dd
-
-{No fixes defined, atoms won't move} :dt
-
-If you are not using a fix like nve, nvt, npt then atom velocities and
-coordinates will not be updated during timestepping. :dd
-
-{No joints between rigid bodies, use fix rigid instead} :dt
-
-The bodies defined by fix poems are not connected by joints.  POEMS
-will integrate the body motion, but it would be more efficient to use
-fix rigid. :dd
-
-{Not using real units with pair reax} :dt
-
-This is most likely an error, unless you have created your own ReaxFF
-parameter file in a different set of units. :dd
-
-{Number of MSM mesh points changed to be a multiple of 2} :dt
-
-MSM requires that the number of grid points in each direction be a multiple
-of two and the number of grid points in one or more directions have been
-adjusted to meet this requirement. :dd
-
-{OMP_NUM_THREADS environment is not set.} :dt
-
-This environment variable must be set appropriately to use the
-USER-OMP package. :dd
-
-{One or more atoms are time integrated more than once} :dt
-
-This is probably an error since you typically do not want to
-advance the positions or velocities of an atom more than once
-per timestep. :dd
-
-{One or more chunks do not contain all atoms in molecule} :dt
-
-This may not be what you intended. :dd
-
-{One or more dynamic groups may not be updated at correct point in timestep} :dt
-
-If there are other fixes that act immediately after the initial stage
-of time integration within a timestep (i.e. after atoms move), then
-the command that sets up the dynamic group should appear after those
-fixes.  This will insure that dynamic group assignments are made
-after all atoms have moved. :dd
-
-{One or more respa levels compute no forces} :dt
-
-This is computationally inefficient. :dd
-
-{Pair COMB charge %.10f with force %.10f hit max barrier} :dt
-
-Something is possibly wrong with your model. :dd
-
-{Pair COMB charge %.10f with force %.10f hit min barrier} :dt
-
-Something is possibly wrong with your model. :dd
-
-{Pair brownian needs newton pair on for momentum conservation} :dt
-
-Self-explanatory. :dd
-
-{Pair dpd needs newton pair on for momentum conservation} :dt
-
-Self-explanatory. :dd
-
-{Pair dsmc: num_of_collisions > number_of_A} :dt
-
-Collision model in DSMC is breaking down. :dd
-
-{Pair dsmc: num_of_collisions > number_of_B} :dt
-
-Collision model in DSMC is breaking down. :dd
-
-{Pair style in data file differs from currently defined pair style} :dt
-
-Self-explanatory. :dd
-
-{Particle deposition was unsuccessful} :dt
-
-The fix deposit command was not able to insert as many atoms as
-needed.  The requested volume fraction may be too high, or other atoms
-may be in the insertion region. :dd
-
-{Proc sub-domain size < neighbor skin, could lead to lost atoms} :dt
-
-The decomposition of the physical domain (likely due to load
-balancing) has led to a processor's sub-domain being smaller than the
-neighbor skin in one or more dimensions.  Since reneighboring is
-triggered by atoms moving the skin distance, this may lead to lost
-atoms, if an atom moves all the way across a neighboring processor's
-sub-domain before reneighboring is triggered. :dd
-
-{Reducing PPPM order b/c stencil extends beyond nearest neighbor processor} :dt
-
-This may lead to a larger grid than desired.  See the kspace_modify overlap
-command to prevent changing of the PPPM order. :dd
-
-{Reducing PPPMDisp Coulomb order b/c stencil extends beyond neighbor processor} :dt
-
-This may lead to a larger grid than desired.  See the kspace_modify overlap
-command to prevent changing of the PPPM order. :dd
-
-{Reducing PPPMDisp dispersion order b/c stencil extends beyond neighbor processor} :dt
-
-This may lead to a larger grid than desired.  See the kspace_modify overlap
-command to prevent changing of the PPPM order. :dd
-
-{Replacing a fix, but new group != old group} :dt
-
-The ID and style of a fix match for a fix you are changing with a fix
-command, but the new group you are specifying does not match the old
-group. :dd
-
-{Replicating in a non-periodic dimension} :dt
-
-The parameters for a replicate command will cause a non-periodic
-dimension to be replicated; this may cause unwanted behavior. :dd
-
-{Resetting reneighboring criteria during PRD} :dt
-
-A PRD simulation 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 PRD simulation. :dd
-
-{Resetting reneighboring criteria during TAD} :dt
-
-A TAD simulation 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 PRD simulation. :dd
-
-{Resetting reneighboring criteria during minimization} :dt
-
-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. :dd
-
-{Restart file used different # of processors} :dt
-
-The restart file was written out by a LAMMPS simulation running on a
-different number of processors.  Due to round-off, the trajectories of
-your restarted simulation may diverge a little more quickly than if
-you ran on the same # of processors. :dd
-
-{Restart file used different 3d processor grid} :dt
-
-The restart file was written out by a LAMMPS simulation running on a
-different 3d grid of processors.  Due to round-off, the trajectories
-of your restarted simulation may diverge a little more quickly than if
-you ran on the same # of processors. :dd
-
-{Restart file used different boundary settings, using restart file values} :dt
-
-Your input script cannot change these restart file settings. :dd
-
-{Restart file used different newton bond setting, using restart file value} :dt
-
-The restart file value will override the setting in the input script. :dd
-
-{Restart file used different newton pair setting, using input script value} :dt
-
-The input script value will override the setting in the restart file. :dd
-
-{Restrain problem: %d %ld %d %d %d %d} :dt
-
-Conformation of the 4 listed dihedral atoms is extreme; you may want
-to check your simulation geometry. :dd
-
-{Running PRD with only one replica} :dt
-
-This is allowed, but you will get no parallel speed-up. :dd
-
-{SRD bin shifting turned on due to small lamda} :dt
-
-This is done to try to preserve accuracy. :dd
-
-{SRD bin size for fix srd differs from user request} :dt
-
-Fix SRD had to adjust the bin size to fit the simulation box.  See the
-cubic keyword if you want this message to be an error vs warning. :dd
-
-{SRD bins for fix srd are not cubic enough} :dt
-
-The bin shape is not within tolerance of cubic.  See the cubic
-keyword if you want this message to be an error vs warning. :dd
-
-{SRD particle %d started inside big particle %d on step %ld bounce %d} :dt
-
-See the inside keyword if you want this message to be an error vs
-warning. :dd
-
-{SRD particle %d started inside wall %d on step %ld bounce %d} :dt
-
-See the inside keyword if you want this message to be an error vs
-warning. :dd
-
-{Shake determinant < 0.0} :dt
-
-The determinant of the quadratic equation being solved for a single
-cluster specified by the fix shake command is numerically suspect.  LAMMPS
-will set it to 0.0 and continue. :dd
-
-{Shell command '%s' failed with error '%s'} :dt
-
-Self-explanatory. :dd
-
-{Shell command returned with non-zero status} :dt
-
-This may indicate the shell command did not operate as expected. :dd
-
-{Should not allow rigid bodies to bounce off relecting walls} :dt
-
-LAMMPS allows this, but their dynamics are not computed correctly. :dd
-
-{Should not use fix nve/limit with fix shake or fix rattle} :dt
-
-This will lead to invalid constraint forces in the SHAKE/RATTLE
-computation. :dd
-
-{Simulations might be very slow because of large number of structure factors} :dt
-
-Self-explanatory. :dd
-
-{Slab correction not needed for MSM} :dt
-
-Slab correction is intended to be used with Ewald or PPPM and is not needed by MSM. :dd
-
-{System is not charge neutral, net charge = %g} :dt
-
-The total charge on all atoms on the system is not 0.0.
-For some KSpace solvers this is only a warning. :dd
-
-{Table inner cutoff >= outer cutoff} :dt
-
-You specified an inner cutoff for a Coulombic table that is longer
-than the global cutoff.  Probably not what you wanted. :dd
-
-{Temperature for MSST is not for group all} :dt
-
-User-assigned temperature to MSST fix does not compute temperature for
-all atoms.  Since MSST computes a global pressure, the kinetic energy
-contribution from the temperature is assumed to also be for all atoms.
-Thus the pressure used by MSST could be inaccurate. :dd
-
-{Temperature for NPT is not for group all} :dt
-
-User-assigned temperature to NPT fix does not compute temperature for
-all atoms.  Since NPT computes a global pressure, the kinetic energy
-contribution from the temperature is assumed to also be for all atoms.
-Thus the pressure used by NPT could be inaccurate. :dd
-
-{Temperature for fix modify is not for group all} :dt
-
-The temperature compute is being used with a pressure calculation
-which does operate on group all, so this may be inconsistent. :dd
-
-{Temperature for thermo pressure is not for group all} :dt
-
-User-assigned temperature to thermo via the thermo_modify command does
-not compute temperature for all atoms.  Since thermo computes a global
-pressure, the kinetic energy contribution from the temperature is
-assumed to also be for all atoms.  Thus the pressure printed by thermo
-could be inaccurate. :dd
-
-{The fix ave/spatial command has been replaced by the more flexible fix ave/chunk and compute chunk/atom commands -- fix ave/spatial will be removed in the summer of 2015} :dt
-
-Self-explanatory. :dd
-
-{The minimizer does not re-orient dipoles when using fix efield} :dt
-
-This means that only the atom coordinates will be minimized,
-not the orientation of the dipoles. :dd
-
-{Too many common neighbors in CNA %d times} :dt
-
-More than the maximum # of neighbors was found multiple times.  This
-was unexpected. :dd
-
-{Too many inner timesteps in fix ttm} :dt
-
-Self-explanatory. :dd
-
-{Too many neighbors in CNA for %d atoms} :dt
-
-More than the maximum # of neighbors was found multiple times.  This
-was unexpected. :dd
-
-{Triclinic box skew is large} :dt
-
-The displacement in a skewed direction is normally required to be less
-than half the box length in that dimension.  E.g. the xy tilt must be
-between -half and +half of the x box length.  You have relaxed the
-constraint using the box tilt command, but the warning means that a
-LAMMPS simulation may be inefficient as a result. :dd
-
-{Use special bonds = 0,1,1 with bond style fene} :dt
-
-Most FENE models need this setting for the special_bonds command. :dd
-
-{Use special bonds = 0,1,1 with bond style fene/expand} :dt
-
-Most FENE models need this setting for the special_bonds command. :dd
-
-{Using a manybody potential with bonds/angles/dihedrals and special_bond exclusions} :dt
-
-This is likely not what you want to do.  The exclusion settings will
-eliminate neighbors in the neighbor list, which the manybody potential
-needs to calculated its terms correctly. :dd
-
-{Using compute temp/deform with inconsistent fix deform remap option} :dt
-
-Fix nvt/sllod assumes deforming atoms have a velocity profile provided
-by "remap v" or "remap none" as a fix deform option. :dd
-
-{Using compute temp/deform with no fix deform defined} :dt
-
-This is probably an error, since it makes little sense to use
-compute temp/deform in this case. :dd
-
-{Using fix srd with box deformation but no SRD thermostat} :dt
-
-The deformation will heat the SRD particles so this can
-be dangerous. :dd
-
-{Using kspace solver on system with no charge} :dt
-
-Self-explanatory. :dd
-
-{Using largest cut-off for lj/long/dipole/long long long} :dt
-
-Self-explanatory. :dd
-
-{Using largest cutoff for buck/long/coul/long} :dt
-
-Self-explanatory. :dd
-
-{Using largest cutoff for lj/long/coul/long} :dt
-
-Self-explanatory. :dd
-
-{Using largest cutoff for pair_style lj/long/tip4p/long} :dt
-
-Self-explanatory. :dd
-
-{Using package gpu without any pair style defined} :dt
-
-Self-explanatory. :dd
-
-{Using pair potential shift with pair_modify compute no} :dt
-
-The shift effects will thus not be computed. :dd
-
-{Using pair tail corrections with nonperiodic system} :dt
-
-This is probably a bogus thing to do, since tail corrections are
-computed by integrating the density of a periodic system out to
-infinity. :dd
-
-{Using pair tail corrections with pair_modify compute no} :dt
-
-The tail corrections will thus not be computed. :dd
-
-{pair style reax is now deprecated and will soon be retired. Users should switch to pair_style reax/c} :dt
-
-Self-explanatory. :dd
-
-:dle
-
diff --git a/doc/src/Errors_warnings.txt b/doc/src/Errors_warnings.txt
new file mode 100644
index 0000000000000000000000000000000000000000..0324f563b6870e8636f15d5cc9a9486b8b7ad334
--- /dev/null
+++ b/doc/src/Errors_warnings.txt
@@ -0,0 +1,934 @@
+"Higher level section"_Errors.html - "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
+
+Warning messages :h3
+
+This is an alphabetic list of the WARNING messages LAMMPS prints out
+and the reason why.  If the explanation here is not sufficient, the
+documentation for the offending command may help.  Warning messages
+also list the source file and line number where the warning was
+generated.  For example, a message lile this:
+
+WARNING: Bond atom missing in box size check (domain.cpp:187) :pre
+
+means that line #187 in the file src/domain.cpp generated the error.
+Looking in the source code may help you figure out what went wrong.
+
+Note that warning messages from "user-contributed
+packages"_Section_start.html#table_user are not listed here.  If such
+a warning occurs and is not self-explanatory, you'll need to look in
+the source code or contact the author of the package.
+
+Doc page with "ERROR messages"_Errors_messages.html
+
+:line
+
+:dlb
+
+{Adjusting Coulombic cutoff for MSM, new cutoff = %g} :dt
+
+The adjust/cutoff command is turned on and the Coulombic cutoff has been
+adjusted to match the user-specified accuracy. :dd
+
+{Angle atoms missing at step %ld} :dt
+
+One or more of 3 atoms needed to compute a particular angle are
+missing on this processor.  Typically this is because the pairwise
+cutoff is set too short or the angle has blown apart and an atom is
+too far away. :dd
+
+{Angle style in data file differs from currently defined angle style} :dt
+
+Self-explanatory. :dd
+
+{Atom style in data file differs from currently defined atom style} :dt
+
+Self-explanatory. :dd
+
+{Bond atom missing in box size check} :dt
+
+The 2nd atoms needed to compute a particular bond is missing on this
+processor.  Typically this is because the pairwise cutoff is set too
+short or the bond has blown apart and an atom is too far away. :dd
+
+{Bond atom missing in image check} :dt
+
+The 2nd atom in a particular bond is missing on this processor.
+Typically this is because the pairwise cutoff is set too short or the
+bond has blown apart and an atom is too far away. :dd
+
+{Bond atoms missing at step %ld} :dt
+
+The 2nd atom needed to compute a particular bond is missing on this
+processor.  Typically this is because the pairwise cutoff is set too
+short or the bond has blown apart and an atom is too far away. :dd
+
+{Bond style in data file differs from currently defined bond style} :dt
+
+Self-explanatory. :dd
+
+{Bond/angle/dihedral extent > half of periodic box length} :dt
+
+This is a restriction because LAMMPS can be confused about which image
+of an atom in the bonded interaction is the correct one to use.
+"Extent" in this context means the maximum end-to-end length of the
+bond/angle/dihedral.  LAMMPS computes this by taking the maximum bond
+length, multiplying by the number of bonds in the interaction (e.g. 3
+for a dihedral) and adding a small amount of stretch. :dd
+
+{Both groups in compute group/group have a net charge; the Kspace boundary correction to energy will be non-zero} :dt
+
+Self-explanatory. :dd
+
+{Calling write_dump before a full system init.} :dt
+
+The write_dump command is used before the system has been fully
+initialized as part of a 'run' or 'minimize' command. Not all dump
+styles and features are fully supported at this point and thus the
+command may fail or produce incomplete or incorrect output. Insert
+a "run 0" command, if a full system init is required. :dd
+
+{Cannot count rigid body degrees-of-freedom before bodies are fully initialized} :dt
+
+This means the temperature associated with the rigid bodies may be
+incorrect on this timestep. :dd
+
+{Cannot count rigid body degrees-of-freedom before bodies are initialized} :dt
+
+This means the temperature associated with the rigid bodies may be
+incorrect on this timestep. :dd
+
+{Cannot include log terms without 1/r terms; setting flagHI to 1} :dt
+
+Self-explanatory. :dd
+
+{Cannot include log terms without 1/r terms; setting flagHI to 1.} :dt
+
+Self-explanatory. :dd
+
+{Charges are set, but coulombic solver is not used} :dt
+
+Self-explanatory. :dd
+
+{Charges did not converge at step %ld: %lg} :dt
+
+Self-explanatory. :dd
+
+{Communication cutoff is too small for SNAP micro load balancing, increased to %lf} :dt
+
+Self-explanatory. :dd
+
+{Compute cna/atom cutoff may be too large to find ghost atom neighbors} :dt
+
+The neighbor cutoff used may not encompass enough ghost atoms
+to perform this operation correctly. :dd
+
+{Computing temperature of portions of rigid bodies} :dt
+
+The group defined by the temperature compute does not encompass all
+the atoms in one or more rigid bodies, so the change in
+degrees-of-freedom for the atoms in those partial rigid bodies will
+not be accounted for. :dd
+
+{Create_bonds max distance > minimum neighbor cutoff} :dt
+
+This means atom pairs for some atom types may not be in the neighbor
+list and thus no bond can be created between them. :dd
+
+{Delete_atoms cutoff > minimum neighbor cutoff} :dt
+
+This means atom pairs for some atom types may not be in the neighbor
+list and thus an atom in that pair cannot be deleted. :dd
+
+{Dihedral atoms missing at step %ld} :dt
+
+One or more of 4 atoms needed to compute a particular dihedral are
+missing on this processor.  Typically this is because the pairwise
+cutoff is set too short or the dihedral has blown apart and an atom is
+too far away. :dd
+
+{Dihedral problem} :dt
+
+Conformation of the 4 listed dihedral atoms is extreme; you may want
+to check your simulation geometry. :dd
+
+{Dihedral problem: %d %ld %d %d %d %d} :dt
+
+Conformation of the 4 listed dihedral atoms is extreme; you may want
+to check your simulation geometry. :dd
+
+{Dihedral style in data file differs from currently defined dihedral style} :dt
+
+Self-explanatory. :dd
+
+{Dump dcd/xtc timestamp may be wrong with fix dt/reset} :dt
+
+If the fix changes the timestep, the dump dcd file will not
+reflect the change. :dd
+
+{Energy due to X extra global DOFs will be included in minimizer energies} :dt
+
+When using fixes like box/relax, the potential energy used by the minimizer
+is augmented by an additional energy provided by the fix. Thus the printed
+converged energy may be different from the total potential energy. :dd
+
+{Energy tally does not account for 'zero yes'} :dt
+
+The energy removed by using the 'zero yes' flag is not accounted
+for in the energy tally and thus energy conservation cannot be
+monitored in this case. :dd
+
+{Estimated error in splitting of dispersion coeffs is %g} :dt
+
+Error is greater than 0.0001 percent. :dd
+
+{Ewald/disp Newton solver failed, using old method to estimate g_ewald} :dt
+
+Self-explanatory. Choosing a different cutoff value may help. :dd
+
+{FENE bond too long} :dt
+
+A FENE bond has stretched dangerously far.  It's interaction strength
+will be truncated to attempt to prevent the bond from blowing up. :dd
+
+{FENE bond too long: %ld %d %d %g} :dt
+
+A FENE bond has stretched dangerously far.  It's interaction strength
+will be truncated to attempt to prevent the bond from blowing up. :dd
+
+{FENE bond too long: %ld %g} :dt
+
+A FENE bond has stretched dangerously far.  It's interaction strength
+will be truncated to attempt to prevent the bond from blowing up. :dd
+
+{Fix SRD walls overlap but fix srd overlap not set} :dt
+
+You likely want to set this in your input script. :dd
+
+{Fix bond/swap will ignore defined angles} :dt
+
+See the doc page for fix bond/swap for more info on this
+restriction. :dd
+
+{Fix deposit near setting < possible overlap separation %g} :dt
+
+This test is performed for finite size particles with a diameter, not
+for point particles.  The near setting is smaller than the particle
+diameter which can lead to overlaps. :dd
+
+{Fix evaporate may delete atom with non-zero molecule ID} :dt
+
+This is probably an error, since you should not delete only one atom
+of a molecule. :dd
+
+{Fix gcmc using full_energy option} :dt
+
+Fix gcmc has automatically turned on the full_energy option since it
+is required for systems like the one specified by the user. User input
+included one or more of the following: kspace, triclinic, a hybrid
+pair style, an eam pair style, or no "single" function for the pair
+style. :dd
+
+{Fix property/atom mol or charge w/out ghost communication} :dt
+
+A model typically needs these properties defined for ghost atoms. :dd
+
+{Fix qeq CG convergence failed (%g) after %d iterations at %ld step} :dt
+
+Self-explanatory. :dd
+
+{Fix qeq has non-zero lower Taper radius cutoff} :dt
+
+Absolute value must be <= 0.01. :dd
+
+{Fix qeq has very low Taper radius cutoff} :dt
+
+Value should typically be >= 5.0. :dd
+
+{Fix qeq/dynamic tolerance may be too small for damped dynamics} :dt
+
+Self-explanatory. :dd
+
+{Fix qeq/fire tolerance may be too small for damped fires} :dt
+
+Self-explanatory. :dd
+
+{Fix rattle should come after all other integration fixes} :dt
+
+This fix is designed to work after all other integration fixes change
+atom positions.  Thus it should be the last integration fix specified.
+If not, it will not satisfy the desired constraints as well as it
+otherwise would. :dd
+
+{Fix recenter should come after all other integration fixes} :dt
+
+Other fixes may change the position of the center-of-mass, so
+fix recenter should come last. :dd
+
+{Fix srd SRD moves may trigger frequent reneighboring} :dt
+
+This is because the SRD particles may move long distances. :dd
+
+{Fix srd grid size > 1/4 of big particle diameter} :dt
+
+This may cause accuracy problems. :dd
+
+{Fix srd particle moved outside valid domain} :dt
+
+This may indicate a problem with your simulation parameters. :dd
+
+{Fix srd particles may move > big particle diameter} :dt
+
+This may cause accuracy problems. :dd
+
+{Fix srd viscosity < 0.0 due to low SRD density} :dt
+
+This may cause accuracy problems. :dd
+
+{Fix thermal/conductivity comes before fix ave/spatial} :dt
+
+The order of these 2 fixes in your input script is such that fix
+thermal/conductivity comes first.  If you are using fix ave/spatial to
+measure the temperature profile induced by fix viscosity, then this
+may cause a glitch in the profile since you are averaging immediately
+after swaps have occurred.  Flipping the order of the 2 fixes
+typically helps. :dd
+
+{Fix viscosity comes before fix ave/spatial} :dt
+
+The order of these 2 fixes in your input script is such that
+fix viscosity comes first.  If you are using fix ave/spatial
+to measure the velocity profile induced by fix viscosity, then
+this may cause a glitch in the profile since you are averaging
+immediately after swaps have occurred.  Flipping the order
+of the 2 fixes typically helps. :dd
+
+{Fixes cannot send data in Kokkos communication, switching to classic communication} :dt
+
+This is current restriction with Kokkos. :dd
+
+{For better accuracy use 'pair_modify table 0'} :dt
+
+The user-specified force accuracy cannot be achieved unless the table
+feature is disabled by using 'pair_modify table 0'. :dd
+
+{Geometric mixing assumed for 1/r^6 coefficients} :dt
+
+Self-explanatory. :dd
+
+{Group for fix_modify temp != fix group} :dt
+
+The fix_modify command is specifying a temperature computation that
+computes a temperature on a different group of atoms than the fix
+itself operates on.  This is probably not what you want to do. :dd
+
+{H matrix size has been exceeded: m_fill=%d H.m=%d\n} :dt
+
+This is the size of the matrix. :dd
+
+{Ignoring unknown or incorrect info command flag} :dt
+
+Self-explanatory.  An unknown argument was given to the info command.
+Compare your input with the documentation. :dd
+
+{Improper atoms missing at step %ld} :dt
+
+One or more of 4 atoms needed to compute a particular improper are
+missing on this processor.  Typically this is because the pairwise
+cutoff is set too short or the improper has blown apart and an atom is
+too far away. :dd
+
+{Improper problem: %d %ld %d %d %d %d} :dt
+
+Conformation of the 4 listed improper atoms is extreme; you may want
+to check your simulation geometry. :dd
+
+{Improper style in data file differs from currently defined improper style} :dt
+
+Self-explanatory. :dd
+
+{Inconsistent image flags} :dt
+
+The image flags for a pair on bonded atoms appear to be inconsistent.
+Inconsistent means that when the coordinates of the two atoms are
+unwrapped using the image flags, the two atoms are far apart.
+Specifically they are further apart than half a periodic box length.
+Or they are more than a box length apart in a non-periodic dimension.
+This is usually due to the initial data file not having correct image
+flags for the 2 atoms in a bond that straddles a periodic boundary.
+They should be different by 1 in that case.  This is a warning because
+inconsistent image flags will not cause problems for dynamics or most
+LAMMPS simulations.  However they can cause problems when such atoms
+are used with the fix rigid or replicate commands.  Note that if you
+have an infinite periodic crystal with bonds then it is impossible to
+have fully consistent image flags, since some bonds will cross
+periodic boundaries and connect two atoms with the same image
+flag. :dd
+
+{KIM Model does not provide 'energy'; Potential energy will be zero} :dt
+
+Self-explanatory. :dd
+
+{KIM Model does not provide 'forces'; Forces will be zero} :dt
+
+Self-explanatory. :dd
+
+{KIM Model does not provide 'particleEnergy'; energy per atom will be zero} :dt
+
+Self-explanatory. :dd
+
+{KIM Model does not provide 'particleVirial'; virial per atom will be zero} :dt
+
+Self-explanatory. :dd
+
+{Kspace_modify slab param < 2.0 may cause unphysical behavior} :dt
+
+The kspace_modify slab parameter should be larger to insure periodic
+grids padded with empty space do not overlap. :dd
+
+{Less insertions than requested} :dt
+
+The fix pour command was unsuccessful at finding open space
+for as many particles as it tried to insert. :dd
+
+{Library error in lammps_gather_atoms} :dt
+
+This library function cannot be used if atom IDs are not defined
+or are not consecutively numbered. :dd
+
+{Library error in lammps_scatter_atoms} :dt
+
+This library function cannot be used if atom IDs are not defined or
+are not consecutively numbered, or if no atom map is defined.  See the
+atom_modify command for details about atom maps. :dd
+
+{Lost atoms via change_box: original %ld current %ld} :dt
+
+The command options you have used caused atoms to be lost. :dd
+
+{Lost atoms via displace_atoms: original %ld current %ld} :dt
+
+The command options you have used caused atoms to be lost. :dd
+
+{Lost atoms: original %ld current %ld} :dt
+
+Lost atoms are checked for each time thermo output is done.  See the
+thermo_modify lost command for options.  Lost atoms usually indicate
+bad dynamics, e.g. atoms have been blown far out of the simulation
+box, or moved further than one processor's sub-domain away before
+reneighboring. :dd
+
+{MSM mesh too small, increasing to 2 points in each direction} :dt
+
+Self-explanatory. :dd
+
+{Mismatch between velocity and compute groups} :dt
+
+The temperature computation used by the velocity command will not be
+on the same group of atoms that velocities are being set for. :dd
+
+{Mixing forced for lj coefficients} :dt
+
+Self-explanatory. :dd
+
+{Molecule attributes do not match system attributes} :dt
+
+An attribute is specified (e.g. diameter, charge) that is
+not defined for the specified atom style. :dd
+
+{Molecule has bond topology but no special bond settings} :dt
+
+This means the bonded atoms will not be excluded in pair-wise
+interactions. :dd
+
+{Molecule template for create_atoms has multiple molecules} :dt
+
+The create_atoms command will only create molecules of a single type,
+i.e. the first molecule in the template. :dd
+
+{Molecule template for fix gcmc has multiple molecules} :dt
+
+The fix gcmc command will only create molecules of a single type,
+i.e. the first molecule in the template. :dd
+
+{Molecule template for fix shake has multiple molecules} :dt
+
+The fix shake command will only recognize molecules of a single
+type, i.e. the first molecule in the template. :dd
+
+{More than one compute centro/atom} :dt
+
+It is not efficient to use compute centro/atom more than once. :dd
+
+{More than one compute cluster/atom} :dt
+
+It is not efficient to use compute cluster/atom  more than once. :dd
+
+{More than one compute cna/atom defined} :dt
+
+It is not efficient to use compute cna/atom  more than once. :dd
+
+{More than one compute contact/atom} :dt
+
+It is not efficient to use compute contact/atom more than once. :dd
+
+{More than one compute coord/atom} :dt
+
+It is not efficient to use compute coord/atom more than once. :dd
+
+{More than one compute damage/atom} :dt
+
+It is not efficient to use compute ke/atom more than once. :dd
+
+{More than one compute dilatation/atom} :dt
+
+Self-explanatory. :dd
+
+{More than one compute erotate/sphere/atom} :dt
+
+It is not efficient to use compute erorate/sphere/atom more than once. :dd
+
+{More than one compute hexorder/atom} :dt
+
+It is not efficient to use compute hexorder/atom more than once. :dd
+
+{More than one compute ke/atom} :dt
+
+It is not efficient to use compute ke/atom more than once. :dd
+
+{More than one compute orientorder/atom} :dt
+
+It is not efficient to use compute orientorder/atom more than once. :dd
+
+{More than one compute plasticity/atom} :dt
+
+Self-explanatory. :dd
+
+{More than one compute sna/atom} :dt
+
+Self-explanatory. :dd
+
+{More than one compute snad/atom} :dt
+
+Self-explanatory. :dd
+
+{More than one compute snav/atom} :dt
+
+Self-explanatory. :dd
+
+{More than one fix poems} :dt
+
+It is not efficient to use fix poems more than once. :dd
+
+{More than one fix rigid} :dt
+
+It is not efficient to use fix rigid more than once. :dd
+
+{Neighbor exclusions used with KSpace solver may give inconsistent Coulombic energies} :dt
+
+This is because excluding specific pair interactions also excludes
+them from long-range interactions which may not be the desired effect.
+The special_bonds command handles this consistently by insuring
+excluded (or weighted) 1-2, 1-3, 1-4 interactions are treated
+consistently by both the short-range pair style and the long-range
+solver.  This is not done for exclusions of charged atom pairs via the
+neigh_modify exclude command. :dd
+
+{New thermo_style command, previous thermo_modify settings will be lost} :dt
+
+If a thermo_style command is used after a thermo_modify command, the
+settings changed by the thermo_modify command will be reset to their
+default values.  This is because the thermo_modify command acts on
+the currently defined thermo style, and a thermo_style command creates
+a new style. :dd
+
+{No Kspace calculation with verlet/split} :dt
+
+The 2nd partition performs a kspace calculation so the kspace_style
+command must be used. :dd
+
+{No automatic unit conversion to XTC file format conventions possible for units lj} :dt
+
+This means no scaling will be performed. :dd
+
+{No fixes defined, atoms won't move} :dt
+
+If you are not using a fix like nve, nvt, npt then atom velocities and
+coordinates will not be updated during timestepping. :dd
+
+{No joints between rigid bodies, use fix rigid instead} :dt
+
+The bodies defined by fix poems are not connected by joints.  POEMS
+will integrate the body motion, but it would be more efficient to use
+fix rigid. :dd
+
+{Not using real units with pair reax} :dt
+
+This is most likely an error, unless you have created your own ReaxFF
+parameter file in a different set of units. :dd
+
+{Number of MSM mesh points changed to be a multiple of 2} :dt
+
+MSM requires that the number of grid points in each direction be a multiple
+of two and the number of grid points in one or more directions have been
+adjusted to meet this requirement. :dd
+
+{OMP_NUM_THREADS environment is not set.} :dt
+
+This environment variable must be set appropriately to use the
+USER-OMP package. :dd
+
+{One or more atoms are time integrated more than once} :dt
+
+This is probably an error since you typically do not want to
+advance the positions or velocities of an atom more than once
+per timestep. :dd
+
+{One or more chunks do not contain all atoms in molecule} :dt
+
+This may not be what you intended. :dd
+
+{One or more dynamic groups may not be updated at correct point in timestep} :dt
+
+If there are other fixes that act immediately after the initial stage
+of time integration within a timestep (i.e. after atoms move), then
+the command that sets up the dynamic group should appear after those
+fixes.  This will insure that dynamic group assignments are made
+after all atoms have moved. :dd
+
+{One or more respa levels compute no forces} :dt
+
+This is computationally inefficient. :dd
+
+{Pair COMB charge %.10f with force %.10f hit max barrier} :dt
+
+Something is possibly wrong with your model. :dd
+
+{Pair COMB charge %.10f with force %.10f hit min barrier} :dt
+
+Something is possibly wrong with your model. :dd
+
+{Pair brownian needs newton pair on for momentum conservation} :dt
+
+Self-explanatory. :dd
+
+{Pair dpd needs newton pair on for momentum conservation} :dt
+
+Self-explanatory. :dd
+
+{Pair dsmc: num_of_collisions > number_of_A} :dt
+
+Collision model in DSMC is breaking down. :dd
+
+{Pair dsmc: num_of_collisions > number_of_B} :dt
+
+Collision model in DSMC is breaking down. :dd
+
+{Pair style in data file differs from currently defined pair style} :dt
+
+Self-explanatory. :dd
+
+{Pair style restartinfo set but has no restart support} :dt
+
+This pair style has a bug, where it does not support reading and
+writing information to a restart file, but does not set the member
+variable "restartinfo" to 0 as required in that case. :dd
+
+{Particle deposition was unsuccessful} :dt
+
+The fix deposit command was not able to insert as many atoms as
+needed.  The requested volume fraction may be too high, or other atoms
+may be in the insertion region. :dd
+
+{Proc sub-domain size < neighbor skin, could lead to lost atoms} :dt
+
+The decomposition of the physical domain (likely due to load
+balancing) has led to a processor's sub-domain being smaller than the
+neighbor skin in one or more dimensions.  Since reneighboring is
+triggered by atoms moving the skin distance, this may lead to lost
+atoms, if an atom moves all the way across a neighboring processor's
+sub-domain before reneighboring is triggered. :dd
+
+{Reducing PPPM order b/c stencil extends beyond nearest neighbor processor} :dt
+
+This may lead to a larger grid than desired.  See the kspace_modify overlap
+command to prevent changing of the PPPM order. :dd
+
+{Reducing PPPMDisp Coulomb order b/c stencil extends beyond neighbor processor} :dt
+
+This may lead to a larger grid than desired.  See the kspace_modify overlap
+command to prevent changing of the PPPM order. :dd
+
+{Reducing PPPMDisp dispersion order b/c stencil extends beyond neighbor processor} :dt
+
+This may lead to a larger grid than desired.  See the kspace_modify overlap
+command to prevent changing of the PPPM order. :dd
+
+{Replacing a fix, but new group != old group} :dt
+
+The ID and style of a fix match for a fix you are changing with a fix
+command, but the new group you are specifying does not match the old
+group. :dd
+
+{Replicating in a non-periodic dimension} :dt
+
+The parameters for a replicate command will cause a non-periodic
+dimension to be replicated; this may cause unwanted behavior. :dd
+
+{Resetting reneighboring criteria during PRD} :dt
+
+A PRD simulation 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 PRD simulation. :dd
+
+{Resetting reneighboring criteria during TAD} :dt
+
+A TAD simulation 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 PRD simulation. :dd
+
+{Resetting reneighboring criteria during minimization} :dt
+
+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. :dd
+
+{Restart file used different # of processors} :dt
+
+The restart file was written out by a LAMMPS simulation running on a
+different number of processors.  Due to round-off, the trajectories of
+your restarted simulation may diverge a little more quickly than if
+you ran on the same # of processors. :dd
+
+{Restart file used different 3d processor grid} :dt
+
+The restart file was written out by a LAMMPS simulation running on a
+different 3d grid of processors.  Due to round-off, the trajectories
+of your restarted simulation may diverge a little more quickly than if
+you ran on the same # of processors. :dd
+
+{Restart file used different boundary settings, using restart file values} :dt
+
+Your input script cannot change these restart file settings. :dd
+
+{Restart file used different newton bond setting, using restart file value} :dt
+
+The restart file value will override the setting in the input script. :dd
+
+{Restart file used different newton pair setting, using input script value} :dt
+
+The input script value will override the setting in the restart file. :dd
+
+{Restrain problem: %d %ld %d %d %d %d} :dt
+
+Conformation of the 4 listed dihedral atoms is extreme; you may want
+to check your simulation geometry. :dd
+
+{Running PRD with only one replica} :dt
+
+This is allowed, but you will get no parallel speed-up. :dd
+
+{SRD bin shifting turned on due to small lamda} :dt
+
+This is done to try to preserve accuracy. :dd
+
+{SRD bin size for fix srd differs from user request} :dt
+
+Fix SRD had to adjust the bin size to fit the simulation box.  See the
+cubic keyword if you want this message to be an error vs warning. :dd
+
+{SRD bins for fix srd are not cubic enough} :dt
+
+The bin shape is not within tolerance of cubic.  See the cubic
+keyword if you want this message to be an error vs warning. :dd
+
+{SRD particle %d started inside big particle %d on step %ld bounce %d} :dt
+
+See the inside keyword if you want this message to be an error vs
+warning. :dd
+
+{SRD particle %d started inside wall %d on step %ld bounce %d} :dt
+
+See the inside keyword if you want this message to be an error vs
+warning. :dd
+
+{Shake determinant < 0.0} :dt
+
+The determinant of the quadratic equation being solved for a single
+cluster specified by the fix shake command is numerically suspect.  LAMMPS
+will set it to 0.0 and continue. :dd
+
+{Shell command '%s' failed with error '%s'} :dt
+
+Self-explanatory. :dd
+
+{Shell command returned with non-zero status} :dt
+
+This may indicate the shell command did not operate as expected. :dd
+
+{Should not allow rigid bodies to bounce off relecting walls} :dt
+
+LAMMPS allows this, but their dynamics are not computed correctly. :dd
+
+{Should not use fix nve/limit with fix shake or fix rattle} :dt
+
+This will lead to invalid constraint forces in the SHAKE/RATTLE
+computation. :dd
+
+{Simulations might be very slow because of large number of structure factors} :dt
+
+Self-explanatory. :dd
+
+{Slab correction not needed for MSM} :dt
+
+Slab correction is intended to be used with Ewald or PPPM and is not needed by MSM. :dd
+
+{System is not charge neutral, net charge = %g} :dt
+
+The total charge on all atoms on the system is not 0.0.
+For some KSpace solvers this is only a warning. :dd
+
+{Table inner cutoff >= outer cutoff} :dt
+
+You specified an inner cutoff for a Coulombic table that is longer
+than the global cutoff.  Probably not what you wanted. :dd
+
+{Temperature for MSST is not for group all} :dt
+
+User-assigned temperature to MSST fix does not compute temperature for
+all atoms.  Since MSST computes a global pressure, the kinetic energy
+contribution from the temperature is assumed to also be for all atoms.
+Thus the pressure used by MSST could be inaccurate. :dd
+
+{Temperature for NPT is not for group all} :dt
+
+User-assigned temperature to NPT fix does not compute temperature for
+all atoms.  Since NPT computes a global pressure, the kinetic energy
+contribution from the temperature is assumed to also be for all atoms.
+Thus the pressure used by NPT could be inaccurate. :dd
+
+{Temperature for fix modify is not for group all} :dt
+
+The temperature compute is being used with a pressure calculation
+which does operate on group all, so this may be inconsistent. :dd
+
+{Temperature for thermo pressure is not for group all} :dt
+
+User-assigned temperature to thermo via the thermo_modify command does
+not compute temperature for all atoms.  Since thermo computes a global
+pressure, the kinetic energy contribution from the temperature is
+assumed to also be for all atoms.  Thus the pressure printed by thermo
+could be inaccurate. :dd
+
+{The fix ave/spatial command has been replaced by the more flexible fix ave/chunk and compute chunk/atom commands -- fix ave/spatial will be removed in the summer of 2015} :dt
+
+Self-explanatory. :dd
+
+{The minimizer does not re-orient dipoles when using fix efield} :dt
+
+This means that only the atom coordinates will be minimized,
+not the orientation of the dipoles. :dd
+
+{Too many common neighbors in CNA %d times} :dt
+
+More than the maximum # of neighbors was found multiple times.  This
+was unexpected. :dd
+
+{Too many inner timesteps in fix ttm} :dt
+
+Self-explanatory. :dd
+
+{Too many neighbors in CNA for %d atoms} :dt
+
+More than the maximum # of neighbors was found multiple times.  This
+was unexpected. :dd
+
+{Triclinic box skew is large} :dt
+
+The displacement in a skewed direction is normally required to be less
+than half the box length in that dimension.  E.g. the xy tilt must be
+between -half and +half of the x box length.  You have relaxed the
+constraint using the box tilt command, but the warning means that a
+LAMMPS simulation may be inefficient as a result. :dd
+
+{Use special bonds = 0,1,1 with bond style fene} :dt
+
+Most FENE models need this setting for the special_bonds command. :dd
+
+{Use special bonds = 0,1,1 with bond style fene/expand} :dt
+
+Most FENE models need this setting for the special_bonds command. :dd
+
+{Using a manybody potential with bonds/angles/dihedrals and special_bond exclusions} :dt
+
+This is likely not what you want to do.  The exclusion settings will
+eliminate neighbors in the neighbor list, which the manybody potential
+needs to calculated its terms correctly. :dd
+
+{Using compute temp/deform with inconsistent fix deform remap option} :dt
+
+Fix nvt/sllod assumes deforming atoms have a velocity profile provided
+by "remap v" or "remap none" as a fix deform option. :dd
+
+{Using compute temp/deform with no fix deform defined} :dt
+
+This is probably an error, since it makes little sense to use
+compute temp/deform in this case. :dd
+
+{Using fix srd with box deformation but no SRD thermostat} :dt
+
+The deformation will heat the SRD particles so this can
+be dangerous. :dd
+
+{Using kspace solver on system with no charge} :dt
+
+Self-explanatory. :dd
+
+{Using largest cut-off for lj/long/dipole/long long long} :dt
+
+Self-explanatory. :dd
+
+{Using largest cutoff for buck/long/coul/long} :dt
+
+Self-explanatory. :dd
+
+{Using largest cutoff for lj/long/coul/long} :dt
+
+Self-explanatory. :dd
+
+{Using largest cutoff for pair_style lj/long/tip4p/long} :dt
+
+Self-explanatory. :dd
+
+{Using package gpu without any pair style defined} :dt
+
+Self-explanatory. :dd
+
+{Using pair potential shift with pair_modify compute no} :dt
+
+The shift effects will thus not be computed. :dd
+
+{Using pair tail corrections with nonperiodic system} :dt
+
+This is probably a bogus thing to do, since tail corrections are
+computed by integrating the density of a periodic system out to
+infinity. :dd
+
+{Using pair tail corrections with pair_modify compute no} :dt
+
+The tail corrections will thus not be computed. :dd
+
+{pair style reax is now deprecated and will soon be retired. Users should switch to pair_style reax/c} :dt
+
+Self-explanatory. :dd
+
+:dle
diff --git a/doc/src/Section_example.txt b/doc/src/Examples.txt
similarity index 96%
rename from doc/src/Section_example.txt
rename to doc/src/Examples.txt
index a2a9940f4845f10c2df5fe3333c8de30cba1ea7d..08afca8b202df67f941182e7e00320118ecb48e2 100644
--- a/doc/src/Section_example.txt
+++ b/doc/src/Examples.txt
@@ -1,4 +1,6 @@
-"Previous Section"_Section_howto.html - "LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc - "Next Section"_Section_perf.html :c
+"Previous Section"_Section_howto.html - "LAMMPS WWW Site"_lws -
+"LAMMPS Documentation"_ld - "LAMMPS Commands"_lc - "Next
+Section"_Section_perf.html :c
 
 :link(lws,http://lammps.sandia.gov)
 :link(ld,Manual.html)
@@ -6,7 +8,7 @@
 
 :line
 
-7. Example problems :h2
+Example scripts :h3
 
 The LAMMPS distribution includes an examples sub-directory with many
 sample problems.  Many are 2d models that run quickly are are
@@ -46,7 +48,7 @@ Lists of both kinds of directories are given below.
 
 :line
 
-Lowercase directories :h3
+Lowercase directories :h4
 
 accelerate: run with various acceleration options (OpenMP, GPU, Phi)
 airebo:   polyethylene with AIREBO potential
@@ -122,7 +124,7 @@ browser.
 
 :line
 
-Uppercase directories :h3
+Uppercase directories :h4
 
 ASPHERE: various aspherical particle models, using ellipsoids, rigid bodies, line/triangle particles, etc
 COUPLE: examples of how to use LAMMPS as a library
diff --git a/doc/src/JPG/pair_body_rounded.jpg b/doc/src/JPG/pair_body_rounded.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..cd745c44e27e96585be021b3dcca342f686e15e9
Binary files /dev/null and b/doc/src/JPG/pair_body_rounded.jpg differ
diff --git a/doc/src/Manual.txt b/doc/src/Manual.txt
index e69797d9ec09551cc6592a7a791c8ea7459825fa..4481c911a009feee3e7babc29ab47cad43a03df7 100644
--- a/doc/src/Manual.txt
+++ b/doc/src/Manual.txt
@@ -1,5 +1,5 @@
 <!-- HTML_ONLY -->
-<HEAD>
+<
 <TITLE>LAMMPS Users Manual</TITLE>
 <META NAME="docnumber" CONTENT="16 Jul 2018 version">
 <META NAME="author" CONTENT="http://lammps.sandia.gov - Sandia National Laboratories">
@@ -114,12 +114,12 @@ it gives quick access to documentation for all LAMMPS commands.
    Section_packages
    Section_accelerate
    Section_howto
-   Section_example
+   Examples
    Section_perf
-   Section_tools
-   Section_modify
-   Section_python
-   Section_errors
+   Tools
+   Modify
+   Python
+   Errors
    Section_history
 
 .. toctree::
@@ -208,38 +208,12 @@ END_RST -->
   6.25 "Polarizable models"_howto_25 :b
   6.26 "Adiabatic core/shell model"_howto_26 :b
   6.27 "Drude induced dipoles"_howto_27 :ule,b
-"Example problems"_Section_example.html :l
+"Example scripts"_Examples.html :l
 "Performance & scalability"_Section_perf.html :l
-"Additional tools"_Section_tools.html :l
-"Modifying & extending LAMMPS"_Section_modify.html :l
-  10.1 "Atom styles"_mod_1 :ulb,b
-  10.2 "Bond, angle, dihedral, improper potentials"_mod_2 :b
-  10.3 "Compute styles"_mod_3 :b
-  10.4 "Dump styles"_mod_4 :b
-  10.5 "Dump custom output options"_mod_5 :b
-  10.6 "Fix styles"_mod_6 :b
-  10.7 "Input script commands"_mod_7 :b
-  10.8 "Kspace computations"_mod_8 :b
-  10.9 "Minimization styles"_mod_9 :b
-  10.10 "Pairwise potentials"_mod_10 :b
-  10.11 "Region styles"_mod_11 :b
-  10.12 "Body styles"_mod_12 :b
-  10.13 "Thermodynamic output options"_mod_13 :b
-  10.14 "Variable options"_mod_14 :b
-  10.15 "Submitting new features for inclusion in LAMMPS"_mod_15 :ule,b
-"Python interface"_Section_python.html :l
-  11.1 "Overview of running LAMMPS from Python"_py_1 :ulb,b
-  11.2 "Overview of using Python from a LAMMPS script"_py_2 :b
-  11.3 "Building LAMMPS as a shared library"_py_3 :b
-  11.4 "Installing the Python wrapper into Python"_py_4 :b
-  11.5 "Extending Python with MPI to run in parallel"_py_5 :b
-  11.6 "Testing the Python-LAMMPS interface"_py_6 :b
-  11.7 "Using LAMMPS from Python"_py_7 :b
-  11.8 "Example Python scripts that use LAMMPS"_py_8 :ule,b
-"Errors"_Section_errors.html :l
-  12.1 "Common problems"_err_1 :ulb,b
-  12.2 "Reporting bugs"_err_2 :b
-  12.3 "Error & warning messages"_err_3 :ule,b
+"Auxiliary tools"_Tools.html :l
+"Modify & extend LAMMPS"_Modify.html :l
+"Use Python with LAMMPS"_Python.html :l
+"Errors"_Errors.html :l
 "Future and history"_Section_history.html :l
   13.1 "Coming attractions"_hist_1 :ulb,b
   13.2 "Past versions"_hist_2 :ule,b
@@ -302,33 +276,6 @@ END_RST -->
 :link(howto_26,Section_howto.html#howto_26)
 :link(howto_27,Section_howto.html#howto_27)
 
-:link(mod_1,Section_modify.html#mod_1)
-:link(mod_2,Section_modify.html#mod_2)
-:link(mod_3,Section_modify.html#mod_3)
-:link(mod_4,Section_modify.html#mod_4)
-:link(mod_5,Section_modify.html#mod_5)
-:link(mod_6,Section_modify.html#mod_6)
-:link(mod_7,Section_modify.html#mod_7)
-:link(mod_8,Section_modify.html#mod_8)
-:link(mod_9,Section_modify.html#mod_9)
-:link(mod_10,Section_modify.html#mod_10)
-:link(mod_11,Section_modify.html#mod_11)
-:link(mod_12,Section_modify.html#mod_12)
-:link(mod_13,Section_modify.html#mod_13)
-:link(mod_14,Section_modify.html#mod_14)
-:link(mod_15,Section_modify.html#mod_15)
-
-:link(py_1,Section_python.html#py_1)
-:link(py_2,Section_python.html#py_2)
-:link(py_3,Section_python.html#py_3)
-:link(py_4,Section_python.html#py_4)
-:link(py_5,Section_python.html#py_5)
-:link(py_6,Section_python.html#py_6)
-
-:link(err_1,Section_errors.html#err_1)
-:link(err_2,Section_errors.html#err_2)
-:link(err_3,Section_errors.html#err_3)
-
 :link(hist_1,Section_history.html#hist_1)
 :link(hist_2,Section_history.html#hist_2)
 <!-- END_HTML_ONLY -->
diff --git a/doc/src/Modify.txt b/doc/src/Modify.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ae0b0dc6bdf2371f9a205c39fbc267b91ecd11b3
--- /dev/null
+++ b/doc/src/Modify.txt
@@ -0,0 +1,76 @@
+"Previous Section"_Tools.html - "LAMMPS WWW Site"_lws -
+"LAMMPS Documentation"_ld - "LAMMPS Commands"_lc - "Next
+Section"_Python.html :c
+
+:link(lws,http://lammps.sandia.gov)
+:link(ld,Manual.html)
+:link(lc,Section_commands.html#comm)
+
+:line
+
+Modify & extend LAMMPS :h2
+
+LAMMPS is designed in a modular fashion so as to be easy to modify and
+extend with new functionality.  In fact, about 95% of its source code
+is add-on files.  These doc pages give basic instructions on how to do
+this.
+
+If you add a new feature to LAMMPS and think it will be of interest to
+general users, we encourage you to submit it for inclusion in LAMMPS
+as a pull request on our "GitHub
+site"_https://github.com/lammps/lammps, after reading the "Modify
+contribute"_Modify_contribute.html doc page.
+
+<!-- RST
+
+.. toctree::
+
+   Modify_overview
+   Modify_contribute
+
+.. toctree::
+
+   Modify_atom
+   Modify_pair
+   Modify_bond
+   Modify_compute
+   Modify_fix
+   Modify_command
+
+.. toctree::
+
+   Modify_dump
+   Modify_kspace
+   Modify_min
+   Modify_region
+   Modify_body
+
+.. toctree::
+
+   Modify_thermo
+   Modify_variable
+
+END_RST -->
+
+<!-- HTML_ONLY -->
+
+"Overview"_Modify_overview.html
+"Submitting new features for inclusion in LAMMPS"_Modify_contribute.html :all(b)
+
+"Atom styles"_Modify_atom.html
+"Pair styles"_Modify_pair.html
+"Bond, angle, dihedral, improper styles"_Modify_bond.html
+"Compute styles"_Modify_compute.html
+"Fix styles"_Modify_fix.html
+"Input script command styles"_Modify_command.html :all(b)
+
+"Dump styles"_Modify_dump.html
+"Kspace styles"_Modify_kspace.html
+"Minimization styles"_Modify_min.html
+"Region styles"_Modify_region.html
+"Body styles"_Modify_body.html :all(b)
+
+"Thermodynamic output options"_Modify_thermo.html
+"Variable options"_Modify_variable.html :all(b)
+
+<!-- END_HTML_ONLY -->
diff --git a/doc/src/Modify_atom.txt b/doc/src/Modify_atom.txt
new file mode 100644
index 0000000000000000000000000000000000000000..afa1c319d25539594bb65f9dcb1f146023623ff8
--- /dev/null
+++ b/doc/src/Modify_atom.txt
@@ -0,0 +1,90 @@
+"Higher level section"_Modify.html - "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
+
+Atom styles :h3
+
+Classes that define an "atom style"_atom_style.html are derived from
+the AtomVec class and managed by the Atom class.  The atom style
+determines what attributes are associated with an atom.  A new atom
+style can be created if one of the existing atom styles does not
+define all the attributes you need to store and communicate with
+atoms.
+
+Atom_vec_atomic.cpp is a simple example of an atom style.
+
+Here is a brief description of methods you define in your new derived
+class.  See atom_vec.h for details.
+
+init: one time setup (optional)
+grow: re-allocate atom arrays to longer lengths (required)
+grow_reset: make array pointers in Atom and AtomVec classes consistent (required)
+copy: copy info for one atom to another atom's array locations (required)
+pack_comm: store an atom's info in a buffer communicated every timestep (required)
+pack_comm_vel: add velocity info to communication buffer (required)
+pack_comm_hybrid: store extra info unique to this atom style (optional)
+unpack_comm: retrieve an atom's info from the buffer (required)
+unpack_comm_vel: also retrieve velocity info (required)
+unpack_comm_hybrid: retrieve extra info unique to this atom style (optional)
+pack_reverse: store an atom's info in a buffer communicating partial forces  (required)
+pack_reverse_hybrid: store extra info unique to this atom style (optional)
+unpack_reverse: retrieve an atom's info from the buffer (required)
+unpack_reverse_hybrid: retrieve extra info unique to this atom style (optional)
+pack_border: store an atom's info in a buffer communicated on neighbor re-builds (required)
+pack_border_vel: add velocity info to buffer (required)
+pack_border_hybrid: store extra info unique to this atom style (optional)
+unpack_border: retrieve an atom's info from the buffer (required)
+unpack_border_vel: also retrieve velocity info (required)
+unpack_border_hybrid: retrieve extra info unique to this atom style (optional)
+pack_exchange: store all an atom's info to migrate to another processor (required)
+unpack_exchange: retrieve an atom's info from the buffer (required)
+size_restart: number of restart quantities associated with proc's atoms (required)
+pack_restart: pack atom quantities into a buffer (required)
+unpack_restart: unpack atom quantities from a buffer (required)
+create_atom: create an individual atom of this style (required)
+data_atom: parse an atom line from the data file (required)
+data_atom_hybrid: parse additional atom info unique to this atom style (optional)
+data_vel: parse one line of velocity information from data file (optional)
+data_vel_hybrid: parse additional velocity data unique to this atom style (optional)
+memory_usage: tally memory allocated by atom arrays (required) :tb(s=:)
+
+The constructor of the derived class sets values for several variables
+that you must set when defining a new atom style, which are documented
+in atom_vec.h.  New atom arrays are defined in atom.cpp.  Search for
+the word "customize" and you will find locations you will need to
+modify.
+
+NOTE: It is possible to add some attributes, such as a molecule ID, to
+atom styles that do not have them via the "fix
+property/atom"_fix_property_atom.html command.  This command also
+allows new custom attributes consisting of extra integer or
+floating-point values to be added to atoms.  See the "fix
+property/atom"_fix_property_atom.html doc page for examples of cases
+where this is useful and details on how to initialize, access, and
+output the custom values.
+
+New "pair styles"_pair_style.html, "fixes"_fix.html, or
+"computes"_compute.html can be added to LAMMPS, as discussed below.
+The code for these classes can use the per-atom properties defined by
+fix property/atom.  The Atom class has a find_custom() method that is
+useful in this context:
+
+int index = atom->find_custom(char *name, int &flag); :pre
+
+The "name" of a custom attribute, as specified in the "fix
+property/atom"_fix_property_atom.html command, is checked to verify
+that it exists and its index is returned.  The method also sets flag =
+0/1 depending on whether it is an integer or floating-point attribute.
+The vector of values associated with the attribute can then be
+accessed using the returned index as
+
+int *ivector = atom->ivector\[index\];
+double *dvector = atom->dvector\[index\]; :pre
+
+Ivector or dvector are vectors of length Nlocal = # of owned atoms,
+which store the attributes of individual atoms.
diff --git a/doc/src/Modify_body.txt b/doc/src/Modify_body.txt
new file mode 100644
index 0000000000000000000000000000000000000000..b1dc8130cd6ad46318fe7a9c336b7e8978cbdbe5
--- /dev/null
+++ b/doc/src/Modify_body.txt
@@ -0,0 +1,35 @@
+"Higher level section"_Modify.html - "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
+
+Body styles :h3
+
+Classes that define body particles are derived from the Body class.
+Body particles can represent complex entities, such as surface meshes
+of discrete points, collections of sub-particles, deformable objects,
+etc.
+
+See "Section 6.14"_Section_howto.html#howto_14 of the manual for
+an overview of using body particles and the "body"_body.html doc page
+for details on the various body styles LAMMPS supports.  New styles
+can be created to add new kinds of body particles to LAMMPS.
+
+Body_nparticle.cpp is an example of a body particle that is treated as
+a rigid body containing N sub-particles.
+
+Here is a brief description of methods you define in your new derived
+class.  See body.h for details.
+
+data_body: process a line from the Bodies section of a data file
+noutrow: number of sub-particles output is generated for
+noutcol: number of values per-sub-particle output is generated for
+output: output values for the Mth sub-particle
+pack_comm_body: body attributes to communicate every timestep
+unpack_comm_body: unpacking of those attributes
+pack_border_body: body attributes to communicate when reneighboring is done
+unpack_border_body: unpacking of those attributes :tb(s=:)
diff --git a/doc/src/Modify_bond.txt b/doc/src/Modify_bond.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f0828a0c3b8544c84fa8539c7eb9f30e63489cfb
--- /dev/null
+++ b/doc/src/Modify_bond.txt
@@ -0,0 +1,33 @@
+"Higher level section"_Modify.html - "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
+
+Bond, angle, dihedral, improper styles :h3
+
+Classes that compute molecular interactions are derived from the Bond,
+Angle, Dihedral, and Improper classes.  New styles can be created to
+add new potentials to LAMMPS.
+
+Bond_harmonic.cpp is the simplest example of a bond style.  Ditto for
+the harmonic forms of the angle, dihedral, and improper style
+commands.
+
+Here is a brief description of common methods you define in your
+new derived class.  See bond.h, angle.h, dihedral.h, and improper.h
+for details and specific additional methods.
+
+init: check if all coefficients are set, calls {init_style} (optional)
+init_style: check if style specific conditions are met (optional)
+compute: compute the molecular interactions (required)
+settings: apply global settings for all types (optional)
+coeff: set coefficients for one type (required)
+equilibrium_distance: length of bond, used by SHAKE (required, bond only)
+equilibrium_angle: opening of angle, used by SHAKE (required, angle only)
+write & read_restart: writes/reads coeffs to restart files (required)
+single: force and energy of a single bond or angle (required, bond or angle only)
+memory_usage: tally memory allocated by the style (optional) :tb(s=:)
diff --git a/doc/src/Modify_command.txt b/doc/src/Modify_command.txt
new file mode 100644
index 0000000000000000000000000000000000000000..6fc9aad1fc55174fa3be29eda559966b34db2259
--- /dev/null
+++ b/doc/src/Modify_command.txt
@@ -0,0 +1,27 @@
+"Higher level section"_Modify.html - "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
+
+Input script command style :h3
+
+New commands can be added to LAMMPS input scripts by adding new
+classes that have a "command" method.  For example, the create_atoms,
+read_data, velocity, and run commands are all implemented in this
+fashion.  When such a command is encountered in the LAMMPS input
+script, LAMMPS simply creates a class with the corresponding name,
+invokes the "command" method of the class, and passes it the arguments
+from the input script.  The command method can perform whatever
+operations it wishes on LAMMPS data structures.
+
+The single method your new class must define is as follows:
+
+command: operations performed by the new command :tb(s=:)
+
+Of course, the new class can define other methods and variables as
+needed.
+
diff --git a/doc/src/Modify_compute.txt b/doc/src/Modify_compute.txt
new file mode 100644
index 0000000000000000000000000000000000000000..b02b8a983ec4c32f0935c7b00b1c3c3dd59e7f5d
--- /dev/null
+++ b/doc/src/Modify_compute.txt
@@ -0,0 +1,49 @@
+"Higher level section"_Modify.html - "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
+
+Compute styles :h3
+
+Classes that compute scalar and vector quantities like temperature
+and the pressure tensor, as well as classes that compute per-atom
+quantities like kinetic energy and the centro-symmetry parameter
+are derived from the Compute class.  New styles can be created
+to add new calculations to LAMMPS.
+
+Compute_temp.cpp is a simple example of computing a scalar
+temperature.  Compute_ke_atom.cpp is a simple example of computing
+per-atom kinetic energy.
+
+Here is a brief description of methods you define in your new derived
+class.  See compute.h for details.
+
+init: perform one time setup (required)
+init_list: neighbor list setup, if needed (optional)
+compute_scalar: compute a scalar quantity (optional)
+compute_vector: compute a vector of quantities (optional)
+compute_peratom: compute one or more quantities per atom (optional)
+compute_local: compute one or more quantities per processor (optional)
+pack_comm: pack a buffer with items to communicate (optional)
+unpack_comm: unpack the buffer (optional)
+pack_reverse: pack a buffer with items to reverse communicate (optional)
+unpack_reverse: unpack the buffer (optional)
+remove_bias: remove velocity bias from one atom (optional)
+remove_bias_all: remove velocity bias from all atoms in group (optional)
+restore_bias: restore velocity bias for one atom after remove_bias (optional)
+restore_bias_all: same as before, but for all atoms in group (optional)
+pair_tally_callback: callback function for {tally}-style computes (optional).
+memory_usage: tally memory usage (optional) :tb(s=:)
+
+Tally-style computes are a special case, as their computation is done
+in two stages: the callback function is registered with the pair style
+and then called from the Pair::ev_tally() function, which is called for
+each pair after force and energy has been computed for this pair. Then
+the tallied values are retrieved with the standard compute_scalar or
+compute_vector or compute_peratom methods. The USER-TALLY package
+provides {examples}_compute_tally.html for utilizing this mechanism.
+
diff --git a/doc/src/Modify_contribute.txt b/doc/src/Modify_contribute.txt
new file mode 100644
index 0000000000000000000000000000000000000000..80795b5e205332fdfac501c74bee8153706ad33e
--- /dev/null
+++ b/doc/src/Modify_contribute.txt
@@ -0,0 +1,210 @@
+"Higher level section"_Modify.html - "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
+
+Submitting new features for inclusion in LAMMPS :h3
+
+We encourage users to submit new features or modifications for LAMMPS
+to "the core developers"_http://lammps.sandia.gov/authors.html so they
+can be added to the LAMMPS distribution. The preferred way to manage
+and coordinate this is as of Fall 2016 via the LAMMPS project on
+"GitHub"_https://github.com/lammps/lammps. An alternative is to
+contact the LAMMPS developers or the indicated developer of a package
+or feature directly and send in your contribution via e-mail.
+
+For any larger modifications or programming project, you are
+encouraged to contact the LAMMPS developers ahead of time, in order to
+discuss implementation strategies and coding guidelines, that will
+make it easier to integrate your contribution and result in less work
+for everybody involved. You are also encouraged to search through the
+list of "open issues on
+GitHub"_https://github.com/lammps/lammps/issues and submit a new issue
+for a planned feature, so you would not duplicate the work of others
+(and possibly get scooped by them) or have your work duplicated by
+others.
+
+How quickly your contribution will be integrated depends largely on
+how much effort it will cause to integrate and test it, how much it
+requires changes to the core codebase, and of how much interest it is
+to the larger LAMMPS community.  Please see below for a checklist of
+typical requirements. Once you have prepared everything, see "this
+tutorial"_tutorial_github.html for instructions on how to submit your
+changes or new files through a GitHub pull request. If you prefer to
+submit patches or full files, you should first make certain, that your
+code works correctly with the latest patch-level version of LAMMPS and
+contains all bugfixes from it. Then create a gzipped tar file of all
+changed or added files or a corresponding patch file using 'diff -u'
+or 'diff -c' and compress it with gzip. Please only use gzip
+compression, as this works well on all platforms.
+
+If the new features/files are broadly useful we may add them as core
+files to LAMMPS or as part of a "standard
+package"_Section_start.html#start_3.  Else we will add them as a
+user-contributed file or package.  Examples of user packages are in
+src sub-directories that start with USER.  The USER-MISC package is
+simply a collection of (mostly) unrelated single files, which is the
+simplest way to have your contribution quickly added to the LAMMPS
+distribution.  You can see a list of the both standard and user
+packages by typing "make package" in the LAMMPS src directory.
+
+Note that by providing us files to release, you are agreeing to make
+them open-source, i.e. we can release them under the terms of the GPL,
+used as a license for the rest of LAMMPS.  See "Section
+1.4"_Section_intro.html#intro_4 for details.
+
+With user packages and files, all we are really providing (aside from
+the fame and fortune that accompanies having your name in the source
+code and on the "Authors page"_http://lammps.sandia.gov/authors.html
+of the "LAMMPS WWW site"_lws), is a means for you to distribute your
+work to the LAMMPS user community, and a mechanism for others to
+easily try out your new feature.  This may help you find bugs or make
+contact with new collaborators.  Note that you're also implicitly
+agreeing to support your code which means answer questions, fix bugs,
+and maintain it if LAMMPS changes in some way that breaks it (an
+unusual event).
+
+NOTE: If you prefer to actively develop and support your add-on
+feature yourself, then you may wish to make it available for download
+from your own website, as a user package that LAMMPS users can add to
+their copy of LAMMPS.  See the "Offsite LAMMPS packages and
+tools"_http://lammps.sandia.gov/offsite.html page of the LAMMPS web
+site for examples of groups that do this.  We are happy to advertise
+your package and web site from that page.  Simply email the
+"developers"_http://lammps.sandia.gov/authors.html with info about
+your package and we will post it there.
+
+The previous sections of this doc page describe how to add new "style"
+files of various kinds to LAMMPS.  Packages are simply collections of
+one or more new class files which are invoked as a new style within a
+LAMMPS input script.  If designed correctly, these additions typically
+do not require changes to the main core of LAMMPS; they are simply
+add-on files.  If you think your new feature requires non-trivial
+changes in core LAMMPS files, you'll need to "communicate with the
+developers"_http://lammps.sandia.gov/authors.html, since we may or may
+not want to make those changes.  An example of a trivial change is
+making a parent-class method "virtual" when you derive a new child
+class from it.
+
+Here is a checklist of steps you need to follow to submit a single file
+or user package for our consideration.  Following these steps will save
+both you and us time. See existing files in packages in the src dir for
+examples. If you are uncertain, please ask.
+
+All source files you provide must compile with the most current
+version of LAMMPS with multiple configurations. In particular you
+need to test compiling LAMMPS from scratch with -DLAMMPS_BIGBIG
+set in addition to the default -DLAMMPS_SMALLBIG setting. Your code
+will need to work correctly in serial and in parallel using MPI. :ulb,l
+
+For consistency with the rest of LAMMPS and especially, if you want
+your contribution(s) to be added to main LAMMPS code or one of its
+standard packages, it needs to be written in a style compatible with
+other LAMMPS source files. This means: 2-character indentation per
+level, [no tabs], no lines over 80 characters. I/O is done via
+the C-style stdio library, class header files should not import any
+system headers outside <stdio.h>, STL containers should be avoided
+in headers, and forward declarations used where possible or needed.
+All added code should be placed into the LAMMPS_NS namespace or a
+sub-namespace; global or static variables should be avoided, as they
+conflict with the modular nature of LAMMPS and the C++ class structure.
+Header files must [not] import namespaces with {using}.
+This all is so the developers can more easily understand, integrate,
+and maintain your contribution and reduce conflicts with other parts
+of LAMMPS.  This basically means that the code accesses data
+structures, performs its operations, and is formatted similar to other
+LAMMPS source files, including the use of the error class for error
+and warning messages. :l
+
+If you want your contribution to be added as a user-contributed
+feature, and it's a single file (actually a *.cpp and *.h file) it can
+rapidly be added to the USER-MISC directory.  Send us the one-line
+entry to add to the USER-MISC/README file in that dir, along with the
+2 source files.  You can do this multiple times if you wish to
+contribute several individual features.  :l
+
+If you want your contribution to be added as a user-contribution and
+it is several related features, it is probably best to make it a user
+package directory with a name like USER-FOO.  In addition to your new
+files, the directory should contain a README text file.  The README
+should contain your name and contact information and a brief
+description of what your new package does.  If your files depend on
+other LAMMPS style files also being installed (e.g. because your file
+is a derived class from the other LAMMPS class), then an Install.sh
+file is also needed to check for those dependencies.  See other README
+and Install.sh files in other USER directories as examples.  Send us a
+tarball of this USER-FOO directory. :l
+
+Your new source files need to have the LAMMPS copyright, GPL notice,
+and your name and email address at the top, like other
+user-contributed LAMMPS source files.  They need to create a class
+that is inside the LAMMPS namespace.  If the file is for one of the
+
+USER packages, including USER-MISC, then we are not as picky about the
+coding style (see above).  I.e. the files do not need to be in the
+same stylistic format and syntax as other LAMMPS files, though that
+would be nice for developers as well as users who try to read your
+code. :l
+
+You [must] also create a [documentation] file for each new command or
+style you are adding to LAMMPS. For simplicity and convenience, the
+documentation of groups of closely related commands or styles may be
+combined into a single file.  This will be one file for a single-file
+feature.  For a package, it might be several files.  These are simple
+text files with a specific markup language, that are then auto-converted
+to HTML and PDF. The tools for this conversion are included in the
+source distribution, and the translation can be as simple as doing
+"make html pdf" in the doc folder.
+Thus the documentation source files must be in the same format and
+style as other *.txt files in the lammps/doc/src directory for similar
+commands and styles; use one or more of them as a starting point.
+A description of the markup can also be found in
+lammps/doc/utils/txt2html/README.html
+As appropriate, the text files can include links to equations
+(see doc/Eqs/*.tex for examples, we auto-create the associated JPG
+files), or figures (see doc/JPG for examples), or even additional PDF
+files with further details (see doc/PDF for examples).  The doc page
+should also include literature citations as appropriate; see the
+bottom of doc/fix_nh.txt for examples and the earlier part of the same
+file for how to format the cite itself.  The "Restrictions" section of
+the doc page should indicate that your command is only available if
+LAMMPS is built with the appropriate USER-MISC or USER-FOO package.
+See other user package doc files for examples of how to do this. The
+prerequisite for building the HTML format files are Python 3.x and
+virtualenv, the requirement for generating the PDF format manual
+is the "htmldoc"_http://www.htmldoc.org/ software. Please run at least
+"make html" and carefully inspect and proofread the resulting HTML format
+doc page before submitting your code. :l
+
+For a new package (or even a single command) you should include one or
+more example scripts demonstrating its use.  These should run in no
+more than a couple minutes, even on a single processor, and not require
+large data files as input.  See directories under examples/USER for
+examples of input scripts other users provided for their packages.
+These example inputs are also required for validating memory accesses
+and testing for memory leaks with valgrind :l
+
+If there is a paper of yours describing your feature (either the
+algorithm/science behind the feature itself, or its initial usage, or
+its implementation in LAMMPS), you can add the citation to the *.cpp
+source file.  See src/USER-EFF/atom_vec_electron.cpp for an example.
+A LaTeX citation is stored in a variable at the top of the file and a
+single line of code that references the variable is added to the
+constructor of the class.  Whenever a user invokes your feature from
+their input script, this will cause LAMMPS to output the citation to a
+log.cite file and prompt the user to examine the file.  Note that you
+should only use this for a paper you or your group authored.
+E.g. adding a cite in the code for a paper by Nose and Hoover if you
+write a fix that implements their integrator is not the intended
+usage.  That kind of citation should just be in the doc page you
+provide. :l
+:ule
+
+Finally, as a general rule-of-thumb, the more clear and
+self-explanatory you make your documentation and README files, and the
+easier you make it for people to get started, e.g. by providing example
+scripts, the more likely it is that users will try out your new feature.
diff --git a/doc/src/Modify_dump.txt b/doc/src/Modify_dump.txt
new file mode 100644
index 0000000000000000000000000000000000000000..81af54e0039a3ad9f95f34f7f0498457914a6f6d
--- /dev/null
+++ b/doc/src/Modify_dump.txt
@@ -0,0 +1,35 @@
+"Higher level section"_Modify.html - "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
+
+Dump styles :h3
+
+Classes that dump per-atom info to files are derived from the Dump
+class.  To dump new quantities or in a new format, a new derived dump
+class can be added, but it is typically simpler to modify the
+DumpCustom class contained in the dump_custom.cpp file.
+
+Dump_atom.cpp is a simple example of a derived dump class.
+
+Here is a brief description of methods you define in your new derived
+class.  See dump.h for details.
+
+write_header: write the header section of a snapshot of atoms
+count: count the number of lines a processor will output
+pack: pack a proc's output data into a buffer
+write_data: write a proc's data to a file :tb(s=:)
+
+See the "dump"_dump.html command and its {custom} style for a list of
+keywords for atom information that can already be dumped by
+DumpCustom.  It includes options to dump per-atom info from Compute
+classes, so adding a new derived Compute class is one way to calculate
+new quantities to dump.
+
+Note that new keywords for atom properties are not typically
+added to the "dump custom"_dump.html command.  Instead they are added
+to the "compute property/atom"_compute_property_atom.html command.
diff --git a/doc/src/Modify_fix.txt b/doc/src/Modify_fix.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ba985475cc9e72721b7dd50bf3bc9268f97f60c0
--- /dev/null
+++ b/doc/src/Modify_fix.txt
@@ -0,0 +1,107 @@
+"Higher level section"_Modify.html - "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
+
+Fix styles :h3
+
+In LAMMPS, a "fix" is any operation that is computed during
+timestepping that alters some property of the system.  Essentially
+everything that happens during a simulation besides force computation,
+neighbor list construction, and output, is a "fix".  This includes
+time integration (update of coordinates and velocities), force
+constraints or boundary conditions (SHAKE or walls), and diagnostics
+(compute a diffusion coefficient).  New styles can be created to add
+new options to LAMMPS.
+
+Fix_setforce.cpp is a simple example of setting forces on atoms to
+prescribed values.  There are dozens of fix options already in LAMMPS;
+choose one as a template that is similar to what you want to
+implement.
+
+Here is a brief description of methods you can define in your new
+derived class.  See fix.h for details.
+
+setmask: determines when the fix is called during the timestep (required)
+init: initialization before a run (optional)
+setup_pre_exchange: called before atom exchange in setup (optional)
+setup_pre_force: called before force computation in setup (optional)
+setup: called immediately before the 1st timestep and after forces are computed (optional)
+min_setup_pre_force: like setup_pre_force, but for minimizations instead of MD runs (optional)
+min_setup: like setup, but for minimizations instead of MD runs (optional)
+initial_integrate: called at very beginning of each timestep (optional)
+pre_exchange: called before atom exchange on re-neighboring steps (optional)
+pre_neighbor: called before neighbor list build (optional)
+pre_force: called before pair & molecular forces are computed (optional)
+post_force: called after pair & molecular forces are computed and communicated (optional)
+final_integrate: called at end of each timestep (optional)
+end_of_step: called at very end of timestep (optional)
+write_restart: dumps fix info to restart file (optional)
+restart: uses info from restart file to re-initialize the fix (optional)
+grow_arrays: allocate memory for atom-based arrays used by fix (optional)
+copy_arrays: copy atom info when an atom migrates to a new processor (optional)
+pack_exchange: store atom's data in a buffer (optional)
+unpack_exchange: retrieve atom's data from a buffer (optional)
+pack_restart: store atom's data for writing to restart file (optional)
+unpack_restart: retrieve atom's data from a restart file buffer (optional)
+size_restart: size of atom's data (optional)
+maxsize_restart: max size of atom's data (optional)
+setup_pre_force_respa: same as setup_pre_force, but for rRESPA (optional)
+initial_integrate_respa: same as initial_integrate, but for rRESPA (optional)
+post_integrate_respa: called after the first half integration step is done in rRESPA (optional)
+pre_force_respa: same as pre_force, but for rRESPA (optional)
+post_force_respa: same as post_force, but for rRESPA (optional)
+final_integrate_respa: same as final_integrate, but for rRESPA (optional)
+min_pre_force: called after pair & molecular forces are computed in minimizer (optional)
+min_post_force: called after pair & molecular forces are computed and communicated in minimizer (optional)
+min_store: store extra data for linesearch based minimization on a LIFO stack (optional)
+min_pushstore: push the minimization LIFO stack one element down (optional)
+min_popstore: pop the minimization LIFO stack one element up (optional)
+min_clearstore: clear minimization LIFO stack (optional)
+min_step: reset or move forward on line search minimization (optional)
+min_dof: report number of degrees of freedom {added} by this fix in minimization (optional)
+max_alpha: report maximum allowed step size during linesearch minimization (optional)
+pack_comm: pack a buffer to communicate a per-atom quantity (optional)
+unpack_comm: unpack a buffer to communicate a per-atom quantity (optional)
+pack_reverse_comm: pack a buffer to reverse communicate a per-atom quantity (optional)
+unpack_reverse_comm: unpack a buffer to reverse communicate a per-atom quantity (optional)
+dof: report number of degrees of freedom {removed} by this fix during MD (optional)
+compute_scalar: return a global scalar property that the fix computes (optional)
+compute_vector: return a component of a vector property that the fix computes (optional)
+compute_array: return a component of an array property that the fix computes (optional)
+deform: called when the box size is changed (optional)
+reset_target: called when a change of the target temperature is requested during a run (optional)
+reset_dt: is called when a change of the time step is requested during a run (optional)
+modify_param: called when a fix_modify request is executed (optional)
+memory_usage: report memory used by fix (optional)
+thermo: compute quantities for thermodynamic output (optional) :tb(s=:)
+
+Typically, only a small fraction of these methods are defined for a
+particular fix.  Setmask is mandatory, as it determines when the fix
+will be invoked during the timestep.  Fixes that perform time
+integration ({nve}, {nvt}, {npt}) implement initial_integrate() and
+final_integrate() to perform velocity Verlet updates.  Fixes that
+constrain forces implement post_force().
+
+Fixes that perform diagnostics typically implement end_of_step().  For
+an end_of_step fix, one of your fix arguments must be the variable
+"nevery" which is used to determine when to call the fix and you must
+set this variable in the constructor of your fix.  By convention, this
+is the first argument the fix defines (after the ID, group-ID, style).
+
+If the fix needs to store information for each atom that persists from
+timestep to timestep, it can manage that memory and migrate the info
+with the atoms as they move from processors to processor by
+implementing the grow_arrays, copy_arrays, pack_exchange, and
+unpack_exchange methods.  Similarly, the pack_restart and
+unpack_restart methods can be implemented to store information about
+the fix in restart files.  If you wish an integrator or force
+constraint fix to work with rRESPA (see the "run_style"_run_style.html
+command), the initial_integrate, post_force_integrate, and
+final_integrate_respa methods can be implemented.  The thermo method
+enables a fix to contribute values to thermodynamic output, as printed
+quantities and/or to be summed to the potential energy of the system.
diff --git a/doc/src/Modify_kspace.txt b/doc/src/Modify_kspace.txt
new file mode 100644
index 0000000000000000000000000000000000000000..21407bf2e9af32f5aa836889ca40824845eb5b98
--- /dev/null
+++ b/doc/src/Modify_kspace.txt
@@ -0,0 +1,25 @@
+"Higher level section"_Modify.html - "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 styles :h3
+
+Classes that compute long-range Coulombic interactions via K-space
+representations (Ewald, PPPM) are derived from the KSpace class.  New
+styles can be created to add new K-space options to LAMMPS.
+
+Ewald.cpp is an example of computing K-space interactions.
+
+Here is a brief description of methods you define in your new derived
+class.  See kspace.h for details.
+
+init: initialize the calculation before a run
+setup: computation before the 1st timestep of a run
+compute: every-timestep computation
+memory_usage: tally of memory usage :tb(s=:)
+
diff --git a/doc/src/Modify_min.txt b/doc/src/Modify_min.txt
new file mode 100644
index 0000000000000000000000000000000000000000..5dcf0f1e6751899be88458220e188dde5e6f716a
--- /dev/null
+++ b/doc/src/Modify_min.txt
@@ -0,0 +1,23 @@
+"Higher level section"_Modify.html - "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
+
+Minimization styles :h3
+
+Classes that perform energy minimization derived from the Min class.
+New styles can be created to add new minimization algorithms to
+LAMMPS.
+
+Min_cg.cpp is an example of conjugate gradient minimization.
+
+Here is a brief description of methods you define in your new derived
+class.  See min.h for details.
+
+init: initialize the minimization before a run
+run: perform the minimization
+memory_usage: tally of memory usage :tb(s=:)
diff --git a/doc/src/Modify_overview.txt b/doc/src/Modify_overview.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f9964d964b14d0ae81d219aab6891278e37a3f36
--- /dev/null
+++ b/doc/src/Modify_overview.txt
@@ -0,0 +1,101 @@
+"Higher level section"_Modify.html - "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
+
+Overview :h3
+
+The best way to add a new feature to LAMMPS is to find a similar
+featureand look at the corresponding source and header files to figure
+out what it does.  You will need some knowledge of C++ to be able to
+understand the hi-level structure of LAMMPS and its class
+organization, but functions (class methods) that do actual
+computations are written in vanilla C-style code and operate on simple
+C-style data structures (vectors and arrays).
+
+Most of the new features described on the "Modify"_Modify.html doc
+page require you to write a new C++ derived class (except for
+exceptions described below, where you can make small edits to existing
+files).  Creating a new class requires 2 files, a source code file
+(*.cpp) and a header file (*.h).  The derived class must provide
+certain methods to work as a new option.  Depending on how different
+your new feature is compared to existing features, you can either
+derive from the base class itself, or from a derived class that
+already exists.  Enabling LAMMPS to invoke the new class is as simple
+as putting the two source files in the src dir and re-building LAMMPS.
+
+The advantage of C++ and its object-orientation is that all the code
+and variables needed to define the new feature are in the 2 files you
+write, and thus shouldn't make the rest of LAMMPS more complex or
+cause side-effect bugs.
+
+Here is a concrete example.  Suppose you write 2 files pair_foo.cpp
+and pair_foo.h that define a new class PairFoo that computes pairwise
+potentials described in the classic 1997 "paper"_#Foo by Foo, et al.
+If you wish to invoke those potentials in a LAMMPS input script with a
+command like
+
+pair_style foo 0.1 3.5 :pre
+
+then your pair_foo.h file should be structured as follows:
+
+#ifdef PAIR_CLASS
+PairStyle(foo,PairFoo)
+#else
+...
+(class definition for PairFoo)
+...
+#endif :pre
+
+where "foo" is the style keyword in the pair_style command, and
+PairFoo is the class name defined in your pair_foo.cpp and pair_foo.h
+files.
+
+When you re-build LAMMPS, your new pairwise potential becomes part of
+the executable and can be invoked with a pair_style command like the
+example above.  Arguments like 0.1 and 3.5 can be defined and
+processed by your new class.
+
+As illustrated by this pairwise example, many kinds of options are
+referred to in the LAMMPS documentation as the "style" of a particular
+command.
+
+The "Modify page"_Modify.html lists all the common styles in LAMMPS,
+and discusses the header file for the base class that these styles are
+derived from.  Public variables in that file are ones used and set by
+the derived classes which are also used by the base class.  Sometimes
+they are also used by the rest of LAMMPS.  Virtual functions in the
+base class header file which are set = 0 are ones you must define in
+your new derived class to give it the functionality LAMMPS expects.
+Virtual functions that are not set to 0 are functions you can
+optionally define.
+
+Additionally, new output options can be added directly to the
+thermo.cpp, dump_custom.cpp, and variable.cpp files.  These are also
+listed on the "Modify page"_Modify.html.
+
+Here are additional guidelines for modifying LAMMPS and adding new
+functionality:
+
+Think about whether what you want to do would be better as a pre- or
+post-processing step.  Many computations are more easily and more
+quickly done that way. :ulb,l
+
+Don't do anything within the timestepping of a run that isn't
+parallel.  E.g. don't accumulate a bunch of data on a single processor
+and analyze it.  You run the risk of seriously degrading the parallel
+efficiency. :l
+
+If your new feature reads arguments or writes output, make sure you
+follow the unit conventions discussed by the "units"_units.html
+command. :l
+:ule
+
+:line
+
+:link(Foo)
+[(Foo)] Foo, Morefoo, and Maxfoo, J of Classic Potentials, 75, 345 (1997).
diff --git a/doc/src/Modify_pair.txt b/doc/src/Modify_pair.txt
new file mode 100644
index 0000000000000000000000000000000000000000..8c234dc62135f635bccc3e96ce93179cb901c569
--- /dev/null
+++ b/doc/src/Modify_pair.txt
@@ -0,0 +1,33 @@
+"Higher level section"_Modify.html - "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 styles :h3
+
+Classes that compute pairwise interactions are derived from the Pair
+class.  In LAMMPS, pairwise calculation include manybody potentials
+such as EAM or Tersoff where particles interact without a static bond
+topology.  New styles can be created to add new pair potentials to
+LAMMPS.
+
+Pair_lj_cut.cpp is a simple example of a Pair class, though it
+includes some optional methods to enable its use with rRESPA.
+
+Here is a brief description of the class methods in pair.h:
+
+compute: workhorse routine that computes pairwise interactions
+settings: reads the input script line with arguments you define
+coeff: set coefficients for one i,j type pair
+init_one: perform initialization for one i,j type pair
+init_style: initialization specific to this pair style
+write & read_restart: write/read i,j pair coeffs to restart files
+write & read_restart_settings: write/read global settings to restart files
+single: force and energy of a single pairwise interaction between 2 atoms
+compute_inner/middle/outer: versions of compute used by rRESPA :tb(s=:)
+
+The inner/middle/outer routines are optional.
diff --git a/doc/src/Modify_region.txt b/doc/src/Modify_region.txt
new file mode 100644
index 0000000000000000000000000000000000000000..9fbf359292b3e2edd95a3e1b6bd616c4336831a2
--- /dev/null
+++ b/doc/src/Modify_region.txt
@@ -0,0 +1,25 @@
+"Higher level section"_Modify.html - "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
+
+Region styles :h3
+
+Classes that define geometric regions are derived from the Region
+class.  Regions are used elsewhere in LAMMPS to group atoms, delete
+atoms to create a void, insert atoms in a specified region, etc.  New
+styles can be created to add new region shapes to LAMMPS.
+
+Region_sphere.cpp is an example of a spherical region.
+
+Here is a brief description of methods you define in your new derived
+class.  See region.h for details.
+
+inside: determine whether a point is in the region
+surface_interior: determine if a point is within a cutoff distance inside of surc
+surface_exterior: determine if a point is within a cutoff distance outside of surf
+shape_update : change region shape if set by time-dependent variable :tb(s=:)
diff --git a/doc/src/Modify_thermo.txt b/doc/src/Modify_thermo.txt
new file mode 100644
index 0000000000000000000000000000000000000000..001a9f99e108e2fb26285ee8a672f0a54d9f0097
--- /dev/null
+++ b/doc/src/Modify_thermo.txt
@@ -0,0 +1,35 @@
+"Higher level section"_Modify.html - "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
+
+Thermodynamic output options :h3
+
+There is one class that computes and prints thermodynamic information
+to the screen and log file; see the file thermo.cpp.
+
+There are two styles defined in thermo.cpp: "one" and "multi".  There
+is also a flexible "custom" style which allows the user to explicitly
+list keywords for quantities to print when thermodynamic info is
+output.  See the "thermo_style"_thermo_style.html command for a list
+of defined quantities.
+
+The thermo styles (one, multi, etc) are simply lists of keywords.
+Adding a new style thus only requires defining a new list of keywords.
+Search for the word "customize" with references to "thermo style" in
+thermo.cpp to see the two locations where code will need to be added.
+
+New keywords can also be added to thermo.cpp to compute new quantities
+for output.  Search for the word "customize" with references to
+"keyword" in thermo.cpp to see the several locations where code will
+need to be added.
+
+Note that the "thermo_style custom"_thermo.html command already allows
+for thermo output of quantities calculated by "fixes"_fix.html,
+"computes"_compute.html, and "variables"_variable.html.  Thus, it may
+be simpler to compute what you wish via one of those constructs, than
+by adding a new keyword to the thermo command.
diff --git a/doc/src/Modify_variable.txt b/doc/src/Modify_variable.txt
new file mode 100644
index 0000000000000000000000000000000000000000..3c5b29cd1af5d234dd76b2d573bcc07d2eb8087f
--- /dev/null
+++ b/doc/src/Modify_variable.txt
@@ -0,0 +1,46 @@
+"Higher level section"_Modify.html - "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
+
+Variable options :h3
+
+There is one class that computes and stores "variable"_variable.html
+information in LAMMPS; see the file variable.cpp.  The value
+associated with a variable can be periodically printed to the screen
+via the "print"_print.html, "fix print"_fix_print.html, or
+"thermo_style custom"_thermo_style.html commands.  Variables of style
+"equal" can compute complex equations that involve the following types
+of arguments:
+
+thermo keywords = ke, vol, atoms, ...
+other variables = v_a, v_myvar, ...
+math functions = div(x,y), mult(x,y), add(x,y), ...
+group functions = mass(group), xcm(group,x), ...
+atom values = x\[123\], y\[3\], vx\[34\], ...
+compute values = c_mytemp\[0\], c_thermo_press\[3\], ... :pre
+
+Adding keywords for the "thermo_style custom"_thermo_style.html
+command (which can then be accessed by variables) is discussed on the
+"Modify thermo"_Modify_thermo.html doc page.
+
+Adding a new math function of one or two arguments can be done by
+editing one section of the Variable::evaluate() method.  Search for
+the word "customize" to find the appropriate location.
+
+Adding a new group function can be done by editing one section of the
+Variable::evaluate() method.  Search for the word "customize" to find
+the appropriate location.  You may need to add a new method to the
+Group class as well (see the group.cpp file).
+
+Accessing a new atom-based vector can be done by editing one section
+of the Variable::evaluate() method.  Search for the word "customize"
+to find the appropriate location.
+
+Adding new "compute styles"_compute.html (whose calculated values can
+then be accessed by variables) is discussed on the "Modify
+compute"_Modify_compute.html doc page.
diff --git a/doc/src/Python.txt b/doc/src/Python.txt
new file mode 100644
index 0000000000000000000000000000000000000000..169670d669da6bbfcbdcb9adb491276819685f9f
--- /dev/null
+++ b/doc/src/Python.txt
@@ -0,0 +1,79 @@
+"Previous Section"_Modify.html - "LAMMPS WWW Site"_lws -
+"LAMMPS Documentation"_ld - "LAMMPS Commands"_lc - "Next
+Section"_Errors.html :c
+
+:link(lws,http://lammps.sandia.gov)
+:link(ld,Manual.html)
+:link(lc,Section_commands.html#comm)
+
+:line
+
+Use Python with LAMMPS :h2
+
+These doc pages describe various ways that LAMMPS and Python can be
+used together.
+
+<!-- RST
+
+.. toctree::
+
+   Python_overview
+
+.. toctree::
+
+   Python_run
+   Python_shlib
+   Python_install
+   Python_mpi
+   Python_test
+   Python_library
+   Python_pylammps
+   Python_examples
+
+.. toctree::
+
+   Python_call
+
+END_RST -->
+
+<!-- HTML_ONLY -->
+
+"Overview of Python and LAMMPS"_Python_overview.html :all(b)
+
+"Run LAMMPS from Python"_Python_run.html
+"Build LAMMPS as a shared library"_Python_shlib.html
+"Install LAMMPS in Python"_Python_install.html
+"Extend Python to run in parallel"_Python_mpi.html
+"Test the Python/LAMMPS interface"_Python_test.html
+"Python library interface"_Python_library.html
+"PyLammps interface"_Python_pylammps.html
+"Example Python scripts that use LAMMPS"_Python_examples.html :all(b)
+
+"Call Python from a LAMMPS input script"_Python_call.html :all(b)
+
+<!-- END_HTML_ONLY -->
+
+If you're not familiar with "Python"_http://www.python.org, it's a
+powerful scripting and programming language which can do most
+everything that lower-level languages like C or C++ can do in fewer
+lines of code.  The only drawback is slower execution speed.  Python
+is also easy to use as a "glue" language to drive a program through
+its library interface, or to hook multiple pieces of software
+together, such as a simulation code plus a visualization tool, or to
+run a coupled multiscale or multiphysics model.
+
+See the "Howto_couple"_Howto_couple.html doc page for more ideas about
+coupling LAMMPS to other codes.  See the "Howto
+library"_Howto_library.html doc page for a description of the LAMMPS
+library interface provided in src/library.h and src/library.h.  That
+interface is exposed to Python either when calling LAMMPS from Python
+or when calling Python from a LAMMPS input script and then calling
+back to LAMMPS from Python code.  The library interface is designed to
+be easy to add funcionality to.  Thus the Python interface to LAMMPS
+is also easy to extend as well.
+
+If you create interesting Python scripts that run LAMMPS or
+interesting Python functions that can be called from a LAMMPS input
+script, that you think would be genearlly useful, please post them as
+a pull request to our "GitHub site"_https://github.com/lammps/lammps,
+and they can be added to the LAMMPS distribution or webpage.
diff --git a/doc/src/Python_call.txt b/doc/src/Python_call.txt
new file mode 100644
index 0000000000000000000000000000000000000000..3e30a5a7c7e7d831413c1e532de421d40555fdd0
--- /dev/null
+++ b/doc/src/Python_call.txt
@@ -0,0 +1,85 @@
+"Higher level section"_Python.html - "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
+
+Call Python from a LAMMPS input script :h3
+
+LAMMPS has several commands which can be used to invoke Python
+code directly from an input script:
+
+"python"_python.html
+"variable python"_variable.html
+"fix python/invoke"_fix_python_invoke.html
+"pair_style python"_pair_python.html :ul
+
+The "python"_python.html command which can be used to define and
+execute a Python function that you write the code for.  The Python
+function can also be assigned to a LAMMPS python-style variable via
+the "variable"_variable.html command.  Each time the variable is
+evaluated, either in the LAMMPS input script itself, or by another
+LAMMPS command that uses the variable, this will trigger the Python
+function to be invoked.
+
+The Python code for the function can be included directly in the input
+script or in an auxiliary file.  The function can have arguments which
+are mapped to LAMMPS variables (also defined in the input script) and
+it can return a value to a LAMMPS variable.  This is thus a mechanism
+for your input script to pass information to a piece of Python code,
+ask Python to execute the code, and return information to your input
+script.
+
+Note that a Python function can be arbitrarily complex.  It can import
+other Python modules, instantiate Python classes, call other Python
+functions, etc.  The Python code that you provide can contain more
+code than the single function.  It can contain other functions or
+Python classes, as well as global variables or other mechanisms for
+storing state between calls from LAMMPS to the function.
+
+The Python function you provide can consist of "pure" Python code that
+only performs operations provided by standard Python.  However, the
+Python function can also "call back" to LAMMPS through its
+Python-wrapped library interface, in the manner described in the
+"Python run"_Python_run.html doc page.  This means it can issue LAMMPS
+input script commands or query and set internal LAMMPS state.  As an
+example, this can be useful in an input script to create a more
+complex loop with branching logic, than can be created using the
+simple looping and branching logic enabled by the "next"_next.html and
+"if"_if.html commands.
+
+See the "python"_python.html doc page and the "variable"_variable.html
+doc page for its python-style variables for more info, including
+examples of Python code you can write for both pure Python operations
+and callbacks to LAMMPS.
+
+The "fix python/invoke"_fix_python_invoke.html command can execute
+Python code at selected timesteps during a simulation run.
+
+The "pair_style python"_pair_python command allows you to define
+pairwise potentials as python code which encodes a single pairwise
+interaction.  This is useful for rapid-developement and debugging of a
+new potential.
+
+To use any of these commands, you only need to build LAMMPS with the
+PYTHON package installed:
+
+make yes-python
+make machine :pre
+
+Note that this will link LAMMPS with the Python library on your
+system, which typically requires several auxiliary system libraries to
+also be linked.  The list of these libraries and the paths to find
+them are specified in the lib/python/Makefile.lammps file.  You need
+to insure that file contains the correct information for your version
+of Python and your machine to successfully build LAMMPS.  See the
+lib/python/README file for more info.
+
+If you want to write Python code with callbacks to LAMMPS, then you
+must also follow the steps overviewed in the "Python
+run"_Python_run.html doc page.  I.e. you must build LAMMPS as a shared
+library and insure that Python can find the python/lammps.py file and
+the shared library.
diff --git a/doc/src/Python_examples.txt b/doc/src/Python_examples.txt
new file mode 100644
index 0000000000000000000000000000000000000000..fbca381e8b0f1cc4084e491162f2dad6dd7ddb36
--- /dev/null
+++ b/doc/src/Python_examples.txt
@@ -0,0 +1,81 @@
+"Higher level section"_Python.html - "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
+
+Example Python scripts that use LAMMPS :h3
+
+These are the Python scripts included as demos in the python/examples
+directory of the LAMMPS distribution, to illustrate the kinds of
+things that are possible when Python wraps LAMMPS.  If you create your
+own scripts, send them to us and we can include them in the LAMMPS
+distribution.
+
+trivial.py, read/run a LAMMPS input script thru Python,
+demo.py, invoke various LAMMPS library interface routines,
+simple.py, run in parallel, similar to examples/COUPLE/simple/simple.cpp,
+split.py, same as simple.py but running in parallel on a subset of procs,
+gui.py, GUI go/stop/temperature-slider to control LAMMPS,
+plot.py, real-time temperature plot with GnuPlot via Pizza.py,
+viz_tool.py, real-time viz via some viz package,
+vizplotgui_tool.py, combination of viz_tool.py and plot.py and gui.py :tb(c=2)
+
+:line
+
+For the viz_tool.py and vizplotgui_tool.py commands, replace "tool"
+with "gl" or "atomeye" or "pymol" or "vmd", depending on what
+visualization package you have installed.
+
+Note that for GL, you need to be able to run the Pizza.py GL tool,
+which is included in the pizza sub-directory.  See the "Pizza.py doc
+pages"_pizza for more info:
+
+:link(pizza,http://www.sandia.gov/~sjplimp/pizza.html)
+
+Note that for AtomEye, you need version 3, and there is a line in the
+scripts that specifies the path and name of the executable.  See the
+AtomEye WWW pages "here"_atomeye or "here"_atomeye3 for more details:
+
+http://mt.seas.upenn.edu/Archive/Graphics/A
+http://mt.seas.upenn.edu/Archive/Graphics/A3/A3.html :pre
+
+:link(atomeye,http://mt.seas.upenn.edu/Archive/Graphics/A)
+:link(atomeye3,http://mt.seas.upenn.edu/Archive/Graphics/A3/A3.html)
+
+The latter link is to AtomEye 3 which has the scriping
+capability needed by these Python scripts.
+
+Note that for PyMol, you need to have built and installed the
+open-source version of PyMol in your Python, so that you can import it
+from a Python script.  See the PyMol WWW pages "here"_pymolhome or
+"here"_pymolopen for more details:
+
+http://www.pymol.org
+http://sourceforge.net/scm/?type=svn&group_id=4546 :pre
+
+:link(pymolhome,http://www.pymol.org)
+:link(pymolopen,http://sourceforge.net/scm/?type=svn&group_id=4546)
+
+The latter link is to the open-source version.
+
+Note that for VMD, you need a fairly current version (1.8.7 works for
+me) and there are some lines in the pizza/vmd.py script for 4 PIZZA
+variables that have to match the VMD installation on your system.
+
+:line
+
+See the python/README file for instructions on how to run them and the
+source code for individual scripts for comments about what they do.
+
+Here are screenshots of the vizplotgui_tool.py script in action for
+different visualization package options.  Click to see larger images:
+
+:image(JPG/screenshot_gl_small.jpg,JPG/screenshot_gl.jpg)
+:image(JPG/screenshot_atomeye_small.jpg,JPG/screenshot_atomeye.jpg)
+:image(JPG/screenshot_pymol_small.jpg,JPG/screenshot_pymol.jpg)
+:image(JPG/screenshot_vmd_small.jpg,JPG/screenshot_vmd.jpg)
+
diff --git a/doc/src/Python_install.txt b/doc/src/Python_install.txt
new file mode 100644
index 0000000000000000000000000000000000000000..631f6c4a7f1a3a40245e3d7ab98b7b195bb4fefc
--- /dev/null
+++ b/doc/src/Python_install.txt
@@ -0,0 +1,74 @@
+"Higher level section"_Python.html - "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
+
+Installing LAMMPS in Python :h3
+
+For Python to invoke LAMMPS, there are 2 files it needs to know about:
+
+python/lammps.py
+src/liblammps.so :ul
+
+Lammps.py is the Python wrapper on the LAMMPS library interface.
+Liblammps.so is the shared LAMMPS library that Python loads, as
+described above.
+
+You can insure Python can find these files in one of two ways:
+
+set two environment variables
+run the python/install.py script :ul
+
+If you set the paths to these files as environment variables, you only
+have to do it once.  For the csh or tcsh shells, add something like
+this to your ~/.cshrc file, one line for each of the two files:
+
+setenv PYTHONPATH $\{PYTHONPATH\}:/home/sjplimp/lammps/python
+setenv LD_LIBRARY_PATH $\{LD_LIBRARY_PATH\}:/home/sjplimp/lammps/src :pre
+
+If you use the python/install.py script, you need to invoke it every
+time you rebuild LAMMPS (as a shared library) or make changes to the
+python/lammps.py file.
+
+You can invoke install.py from the python directory as
+
+% python install.py \[libdir\] \[pydir\] :pre
+
+The optional libdir is where to copy the LAMMPS shared library to; the
+default is /usr/local/lib.  The optional pydir is where to copy the
+lammps.py file to; the default is the site-packages directory of the
+version of Python that is running the install script.
+
+Note that libdir must be a location that is in your default
+LD_LIBRARY_PATH, like /usr/local/lib or /usr/lib.  And pydir must be a
+location that Python looks in by default for imported modules, like
+its site-packages dir.  If you want to copy these files to
+non-standard locations, such as within your own user space, you will
+need to set your PYTHONPATH and LD_LIBRARY_PATH environment variables
+accordingly, as above.
+
+If the install.py script does not allow you to copy files into system
+directories, prefix the python command with "sudo".  If you do this,
+make sure that the Python that root runs is the same as the Python you
+run.  E.g. you may need to do something like
+
+% sudo /usr/local/bin/python install.py \[libdir\] \[pydir\] :pre
+
+You can also invoke install.py from the make command in the src
+directory as
+
+% make install-python :pre
+
+In this mode you cannot append optional arguments.  Again, you may
+need to prefix this with "sudo".  In this mode you cannot control
+which Python is invoked by root.
+
+Note that if you want Python to be able to load different versions of
+the LAMMPS shared library (see "this section"_#py_5 below), you will
+need to manually copy files like liblammps_g++.so into the appropriate
+system directory.  This is not needed if you set the LD_LIBRARY_PATH
+environment variable as described above.
diff --git a/doc/src/Python_library.txt b/doc/src/Python_library.txt
new file mode 100644
index 0000000000000000000000000000000000000000..4babbb746cc3c1753f85ef6f5146dfdc51e8ee9a
--- /dev/null
+++ b/doc/src/Python_library.txt
@@ -0,0 +1,256 @@
+"Higher level section"_Python.html - "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
+
+Python library interface :h3
+
+As described previously, the Python interface to LAMMPS consists of a
+Python "lammps" module, the source code for which is in
+python/lammps.py, which creates a "lammps" object, with a set of
+methods that can be invoked on that object.  The sample Python code
+below assumes you have first imported the "lammps" module in your
+Python script, as follows:
+
+from lammps import lammps :pre
+
+These are the methods defined by the lammps module.  If you look at
+the files src/library.cpp and src/library.h you will see they
+correspond one-to-one with calls you can make to the LAMMPS library
+from a C++ or C or Fortran program, and which are described in
+"Section 6.19"_Section_howto.html#howto_19 of the manual.
+
+The python/examples directory has Python scripts which show how Python
+can run LAMMPS, grab data, change it, and put it back into LAMMPS.
+
+lmp = lammps()           # create a LAMMPS object using the default liblammps.so library
+                         # 4 optional args are allowed: name, cmdargs, ptr, comm
+lmp = lammps(ptr=lmpptr) # use lmpptr as previously created LAMMPS object
+lmp = lammps(comm=split) # create a LAMMPS object with a custom communicator, requires mpi4py 2.0.0 or later
+lmp = lammps(name="g++")   # create a LAMMPS object using the liblammps_g++.so library
+lmp = lammps(name="g++",cmdargs=list)    # add LAMMPS command-line args, e.g. list = \["-echo","screen"\] :pre
+
+lmp.close()              # destroy a LAMMPS object :pre
+
+version = lmp.version()  # return the numerical version id, e.g. LAMMPS 2 Sep 2015 -> 20150902 :pre
+
+lmp.file(file)           # run an entire input script, file = "in.lj"
+lmp.command(cmd)         # invoke a single LAMMPS command, cmd = "run 100"
+lmp.commands_list(cmdlist)     # invoke commands in cmdlist = ["run 10", "run 20"]
+lmp.commands_string(multicmd)  # invoke commands in multicmd = "run 10\nrun 20" :pre
+
+size = lmp.extract_setting(name)     # return data type info :pre
+
+xlo = lmp.extract_global(name,type)  # extract a global quantity
+                                     # name = "boxxlo", "nlocal", etc
+                                     # type = 0 = int
+                                     #        1 = double :pre
+
+boxlo,boxhi,xy,yz,xz,periodicity,box_change = lmp.extract_box()  # extract box info :pre
+
+coords = lmp.extract_atom(name,type)      # extract a per-atom quantity
+                                          # name = "x", "type", etc
+                                          # type = 0 = vector of ints
+                                          #        1 = array of ints
+                                          #        2 = vector of doubles
+                                          #        3 = array of doubles :pre
+
+eng = lmp.extract_compute(id,style,type)  # extract value(s) from a compute
+v3 = lmp.extract_fix(id,style,type,i,j)   # extract value(s) from a fix
+                                          # id = ID of compute or fix
+                                          # style = 0 = global data
+                                          #         1 = per-atom data
+                                          #         2 = local data
+                                          # type = 0 = scalar
+                                          #        1 = vector
+                                          #        2 = array
+                                          # i,j = indices of value in global vector or array :pre
+
+var = lmp.extract_variable(name,group,flag)  # extract value(s) from a variable
+                                             # name = name of variable
+                                             # group = group ID (ignored for equal-style variables)
+                                             # flag = 0 = equal-style variable
+                                             #        1 = atom-style variable :pre
+
+value = lmp.get_thermo(name)              # return current value of a thermo keyword
+natoms = lmp.get_natoms()                 # total # of atoms as int :pre
+
+flag = lmp.set_variable(name,value)       # set existing named string-style variable to value, flag = 0 if successful
+lmp.reset_box(boxlo,boxhi,xy,yz,xz)       # reset the simulation box size :pre
+
+data = lmp.gather_atoms(name,type,count)  # return per-atom property of all atoms gathered into data, ordered by atom ID
+                                          # name = "x", "charge", "type", etc
+data = lmp.gather_atoms_concat(name,type,count)  # ditto, but concatenated atom values from each proc (unordered)
+data = lmp.gather_atoms_subset(name,type,count,ndata,ids)  # ditto, but for subset of Ndata atoms with IDs :pre
+
+lmp.scatter_atoms(name,type,count,data)   # scatter per-atom property to all atoms from data, ordered by atom ID
+                                          # name = "x", "charge", "type", etc
+                                          # count = # of per-atom values, 1 or 3, etc :pre
+lmp.scatter_atoms_subset(name,type,count,ndata,ids,data)  # ditto, but for subset of Ndata atoms with IDs :pre
+
+lmp.create_atoms(n,ids,types,x,v,image,shrinkexceed)   # create N atoms with IDs, types, x, v, and image flags :pre
+
+:line
+
+The lines
+
+from lammps import lammps
+lmp = lammps() :pre
+
+create an instance of LAMMPS, wrapped in a Python class by the lammps
+Python module, and return an instance of the Python class as lmp.  It
+is used to make all subsequent calls to the LAMMPS library.
+
+Additional arguments to lammps() can be used to tell Python the name
+of the shared library to load or to pass arguments to the LAMMPS
+instance, the same as if LAMMPS were launched from a command-line
+prompt.
+
+If the ptr argument is set like this:
+
+lmp = lammps(ptr=lmpptr) :pre
+
+then lmpptr must be an argument passed to Python via the LAMMPS
+"python"_python.html command, when it is used to define a Python
+function that is invoked by the LAMMPS input script.  This mode of
+calling Python from LAMMPS is described in the "Python
+call"_Python_call.html doc page.  The variable lmpptr refers to the
+instance of LAMMPS that called the embedded Python interpreter.  Using
+it as an argument to lammps() allows the returned Python class
+instance "lmp" to make calls to that instance of LAMMPS.  See the
+"python"_python.html command doc page for examples using this syntax.
+
+Note that you can create multiple LAMMPS objects in your Python
+script, and coordinate and run multiple simulations, e.g.
+
+from lammps import lammps
+lmp1 = lammps()
+lmp2 = lammps()
+lmp1.file("in.file1")
+lmp2.file("in.file2") :pre
+
+The file(), command(), commands_list(), commands_string() methods
+allow an input script, a single command, or multiple commands to be
+invoked.
+
+The extract_setting(), extract_global(), extract_box(),
+extract_atom(), extract_compute(), extract_fix(), and
+extract_variable() methods return values or pointers to data
+structures internal to LAMMPS.
+
+For extract_global() see the src/library.cpp file for the list of
+valid names.  New names could easily be added.  A double or integer is
+returned.  You need to specify the appropriate data type via the type
+argument.
+
+For extract_atom(), a pointer to internal LAMMPS atom-based data is
+returned, which you can use via normal Python subscripting.  See the
+extract() method in the src/atom.cpp file for a list of valid names.
+Again, new names could easily be added if the property you want is not
+listed.  A pointer to a vector of doubles or integers, or a pointer to
+an array of doubles (double **) or integers (int **) is returned.  You
+need to specify the appropriate data type via the type argument.
+
+For extract_compute() and extract_fix(), the global, per-atom, or
+local data calculated by the compute or fix can be accessed.  What is
+returned depends on whether the compute or fix calculates a scalar or
+vector or array.  For a scalar, a single double value is returned.  If
+the compute or fix calculates a vector or array, a pointer to the
+internal LAMMPS data is returned, which you can use via normal Python
+subscripting.  The one exception is that for a fix that calculates a
+global vector or array, a single double value from the vector or array
+is returned, indexed by I (vector) or I and J (array).  I,J are
+zero-based indices.  The I,J arguments can be left out if not needed.
+See "Section 6.15"_Section_howto.html#howto_15 of the manual for a
+discussion of global, per-atom, and local data, and of scalar, vector,
+and array data types.  See the doc pages for individual
+"computes"_compute.html and "fixes"_fix.html for a description of what
+they calculate and store.
+
+For extract_variable(), an "equal-style or atom-style
+variable"_variable.html is evaluated and its result returned.
+
+For equal-style variables a single double value is returned and the
+group argument is ignored.  For atom-style variables, a vector of
+doubles is returned, one value per atom, which you can use via normal
+Python subscripting. The values will be zero for atoms not in the
+specified group.
+
+The get_thermo() method returns returns the current value of a thermo
+keyword as a float.
+
+The get_natoms() method returns the total number of atoms in the
+simulation, as an int.
+
+The set_variable() methosd sets an existing string-style variable to a
+new string value, so that subsequent LAMMPS commands can access the
+variable.
+
+The reset_box() emthods resets the size and shape of the simulation
+box, e.g. as part of restoring a previously extracted and saved state
+of a simulation.
+
+The gather methods collect peratom info of the requested type (atom
+coords, atom types, forces, etc) from all processors, and returns the
+same vector of values to each callling processor.  The scatter
+functions do the inverse.  They distribute a vector of peratom values,
+passed by all calling processors, to invididual atoms, which may be
+owned by different processos.
+
+Note that the data returned by the gather methods,
+e.g. gather_atoms("x"), is different from the data structure returned
+by extract_atom("x") in four ways.  (1) Gather_atoms() returns a
+vector which you index as x\[i\]; extract_atom() returns an array
+which you index as x\[i\]\[j\].  (2) Gather_atoms() orders the atoms
+by atom ID while extract_atom() does not.  (3) Gather_atoms() returns
+a list of all atoms in the simulation; extract_atoms() returns just
+the atoms local to each processor.  (4) Finally, the gather_atoms()
+data structure is a copy of the atom coords stored internally in
+LAMMPS, whereas extract_atom() returns an array that effectively
+points directly to the internal data.  This means you can change
+values inside LAMMPS from Python by assigning a new values to the
+extract_atom() array.  To do this with the gather_atoms() vector, you
+need to change values in the vector, then invoke the scatter_atoms()
+method.
+
+For the scatter methods, the array of coordinates passed to must be a
+ctypes vector of ints or doubles, allocated and initialized something
+like this:
+
+from ctypes import *
+natoms = lmp.get_natoms()
+n3 = 3*natoms
+x = (n3*c_double)()
+x\[0\] = x coord of atom with ID 1
+x\[1\] = y coord of atom with ID 1
+x\[2\] = z coord of atom with ID 1
+x\[3\] = x coord of atom with ID 2
+...
+x\[n3-1\] = z coord of atom with ID natoms
+lmp.scatter_atoms("x",1,3,x) :pre
+
+Alternatively, you can just change values in the vector returned by
+the gather methods, since they are also ctypes vectors.
+
+:line
+
+As noted above, these Python class methods correspond one-to-one with
+the functions in the LAMMPS library interface in src/library.cpp and
+library.h.  This means you can extend the Python wrapper via the
+following steps:
+
+Add a new interface function to src/library.cpp and
+src/library.h. :ulb,l
+
+Rebuild LAMMPS as a shared library. :l
+
+Add a wrapper method to python/lammps.py for this interface
+function. :l
+
+You should now be able to invoke the new interface function from a
+Python script. :l
+:ule
diff --git a/doc/src/Python_mpi.txt b/doc/src/Python_mpi.txt
new file mode 100644
index 0000000000000000000000000000000000000000..8377bbb3d0a0ac058c1f97274ba7fe7ba054b648
--- /dev/null
+++ b/doc/src/Python_mpi.txt
@@ -0,0 +1,67 @@
+"Higher level section"_Python.html - "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
+
+Extending Python to run in parallel :h3
+
+If you wish to run LAMMPS in parallel from Python, you need to extend
+your Python with an interface to MPI.  This also allows you to
+make MPI calls directly from Python in your script, if you desire.
+
+We recommend use of mpi4py:
+
+"PyPar"_https://github.com/daleroberts/pypar :ul
+
+As of version 2.0.0 it allows passing a custom MPI communicator to
+the LAMMPS constructor, which means one can easily run one or more
+LAMMPS instances on subsets of the total MPI ranks.
+
+To install mpi4py (version mpi4py-2.0.0 as of Oct 2015), unpack it
+and from its main directory, type
+
+python setup.py build
+sudo python setup.py install :pre
+
+Again, the "sudo" is only needed if required to copy mpi4py files into
+your Python distribution's site-packages directory. To install with
+user privilege into the user local directory type
+
+python setup.py install --user :pre
+
+If you have successfully installed mpi4py, you should be able to run
+Python and type
+
+from mpi4py import MPI :pre
+
+without error.  You should also be able to run python in parallel
+on a simple test script
+
+% mpirun -np 4 python test.py :pre
+
+where test.py contains the lines
+
+from mpi4py import MPI
+comm = MPI.COMM_WORLD
+print "Proc %d out of %d procs" % (comm.Get_rank(),comm.Get_size()) :pre
+
+and see one line of output for each processor you run on.
+
+NOTE: To use mpi4py and LAMMPS in parallel from Python, you must
+insure both are using the same version of MPI.  If you only have one
+MPI installed on your system, this is not an issue, but it can be if
+you have multiple MPIs.  Your LAMMPS build is explicit about which MPI
+it is using, since you specify the details in your lo-level
+src/MAKE/Makefile.foo file.  Mpi4py uses the "mpicc" command to find
+information about the MPI it uses to build against.  And it tries to
+load "libmpi.so" from the LD_LIBRARY_PATH.  This may or may not find
+the MPI library that LAMMPS is using.  If you have problems running
+both mpi4py and LAMMPS together, this is an issue you may need to
+address, e.g. by moving other MPI installations so that mpi4py finds
+the right one.
+
+
diff --git a/doc/src/Python_overview.txt b/doc/src/Python_overview.txt
new file mode 100644
index 0000000000000000000000000000000000000000..a5d6a469ffdaffddfe5347e1c5ecaec0be5257cb
--- /dev/null
+++ b/doc/src/Python_overview.txt
@@ -0,0 +1,35 @@
+"Previous Section"_Examples.html - "LAMMPS WWW Site"_lws -
+"LAMMPS Documentation"_ld - "LAMMPS Commands"_lc - "Next
+Section"_Tools.html :c
+
+:link(lws,http://lammps.sandia.gov)
+:link(ld,Manual.html)
+:link(lc,Commands.html#comm)
+
+:line
+
+Overview of Python and LAMMPS :h3
+
+LAMMPS can work together with Python in three ways.  First, Python can
+wrap LAMMPS through the its "library interface"_Howto_library.html, so
+that a Python script can create one or more instances of LAMMPS and
+launch one or more simulations.  In Python lingo, this is "extending"
+Python with LAMMPS.
+
+Second, a lower-level Python interface can be used indirectly through
+provided PyLammps and IPyLammps wrapper classes, written in Python.
+These wrappers try to simplify the usage of LAMMPS in Python by
+providing an object-based interface to common LAMMPS functionality.
+They also reduces the amount of code necessary to parameterize LAMMPS
+scripts through Python and make variables and computes directly
+accessible.
+
+Third, LAMMPS can use the Python interpreter, so that a LAMMPS
+input script can invoke Python code directly, and pass information
+back-and-forth between the input script and Python functions you
+write.  This Python code can also callback to LAMMPS to query or change
+its attributes.  In Python lingo, this is "embedding" Python in
+LAMMPS.  When used in this mode, Python can perform operations that
+the simple LAMMPS input script syntax cannot.
+
+
diff --git a/doc/src/Python_pylammps.txt b/doc/src/Python_pylammps.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ad5ed192ee669f0b14fcaa10ccd9097391e74f54
--- /dev/null
+++ b/doc/src/Python_pylammps.txt
@@ -0,0 +1,14 @@
+"Higher level section"_Python.html - "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
+
+PyLammps interface :h3
+
+PyLammps is a Python wrapper class which can be created on its own or
+use an existing lammps Python object.  It has its own "PyLammps
+Tutorial"_tutorial_pylammps.html doc page.
diff --git a/doc/src/Python_run.txt b/doc/src/Python_run.txt
new file mode 100644
index 0000000000000000000000000000000000000000..03ab2ed3d7dc3e6b4703c78950978323835c394d
--- /dev/null
+++ b/doc/src/Python_run.txt
@@ -0,0 +1,40 @@
+"Higher level section"_Python.html - "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
+
+Run LAMMPS from Python :h3
+
+The LAMMPS distribution includes a python directory with all you need
+to run LAMMPS from Python.  The python/lammps.py file wraps the LAMMPS
+library interface, with one wrapper function per LAMMPS library
+function.  This file makes it is possible to do the following either
+from a Python script, or interactively from a Python prompt: create
+one or more instances of LAMMPS, invoke LAMMPS commands or give it an
+input script, run LAMMPS incrementally, extract LAMMPS results, an
+modify internal LAMMPS variables.  From a Python script you can do
+this in serial or parallel.  Running Python interactively in parallel
+does not generally work, unless you have a version of Python that
+extends Python to enable multiple instances of Python to read what you
+type.
+
+To do all of this, you must first build LAMMPS as a shared library,
+then insure that your Python can find the python/lammps.py file and
+the shared library.
+
+Two advantages of using Python to run LAMMPS are how concise the
+language is, and that it can be run interactively, enabling rapid
+development and debugging.  If you use it to mostly invoke costly
+operations within LAMMPS, such as running a simulation for a
+reasonable number of timesteps, then the overhead cost of invoking
+LAMMPS thru Python will be negligible.
+
+The Python wrapper for LAMMPS uses the "ctypes" package in Python,
+which auto-generates the interface code needed between Python and a
+set of C-style library functions.  Ctypes is part of standard Python
+for versions 2.5 and later.  You can check which version of Python you
+have by simply typing "python" at a shell prompt.
diff --git a/doc/src/Python_shlib.txt b/doc/src/Python_shlib.txt
new file mode 100644
index 0000000000000000000000000000000000000000..1aafbe2e847e3b486f10b7991b85bbea9009d45b
--- /dev/null
+++ b/doc/src/Python_shlib.txt
@@ -0,0 +1,34 @@
+"Higher level section"_Python.html - "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
+
+Build LAMMPS as a shared library :h3
+
+Instructions on how to build LAMMPS as a shared library are given in
+"Section 2.4"_Section_start.html#start_4.  A shared library is one
+that is dynamically loadable, which is what Python requires to wrap
+LAMMPS.  On Linux this is a library file that ends in ".so", not ".a".
+
+From the src directory, type
+
+make foo mode=shlib :pre
+
+where foo is the machine target name, such as mpi or serial.
+This should create the file liblammps_foo.so in the src directory, as
+well as a soft link liblammps.so, which is what the Python wrapper will
+load by default.  Note that if you are building multiple machine
+versions of the shared library, the soft link is always set to the
+most recently built version.
+
+NOTE: If you are building LAMMPS with an MPI or FFT library or other
+auxiliary libraries (used by various packages), then all of these
+extra libraries must also be shared libraries.  If the LAMMPS
+shared-library build fails with an error complaining about this, see
+"Section 2.4"_Section_start.html#start_4 for more details.
+
+Also include CMake info on this
diff --git a/doc/src/Python_test.txt b/doc/src/Python_test.txt
new file mode 100644
index 0000000000000000000000000000000000000000..5f361a500b6c8ba12748fed18b61af3c81d9028b
--- /dev/null
+++ b/doc/src/Python_test.txt
@@ -0,0 +1,131 @@
+"Higher level section"_Python.html - "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
+
+Test the Python/LAMMPS interface :h3
+
+To test if LAMMPS is callable from Python, launch Python interactively
+and type:
+
+>>> from lammps import lammps
+>>> lmp = lammps() :pre
+
+If you get no errors, you're ready to use LAMMPS from Python.  If the
+2nd command fails, the most common error to see is
+
+OSError: Could not load LAMMPS dynamic library :pre
+
+which means Python was unable to load the LAMMPS shared library.  This
+typically occurs if the system can't find the LAMMPS shared library or
+one of the auxiliary shared libraries it depends on, or if something
+about the library is incompatible with your Python.  The error message
+should give you an indication of what went wrong.
+
+You can also test the load directly in Python as follows, without
+first importing from the lammps.py file:
+
+>>> from ctypes import CDLL
+>>> CDLL("liblammps.so") :pre
+
+If an error occurs, carefully go thru the steps in "Section
+2.4"_Section_start.html#start_4 and above about building a shared
+library and about insuring Python can find the necessary two files
+it needs.
+
+[Test LAMMPS and Python in serial:] :h4
+
+To run a LAMMPS test in serial, type these lines into Python
+interactively from the bench directory:
+
+>>> from lammps import lammps
+>>> lmp = lammps()
+>>> lmp.file("in.lj") :pre
+
+Or put the same lines in the file test.py and run it as
+
+% python test.py :pre
+
+Either way, you should see the results of running the in.lj benchmark
+on a single processor appear on the screen, the same as if you had
+typed something like:
+
+lmp_g++ -in in.lj :pre
+
+[Test LAMMPS and Python in parallel:] :h4
+
+To run LAMMPS in parallel, assuming you have installed the
+"PyPar"_https://github.com/daleroberts/pypar package as discussed
+above, create a test.py file containing these lines:
+
+import pypar
+from lammps import lammps
+lmp = lammps()
+lmp.file("in.lj")
+print "Proc %d out of %d procs has" % (pypar.rank(),pypar.size()),lmp
+pypar.finalize() :pre
+
+To run LAMMPS in parallel, assuming you have installed the
+"mpi4py"_https://bitbucket.org/mpi4py/mpi4py package as discussed
+above, create a test.py file containing these lines:
+
+from mpi4py import MPI
+from lammps import lammps
+lmp = lammps()
+lmp.file("in.lj")
+me = MPI.COMM_WORLD.Get_rank()
+nprocs = MPI.COMM_WORLD.Get_size()
+print "Proc %d out of %d procs has" % (me,nprocs),lmp
+MPI.Finalize() :pre
+
+You can either script in parallel as:
+
+% mpirun -np 4 python test.py :pre
+
+and you should see the same output as if you had typed
+
+% mpirun -np 4 lmp_g++ -in in.lj :pre
+
+Note that if you leave out the 3 lines from test.py that specify PyPar
+commands you will instantiate and run LAMMPS independently on each of
+the P processors specified in the mpirun command.  In this case you
+should get 4 sets of output, each showing that a LAMMPS run was made
+on a single processor, instead of one set of output showing that
+LAMMPS ran on 4 processors.  If the 1-processor outputs occur, it
+means that PyPar is not working correctly.
+
+Also note that once you import the PyPar module, PyPar initializes MPI
+for you, and you can use MPI calls directly in your Python script, as
+described in the PyPar documentation.  The last line of your Python
+script should be pypar.finalize(), to insure MPI is shut down
+correctly.
+
+[Running Python scripts:] :h4
+
+Note that any Python script (not just for LAMMPS) can be invoked in
+one of several ways:
+
+% python foo.script
+% python -i foo.script
+% foo.script :pre
+
+The last command requires that the first line of the script be
+something like this:
+
+#!/usr/local/bin/python
+#!/usr/local/bin/python -i :pre
+
+where the path points to where you have Python installed, and that you
+have made the script file executable:
+
+% chmod +x foo.script :pre
+
+Without the "-i" flag, Python will exit when the script finishes.
+With the "-i" flag, you will be left in the Python interpreter when
+the script finishes, so you can type subsequent commands.  As
+mentioned above, you can only run Python interactively when running
+Python on a single processor, not in parallel.
diff --git a/doc/src/Section_commands.txt b/doc/src/Section_commands.txt
index fa844b81cac9acfab6ce60d39cd7ca28ef7af398..7b9349a233e1d0d5decaca3885fec3ad58f23c0f 100644
--- a/doc/src/Section_commands.txt
+++ b/doc/src/Section_commands.txt
@@ -67,7 +67,7 @@ values are not desired, the "processors"_processors.html and
 tell LAMMPS how to map processors to the simulation box.
 
 Many input script errors are detected by LAMMPS and an ERROR or
-WARNING message is printed.  "This section"_Section_errors.html gives
+WARNING message is printed.  The "Errors"_Errors.html doc page gives
 more information on what errors mean.  The documentation for each
 command lists restrictions on how the command can be used.
 
@@ -204,10 +204,10 @@ allowed, but that should be sufficient for most use cases.
 3.3 Input script structure :h3,link(cmd_3)
 
 This section describes the structure of a typical LAMMPS input script.
-The "examples" directory in the LAMMPS distribution contains many
-sample input scripts; the corresponding problems are discussed in
-"Section 7"_Section_example.html, and animated on the "LAMMPS
-WWW Site"_lws.
+The examples directory in the LAMMPS distribution contains many sample
+input scripts; the corresponding problems are discussed on the
+"Examples"_Examples.html doc page, and animated on the "LAMMPS WWW
+Site"_lws.
 
 A LAMMPS input script typically has 4 parts:
 
@@ -678,6 +678,8 @@ USER-INTEL, k = KOKKOS, o = USER-OMP, t = OPT.
 "vector"_fix_vector.html,
 "viscosity"_fix_viscosity.html,
 "viscous"_fix_viscous.html,
+"wall/body/polygon"_fix_wall_body_polygon.html,
+"wall/body/polyhedron"_fix_wall_body_polyhedron.html,
 "wall/colloid"_fix_wall.html,
 "wall/gran"_fix_wall_gran.html,
 "wall/gran/region"_fix_wall_gran_region.html,
@@ -930,7 +932,9 @@ KOKKOS, o = USER-OMP, t = OPT.
 "airebo (oi)"_pair_airebo.html,
 "airebo/morse (oi)"_pair_airebo.html,
 "beck (go)"_pair_beck.html,
-"body"_pair_body.html,
+"body/nparticle"_pair_body_nparticle.html,
+"body/rounded/polygon"_pair_body_rounded/polygon.html,
+"body/rounded/polyhedron"_pair_body_rounded/polyhedron.html,
 "bop"_pair_bop.html,
 "born (go)"_pair_born.html,
 "born/coul/dsf"_pair_born.html,
diff --git a/doc/src/Section_history.txt b/doc/src/Section_history.txt
index 7b9041062855136866e909b7c37a451c41460256..6bbd1e4d99a8d02e89147b5a240f1479252c2940 100644
--- a/doc/src/Section_history.txt
+++ b/doc/src/Section_history.txt
@@ -1,4 +1,4 @@
-"Previous Section"_Section_errors.html - "LAMMPS WWW Site"_lws -
+"Previous Section"_Errors.html - "LAMMPS WWW Site"_lws -
 "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc - "Next
 Section"_Manual.html :c
 
diff --git a/doc/src/Section_howto.txt b/doc/src/Section_howto.txt
index 2784858f020dc3db8fccea6c4f04d4dc020b6080..3c5fe47057d3cbca85e60f0ffe7aab4fd0ecee56 100644
--- a/doc/src/Section_howto.txt
+++ b/doc/src/Section_howto.txt
@@ -1,4 +1,4 @@
-"Previous Section"_Section_accelerate.html - "LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc - "Next Section"_Section_example.html :c
+"Previous Section"_Section_accelerate.html - "LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc - "Next Section"_Examples.html :c
 
 :link(lws,http://lammps.sandia.gov)
 :link(ld,Manual.html)
@@ -40,7 +40,7 @@ This section describes how to perform common tasks using LAMMPS.
 6.28 "Magnetic spins"_#howto_28 :all(b)
 
 The example input scripts included in the LAMMPS distribution and
-highlighted in "Section 7"_Section_example.html also show how to
+highlighted on the "Examples"_Examples.html doc page also show how to
 setup and run various kinds of simulations.
 
 :line
@@ -188,9 +188,9 @@ used in the CHARMM, AMBER, and DREIDING force fields.  Setting
 coefficients is done in the input data file via the
 "read_data"_read_data.html command or in the input script with
 commands like "pair_coeff"_pair_coeff.html or
-"bond_coeff"_bond_coeff.html.  See "Section 9"_Section_tools.html
-for additional tools that can use CHARMM or AMBER to assign force
-field coefficients and convert their output into LAMMPS input.
+"bond_coeff"_bond_coeff.html.  See the "Tools"_Tools.html doc page for
+additional tools that can use CHARMM or AMBER to assign force field
+coefficients and convert their output into LAMMPS input.
 
 See "(MacKerell)"_#howto-MacKerell for a description of the CHARMM force
 field.  See "(Cornell)"_#howto-Cornell for a description of the AMBER force
@@ -672,10 +672,10 @@ 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
 "POEMS"_poems package that performs constrained rigid-body motion on
-groups of atoms is hooked to LAMMPS.  See the
-"fix poems"_fix_poems.html command for more details.  See "this
-section"_Section_modify.html of the documentation for info on how to add
-a new fix to LAMMPS.
+groups of atoms is hooked to LAMMPS.  See the "fix
+poems"_fix_poems.html command for more details.  See the
+"Modify"_Modify.html doc page for info on how to add a new fix to
+LAMMPS.
 
 :link(poems,http://www.rpi.edu/~anderk5/lab)
 
@@ -696,8 +696,8 @@ 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.
 
-See "Section 10"_Section_modify.html of the documentation for how
-to add a new command to LAMMPS.
+See the "Modify"_Modify.html doc page for how to add a new command to
+LAMMPS.
 
 (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
@@ -731,10 +731,10 @@ 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
-"Section 11"_Section_python.html of the manual for a description
-of the Python wrapper provided with LAMMPS that operates through the
-LAMMPS library interface.
+or Fortran you can make function calls to do the same things.  See the
+"Python"_Python.html doc page for a description of the Python wrapper
+provided with LAMMPS that operates through the LAMMPS library
+interface.
 
 The files src/library.cpp and library.h contain the C-style interface
 to LAMMPS.  See "Section 6.19"_Section_howto.html#howto_19 of the
@@ -762,12 +762,12 @@ simulations can be visualized (and analyzed) in a variety of ways.
 LAMMPS snapshots are created by the "dump"_dump.html 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 several popular visualization tools. The "dump image"_dump_image.html
-and "dump movie"_dump_image.html styles can output internally rendered
-images and convert a sequence of them to a movie during the MD run.
-Several programs included with LAMMPS as auxiliary tools can convert
-between LAMMPS format files and other formats.
-See the "Section 9"_Section_tools.html doc page for details.
+by several popular visualization tools. The "dump
+image"_dump_image.html and "dump movie"_dump_image.html styles can
+output internally rendered images and convert a sequence of them to a
+movie during the MD run.  Several programs included with LAMMPS as
+auxiliary tools can convert between LAMMPS format files and other
+formats.  See the "Tools"_Tools.html doc page for details.
 
 A Python-based toolkit distributed by our group can read native LAMMPS
 dump files, including custom dump files with additional columns of
@@ -1057,7 +1057,7 @@ rigid bodies composed of finite-size particles :ul
 
 Example input scripts for these kinds of models are in the body,
 colloid, dipole, ellipse, line, peri, pour, and tri directories of the
-"examples directory"_Section_example.html in the LAMMPS distribution.
+"examples directory"_Examples.html in the LAMMPS distribution.
 
 Atom styles :h4
 
@@ -1302,8 +1302,8 @@ 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 "add their own computes and fixes
-to LAMMPS"_Section_modify.html which can then generate values that can
-then be output with these commands.
+to LAMMPS"_Modify.html which can then generate values that can then be
+output with these commands.
 
 The following sub-sections discuss different LAMMPS command related
 to output and the kind of data they operate on and produce:
@@ -1824,8 +1824,8 @@ At zero temperature, it is easy to estimate these derivatives by
 deforming the simulation box in one of the six directions using the
 "change_box"_change_box.html 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 "this
-section"_Section_example.html.
+examples/elastic directory described on the "Examples"_Examples.html
+doc page.
 
 Calculating elastic constants at finite temperature is more
 challenging, because it is necessary to run a simulation that perfoms
@@ -1843,10 +1843,10 @@ converge and requires careful post-processing "(Shinoda)"_#Shinoda1
 
 6.19 Library interface to LAMMPS :link(howto_19),h4
 
-As described in "Section 2.5"_Section_start.html#start_5, LAMMPS
-can be built as a library, so that it can be called by another code,
-used in a "coupled manner"_Section_howto.html#howto_10 with other
-codes, or driven through a "Python interface"_Section_python.html.
+As described in "Section 2.5"_Section_start.html#start_5, LAMMPS can
+be built as a library, so that it can be called by another code, used
+in a "coupled manner"_Section_howto.html#howto_10 with other codes, or
+driven through a "Python interface"_Python.html.
 
 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
@@ -1869,9 +1869,9 @@ details.
 
 NOTE: You can write code for additional functions as needed to define
 how your code talks to LAMMPS and add them to src/library.cpp and
-src/library.h, as well as to the "Python
-interface"_Section_python.html.  The added functions can access or
-change any internal LAMMPS data you wish.
+src/library.h, as well as to the "Python interface"_Python.html.  The
+added functions can access or change any internal LAMMPS data you
+wish.
 
 void lammps_open(int, char **, MPI_Comm, void **)
 void lammps_open_no_mpi(int, char **, void **)
@@ -2322,11 +2322,10 @@ Note that this compute allows the per-atom output of other
 "computes"_compute.html, "fixes"_fix.html, and
 "variables"_variable.html to be used to define chunk IDs for each
 atom.  This means you can write your own compute or fix to output a
-per-atom quantity to use as chunk ID.  See
-"Section 10"_Section_modify.html of the documentation for how to
-do this.  You can also define a "per-atom variable"_variable.html in
-the input script that uses a formula to generate a chunk ID for each
-atom.
+per-atom quantity to use as chunk ID.  See the "Modify"_Modify.html
+doc page for how to do this.  You can also define a "per-atom
+variable"_variable.html in the input script that uses a formula to
+generate a chunk ID for each atom.
 
 Fix ave/chunk command: :h4
 
diff --git a/doc/src/Section_intro.txt b/doc/src/Section_intro.txt
index 67293b2ee3363b422cdb3f2f58bd0da9a037d9ab..c7cf5bf8d29bdb5e76b426ee16d9391f33684b14 100644
--- a/doc/src/Section_intro.txt
+++ b/doc/src/Section_intro.txt
@@ -1,4 +1,6 @@
-"Previous Section"_Manual.html - "LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc - "Next Section"_Section_start.html :c
+"Previous Section"_Manual.html - "LAMMPS WWW Site"_lws - "LAMMPS
+Documentation"_ld - "LAMMPS Commands"_lc - "Next
+Section"_Section_start.html :c
 
 :link(lws,http://lammps.sandia.gov)
 :link(ld,Manual.html)
@@ -54,8 +56,8 @@ brief discussion of the open-source philosophy.
 
 LAMMPS is designed to be easy to modify or extend with new
 capabilities, such as new force fields, atom types, boundary
-conditions, or diagnostics.  See "Section 10"_Section_modify.html
-for more details.
+conditions, or diagnostics.  See the "Modify"_Modify.html doc page for
+more details.
 
 The current version of LAMMPS is written in C++.  Earlier versions
 were written in F77 and F90.  See
@@ -94,8 +96,8 @@ LAMMPS are listed in "this section"_#intro_5.
 This section highlights LAMMPS features, with pointers to specific
 commands which give more details.  If LAMMPS doesn't have your
 favorite interatomic potential, boundary condition, or atom type, see
-"Section 10"_Section_modify.html, which describes how you can add
-it to LAMMPS.
+the "Modify"_Modify.html doc page, which describes how you can add it
+to LAMMPS.
 
 General features :h4
 
@@ -234,8 +236,8 @@ Multi-replica models :h4
 
 Pre- and post-processing :h4
 
-Various pre- and post-processing serial tools are packaged
-with LAMMPS; see these "doc pages"_Section_tools.html. :ulb,l
+Various pre- and post-processing serial tools are packaged with
+LAMMPS; see the "Tools"_Tools.html doc page for details. :ulb,l
 
 Our group has also written and released a separate toolkit called
 "Pizza.py"_pizza which provides tools for doing setup, analysis,
@@ -296,9 +298,9 @@ visualize your MD simulation
 plot your output data :ul
 
 A few tools for pre- and post-processing tasks are provided as part of
-the LAMMPS package; they are described in "this
-section"_Section_tools.html.  However, many people use other codes or
-write their own tools for these tasks.
+the LAMMPS package; they are described on the "Tools"_Tools.html doc
+page.  However, many people use other codes or write their own tools
+for these tasks.
 
 As noted above, our group has also written and released a separate
 toolkit called "Pizza.py"_pizza which addresses some of the listed
@@ -327,15 +329,15 @@ topology information and hundreds of force-field coefficients must
 typically be specified.  We suggest you use a program like
 "CHARMM"_charmm or "AMBER"_amber or other molecular builders to setup
 such problems and dump its information to a file.  You can then
-reformat the file as LAMMPS input.  Some of the tools in "this
-section"_Section_tools.html can assist in this process.
+reformat the file as LAMMPS input.  Some of the tools described on the
+"Tools"_Tools.html doc page can assist in this process.
 
 Similarly, LAMMPS creates output files in a simple format.  Most users
 post-process these files with their own analysis tools or re-format
 them for input into other programs, including visualization packages.
 If you are convinced you need to compute something on-the-fly as
-LAMMPS runs, see "Section 10"_Section_modify.html for a discussion
-of how you can use the "dump"_dump.html and "compute"_compute.html and
+LAMMPS runs, see the "Modify"_Modify.html doc page for a discussion of
+how you can use the "dump"_dump.html and "compute"_compute.html and
 "fix"_fix.html commands to print out data of your choosing.  Keep in
 mind that complicated computations can slow down the molecular
 dynamics timestepping, particularly if the computations are not
@@ -429,7 +431,7 @@ Site"_lws, or have a suggestion for something to clarify or include,
 send an email to the
 "developers"_http://lammps.sandia.gov/authors.html. :l
 
-If you find a bug, "Section 12.2"_Section_errors.html#err_2
+If you find a bug, the "Errors bugs"_Errors_bugs.html doc page
 describes how to report it. :l
 
 If you publish a paper using LAMMPS results, send the citation (and
@@ -442,15 +444,14 @@ directory. :l
 
 The tools sub-directory of the LAMMPS distribution has various
 stand-alone codes for pre- and post-processing of LAMMPS data.  More
-details are given in "Section 9"_Section_tools.html.  If you write
-a new tool that users will find useful, it can be added to the LAMMPS
+details are given on the "Tools"_Tools.html doc page.  If you write a
+new tool that users will find useful, it can be added to the LAMMPS
 distribution. :l
 
 LAMMPS is designed to be easy to extend with new code for features
 like potentials, boundary conditions, diagnostic computations, etc.
-"This section"_Section_modify.html gives details.  If you add a
-feature of general interest, it can be added to the LAMMPS
-distribution. :l
+The "Modify"_Modify.html doc page gives details.  If you add a feature
+of general interest, it can be added to the LAMMPS distribution. :l
 
 The Benchmark page of the "LAMMPS WWW Site"_lws lists LAMMPS
 performance on various platforms.  The files needed to run the
diff --git a/doc/src/Section_modify.txt b/doc/src/Section_modify.txt
deleted file mode 100644
index f1d55758c8b0b498710d2f9c2e83eb9834817481..0000000000000000000000000000000000000000
--- a/doc/src/Section_modify.txt
+++ /dev/null
@@ -1,827 +0,0 @@
- "Previous Section"_Section_tools.html - "LAMMPS WWW Site"_lws -
-"LAMMPS Documentation"_ld - "LAMMPS Commands"_lc - "Next
-Section"_Section_python.html :c
-
-:link(lws,http://lammps.sandia.gov)
-:link(ld,Manual.html)
-:link(lc,Section_commands.html#comm)
-
-:line
-
-10. Modifying & extending LAMMPS :h2
-
-This section describes how to customize LAMMPS by modifying
-and extending its source code.
-
-10.1 "Atom styles"_#mod_1
-10.2 "Bond, angle, dihedral, improper potentials"_#mod_2
-10.3 "Compute styles"_#mod_3
-10.4 "Dump styles"_#mod_4
-10.5 "Dump custom output options"_#mod_5
-10.6 "Fix styles"_#mod_6 which include integrators, \
-     temperature and pressure control, force constraints, \
-     boundary conditions, diagnostic output, etc
-10.7 "Input script commands"_#mod_7
-10.8 "Kspace computations"_#mod_8
-10.9 "Minimization styles"_#mod_9
-10.10 "Pairwise potentials"_#mod_10
-10.11 "Region styles"_#mod_11
-10.12 "Body styles"_#mod_12
-10.13 "Thermodynamic output options"_#mod_13
-10.14 "Variable options"_#mod_14
-10.15 "Submitting new features for inclusion in LAMMPS"_#mod_15 :all(b)
-
-LAMMPS is designed in a modular fashion so as to be easy to modify and
-extend with new functionality.  In fact, about 75% of its source code
-is files added in this fashion.
-
-In this section, changes and additions users can make are listed along
-with minimal instructions.  If you add a new feature to LAMMPS and
-think it will be of interest to general users, we encourage you to
-submit it to the developers for inclusion in the released version of
-LAMMPS.  Information about how to do this is provided
-"below"_#mod_14.
-
-The best way to add a new feature is to find a similar feature in
-LAMMPS and look at the corresponding source and header files to figure
-out what it does.  You will need some knowledge of C++ to be able to
-understand the hi-level structure of LAMMPS and its class
-organization, but functions (class methods) that do actual
-computations are written in vanilla C-style code and operate on simple
-C-style data structures (vectors and arrays).
-
-Most of the new features described in this section require you to
-write a new C++ derived class (except for exceptions described below,
-where you can make small edits to existing files).  Creating a new
-class requires 2 files, a source code file (*.cpp) and a header file
-(*.h).  The derived class must provide certain methods to work as a
-new option.  Depending on how different your new feature is compared
-to existing features, you can either derive from the base class
-itself, or from a derived class that already exists.  Enabling LAMMPS
-to invoke the new class is as simple as putting the two source
-files in the src dir and re-building LAMMPS.
-
-The advantage of C++ and its object-orientation is that all the code
-and variables needed to define the new feature are in the 2 files you
-write, and thus shouldn't make the rest of LAMMPS more complex or
-cause side-effect bugs.
-
-Here is a concrete example.  Suppose you write 2 files pair_foo.cpp
-and pair_foo.h that define a new class PairFoo that computes pairwise
-potentials described in the classic 1997 "paper"_#Foo by Foo, et al.
-If you wish to invoke those potentials in a LAMMPS input script with a
-command like
-
-pair_style foo 0.1 3.5 :pre
-
-then your pair_foo.h file should be structured as follows:
-
-#ifdef PAIR_CLASS
-PairStyle(foo,PairFoo)
-#else
-...
-(class definition for PairFoo)
-...
-#endif :pre
-
-where "foo" is the style keyword in the pair_style command, and
-PairFoo is the class name defined in your pair_foo.cpp and pair_foo.h
-files.
-
-When you re-build LAMMPS, your new pairwise potential becomes part of
-the executable and can be invoked with a pair_style command like the
-example above.  Arguments like 0.1 and 3.5 can be defined and
-processed by your new class.
-
-As illustrated by this pairwise example, many kinds of options are
-referred to in the LAMMPS documentation as the "style" of a particular
-command.
-
-The instructions below give the header file for the base class that
-these styles are derived from.  Public variables in that file are ones
-used and set by the derived classes which are also used by the base
-class.  Sometimes they are also used by the rest of LAMMPS.  Virtual
-functions in the base class header file which are set = 0 are ones you
-must define in your new derived class to give it the functionality
-LAMMPS expects.  Virtual functions that are not set to 0 are functions
-you can optionally define.
-
-Additionally, new output options can be added directly to the
-thermo.cpp, dump_custom.cpp, and variable.cpp files as explained
-below.
-
-Here are additional guidelines for modifying LAMMPS and adding new
-functionality:
-
-Think about whether what you want to do would be better as a pre- or
-post-processing step.  Many computations are more easily and more
-quickly done that way. :ulb,l
-
-Don't do anything within the timestepping of a run that isn't
-parallel.  E.g. don't accumulate a bunch of data on a single processor
-and analyze it.  You run the risk of seriously degrading the parallel
-efficiency. :l
-
-If your new feature reads arguments or writes output, make sure you
-follow the unit conventions discussed by the "units"_units.html
-command. :l
-
-If you add something you think is truly useful and doesn't impact
-LAMMPS performance when it isn't used, send an email to the
-"developers"_http://lammps.sandia.gov/authors.html.  We might be
-interested in adding it to the LAMMPS distribution.  See further
-details on this at the bottom of this page. :l
-:ule
-
-:line
-:line
-
-10.1 Atom styles :link(mod_1),h4
-
-Classes that define an "atom style"_atom_style.html are derived from
-the AtomVec class and managed by the Atom class.  The atom style
-determines what attributes are associated with an atom.  A new atom
-style can be created if one of the existing atom styles does not
-define all the attributes you need to store and communicate with
-atoms.
-
-Atom_vec_atomic.cpp is a simple example of an atom style.
-
-Here is a brief description of methods you define in your new derived
-class.  See atom_vec.h for details.
-
-init: one time setup (optional)
-grow: re-allocate atom arrays to longer lengths (required)
-grow_reset: make array pointers in Atom and AtomVec classes consistent (required)
-copy: copy info for one atom to another atom's array locations (required)
-pack_comm: store an atom's info in a buffer communicated every timestep (required)
-pack_comm_vel: add velocity info to communication buffer (required)
-pack_comm_hybrid: store extra info unique to this atom style (optional)
-unpack_comm: retrieve an atom's info from the buffer (required)
-unpack_comm_vel: also retrieve velocity info (required)
-unpack_comm_hybrid: retrieve extra info unique to this atom style (optional)
-pack_reverse: store an atom's info in a buffer communicating partial forces  (required)
-pack_reverse_hybrid: store extra info unique to this atom style (optional)
-unpack_reverse: retrieve an atom's info from the buffer (required)
-unpack_reverse_hybrid: retrieve extra info unique to this atom style (optional)
-pack_border: store an atom's info in a buffer communicated on neighbor re-builds (required)
-pack_border_vel: add velocity info to buffer (required)
-pack_border_hybrid: store extra info unique to this atom style (optional)
-unpack_border: retrieve an atom's info from the buffer (required)
-unpack_border_vel: also retrieve velocity info (required)
-unpack_border_hybrid: retrieve extra info unique to this atom style (optional)
-pack_exchange: store all an atom's info to migrate to another processor (required)
-unpack_exchange: retrieve an atom's info from the buffer (required)
-size_restart: number of restart quantities associated with proc's atoms (required)
-pack_restart: pack atom quantities into a buffer (required)
-unpack_restart: unpack atom quantities from a buffer (required)
-create_atom: create an individual atom of this style (required)
-data_atom: parse an atom line from the data file (required)
-data_atom_hybrid: parse additional atom info unique to this atom style (optional)
-data_vel: parse one line of velocity information from data file (optional)
-data_vel_hybrid: parse additional velocity data unique to this atom style (optional)
-memory_usage: tally memory allocated by atom arrays (required) :tb(s=:)
-
-The constructor of the derived class sets values for several variables
-that you must set when defining a new atom style, which are documented
-in atom_vec.h.  New atom arrays are defined in atom.cpp.  Search for
-the word "customize" and you will find locations you will need to
-modify.
-
-NOTE: It is possible to add some attributes, such as a molecule ID, to
-atom styles that do not have them via the "fix
-property/atom"_fix_property_atom.html command.  This command also
-allows new custom attributes consisting of extra integer or
-floating-point values to be added to atoms.  See the "fix
-property/atom"_fix_property_atom.html doc page for examples of cases
-where this is useful and details on how to initialize, access, and
-output the custom values.
-
-New "pair styles"_pair_style.html, "fixes"_fix.html, or
-"computes"_compute.html can be added to LAMMPS, as discussed below.
-The code for these classes can use the per-atom properties defined by
-fix property/atom.  The Atom class has a find_custom() method that is
-useful in this context:
-
-int index = atom->find_custom(char *name, int &flag); :pre
-
-The "name" of a custom attribute, as specified in the "fix
-property/atom"_fix_property_atom.html command, is checked to verify
-that it exists and its index is returned.  The method also sets flag =
-0/1 depending on whether it is an integer or floating-point attribute.
-The vector of values associated with the attribute can then be
-accessed using the returned index as
-
-int *ivector = atom->ivector\[index\];
-double *dvector = atom->dvector\[index\]; :pre
-
-Ivector or dvector are vectors of length Nlocal = # of owned atoms,
-which store the attributes of individual atoms.
-
-:line
-
-10.2 Bond, angle, dihedral, improper potentials :link(mod_2),h4
-
-Classes that compute molecular interactions are derived from the Bond,
-Angle, Dihedral, and Improper classes.  New styles can be created to
-add new potentials to LAMMPS.
-
-Bond_harmonic.cpp is the simplest example of a bond style.  Ditto for
-the harmonic forms of the angle, dihedral, and improper style
-commands.
-
-Here is a brief description of common methods you define in your
-new derived class.  See bond.h, angle.h, dihedral.h, and improper.h
-for details and specific additional methods.
-
-init: check if all coefficients are set, calls {init_style} (optional)
-init_style: check if style specific conditions are met (optional)
-compute: compute the molecular interactions (required)
-settings: apply global settings for all types (optional)
-coeff: set coefficients for one type (required)
-equilibrium_distance: length of bond, used by SHAKE (required, bond only)
-equilibrium_angle: opening of angle, used by SHAKE (required, angle only)
-write & read_restart: writes/reads coeffs to restart files (required)
-single: force and energy of a single bond or angle (required, bond or angle only)
-memory_usage: tally memory allocated by the style (optional) :tb(s=:)
-
-:line
-
-10.3 Compute styles :link(mod_3),h4
-
-Classes that compute scalar and vector quantities like temperature
-and the pressure tensor, as well as classes that compute per-atom
-quantities like kinetic energy and the centro-symmetry parameter
-are derived from the Compute class.  New styles can be created
-to add new calculations to LAMMPS.
-
-Compute_temp.cpp is a simple example of computing a scalar
-temperature.  Compute_ke_atom.cpp is a simple example of computing
-per-atom kinetic energy.
-
-Here is a brief description of methods you define in your new derived
-class.  See compute.h for details.
-
-init: perform one time setup (required)
-init_list: neighbor list setup, if needed (optional)
-compute_scalar: compute a scalar quantity (optional)
-compute_vector: compute a vector of quantities (optional)
-compute_peratom: compute one or more quantities per atom (optional)
-compute_local: compute one or more quantities per processor (optional)
-pack_comm: pack a buffer with items to communicate (optional)
-unpack_comm: unpack the buffer (optional)
-pack_reverse: pack a buffer with items to reverse communicate (optional)
-unpack_reverse: unpack the buffer (optional)
-remove_bias: remove velocity bias from one atom (optional)
-remove_bias_all: remove velocity bias from all atoms in group (optional)
-restore_bias: restore velocity bias for one atom after remove_bias (optional)
-restore_bias_all: same as before, but for all atoms in group (optional)
-pair_tally_callback: callback function for {tally}-style computes (optional).
-memory_usage: tally memory usage (optional) :tb(s=:)
-
-Tally-style computes are a special case, as their computation is done
-in two stages: the callback function is registered with the pair style
-and then called from the Pair::ev_tally() function, which is called for
-each pair after force and energy has been computed for this pair. Then
-the tallied values are retrieved with the standard compute_scalar or
-compute_vector or compute_peratom methods. The USER-TALLY package
-provides {examples}_compute_tally.html for utilizing this mechanism.
-
-:line
-
-10.4 Dump styles :link(mod_4),h4
-10.5 Dump custom output options :link(mod_5),h4
-
-Classes that dump per-atom info to files are derived from the Dump
-class.  To dump new quantities or in a new format, a new derived dump
-class can be added, but it is typically simpler to modify the
-DumpCustom class contained in the dump_custom.cpp file.
-
-Dump_atom.cpp is a simple example of a derived dump class.
-
-Here is a brief description of methods you define in your new derived
-class.  See dump.h for details.
-
-write_header: write the header section of a snapshot of atoms
-count: count the number of lines a processor will output
-pack: pack a proc's output data into a buffer
-write_data: write a proc's data to a file :tb(s=:)
-
-See the "dump"_dump.html command and its {custom} style for a list of
-keywords for atom information that can already be dumped by
-DumpCustom.  It includes options to dump per-atom info from Compute
-classes, so adding a new derived Compute class is one way to calculate
-new quantities to dump.
-
-Alternatively, you can add new keywords to the dump custom command.
-Search for the word "customize" in dump_custom.cpp to see the
-half-dozen or so locations where code will need to be added.
-
-:line
-
-10.6 Fix styles :link(mod_6),h4
-
-In LAMMPS, a "fix" is any operation that is computed during
-timestepping that alters some property of the system.  Essentially
-everything that happens during a simulation besides force computation,
-neighbor list construction, and output, is a "fix".  This includes
-time integration (update of coordinates and velocities), force
-constraints or boundary conditions (SHAKE or walls), and diagnostics
-(compute a diffusion coefficient).  New styles can be created to add
-new options to LAMMPS.
-
-Fix_setforce.cpp is a simple example of setting forces on atoms to
-prescribed values.  There are dozens of fix options already in LAMMPS;
-choose one as a template that is similar to what you want to
-implement.
-
-Here is a brief description of methods you can define in your new
-derived class.  See fix.h for details.
-
-setmask: determines when the fix is called during the timestep (required)
-init: initialization before a run (optional)
-setup_pre_exchange: called before atom exchange in setup (optional)
-setup_pre_force: called before force computation in setup (optional)
-setup: called immediately before the 1st timestep and after forces are computed (optional)
-min_setup_pre_force: like setup_pre_force, but for minimizations instead of MD runs (optional)
-min_setup: like setup, but for minimizations instead of MD runs (optional)
-initial_integrate: called at very beginning of each timestep (optional)
-pre_exchange: called before atom exchange on re-neighboring steps (optional)
-pre_neighbor: called before neighbor list build (optional)
-pre_force: called before pair & molecular forces are computed (optional)
-post_force: called after pair & molecular forces are computed and communicated (optional)
-final_integrate: called at end of each timestep (optional)
-end_of_step: called at very end of timestep (optional)
-write_restart: dumps fix info to restart file (optional)
-restart: uses info from restart file to re-initialize the fix (optional)
-grow_arrays: allocate memory for atom-based arrays used by fix (optional)
-copy_arrays: copy atom info when an atom migrates to a new processor (optional)
-pack_exchange: store atom's data in a buffer (optional)
-unpack_exchange: retrieve atom's data from a buffer (optional)
-pack_restart: store atom's data for writing to restart file (optional)
-unpack_restart: retrieve atom's data from a restart file buffer (optional)
-size_restart: size of atom's data (optional)
-maxsize_restart: max size of atom's data (optional)
-setup_pre_force_respa: same as setup_pre_force, but for rRESPA (optional)
-initial_integrate_respa: same as initial_integrate, but for rRESPA (optional)
-post_integrate_respa: called after the first half integration step is done in rRESPA (optional)
-pre_force_respa: same as pre_force, but for rRESPA (optional)
-post_force_respa: same as post_force, but for rRESPA (optional)
-final_integrate_respa: same as final_integrate, but for rRESPA (optional)
-min_pre_force: called after pair & molecular forces are computed in minimizer (optional)
-min_post_force: called after pair & molecular forces are computed and communicated in minimizer (optional)
-min_store: store extra data for linesearch based minimization on a LIFO stack (optional)
-min_pushstore: push the minimization LIFO stack one element down (optional)
-min_popstore: pop the minimization LIFO stack one element up (optional)
-min_clearstore: clear minimization LIFO stack (optional)
-min_step: reset or move forward on line search minimization (optional)
-min_dof: report number of degrees of freedom {added} by this fix in minimization (optional)
-max_alpha: report maximum allowed step size during linesearch minimization (optional)
-pack_comm: pack a buffer to communicate a per-atom quantity (optional)
-unpack_comm: unpack a buffer to communicate a per-atom quantity (optional)
-pack_reverse_comm: pack a buffer to reverse communicate a per-atom quantity (optional)
-unpack_reverse_comm: unpack a buffer to reverse communicate a per-atom quantity (optional)
-dof: report number of degrees of freedom {removed} by this fix during MD (optional)
-compute_scalar: return a global scalar property that the fix computes (optional)
-compute_vector: return a component of a vector property that the fix computes (optional)
-compute_array: return a component of an array property that the fix computes (optional)
-deform: called when the box size is changed (optional)
-reset_target: called when a change of the target temperature is requested during a run (optional)
-reset_dt: is called when a change of the time step is requested during a run (optional)
-modify_param: called when a fix_modify request is executed (optional)
-memory_usage: report memory used by fix (optional)
-thermo: compute quantities for thermodynamic output (optional) :tb(s=:)
-
-Typically, only a small fraction of these methods are defined for a
-particular fix.  Setmask is mandatory, as it determines when the fix
-will be invoked during the timestep.  Fixes that perform time
-integration ({nve}, {nvt}, {npt}) implement initial_integrate() and
-final_integrate() to perform velocity Verlet updates.  Fixes that
-constrain forces implement post_force().
-
-Fixes that perform diagnostics typically implement end_of_step().  For
-an end_of_step fix, one of your fix arguments must be the variable
-"nevery" which is used to determine when to call the fix and you must
-set this variable in the constructor of your fix.  By convention, this
-is the first argument the fix defines (after the ID, group-ID, style).
-
-If the fix needs to store information for each atom that persists from
-timestep to timestep, it can manage that memory and migrate the info
-with the atoms as they move from processors to processor by
-implementing the grow_arrays, copy_arrays, pack_exchange, and
-unpack_exchange methods.  Similarly, the pack_restart and
-unpack_restart methods can be implemented to store information about
-the fix in restart files.  If you wish an integrator or force
-constraint fix to work with rRESPA (see the "run_style"_run_style.html
-command), the initial_integrate, post_force_integrate, and
-final_integrate_respa methods can be implemented.  The thermo method
-enables a fix to contribute values to thermodynamic output, as printed
-quantities and/or to be summed to the potential energy of the system.
-
-:line
-
-10.7 Input script commands :link(mod_7),h4
-
-New commands can be added to LAMMPS input scripts by adding new
-classes that have a "command" method.  For example, the create_atoms,
-read_data, velocity, and run commands are all implemented in this
-fashion.  When such a command is encountered in the LAMMPS input
-script, LAMMPS simply creates a class with the corresponding name,
-invokes the "command" method of the class, and passes it the arguments
-from the input script.  The command method can perform whatever
-operations it wishes on LAMMPS data structures.
-
-The single method your new class must define is as follows:
-
-command: operations performed by the new command :tb(s=:)
-
-Of course, the new class can define other methods and variables as
-needed.
-
-:line
-
-10.8 Kspace computations :link(mod_8),h4
-
-Classes that compute long-range Coulombic interactions via K-space
-representations (Ewald, PPPM) are derived from the KSpace class.  New
-styles can be created to add new K-space options to LAMMPS.
-
-Ewald.cpp is an example of computing K-space interactions.
-
-Here is a brief description of methods you define in your new derived
-class.  See kspace.h for details.
-
-init: initialize the calculation before a run
-setup: computation before the 1st timestep of a run
-compute: every-timestep computation
-memory_usage: tally of memory usage :tb(s=:)
-
-:line
-
-10.9 Minimization styles :link(mod_9),h4
-
-Classes that perform energy minimization derived from the Min class.
-New styles can be created to add new minimization algorithms to
-LAMMPS.
-
-Min_cg.cpp is an example of conjugate gradient minimization.
-
-Here is a brief description of methods you define in your new derived
-class.  See min.h for details.
-
-init: initialize the minimization before a run
-run: perform the minimization
-memory_usage: tally of memory usage :tb(s=:)
-
-:line
-
-10.10 Pairwise potentials :link(mod_10),h4
-
-Classes that compute pairwise interactions are derived from the Pair
-class.  In LAMMPS, pairwise calculation include manybody potentials
-such as EAM or Tersoff where particles interact without a static bond
-topology.  New styles can be created to add new pair potentials to
-LAMMPS.
-
-Pair_lj_cut.cpp is a simple example of a Pair class, though it
-includes some optional methods to enable its use with rRESPA.
-
-Here is a brief description of the class methods in pair.h:
-
-compute: workhorse routine that computes pairwise interactions
-settings: reads the input script line with arguments you define
-coeff: set coefficients for one i,j type pair
-init_one: perform initialization for one i,j type pair
-init_style: initialization specific to this pair style
-write & read_restart: write/read i,j pair coeffs to restart files
-write & read_restart_settings: write/read global settings to restart files
-single: force and energy of a single pairwise interaction between 2 atoms
-compute_inner/middle/outer: versions of compute used by rRESPA :tb(s=:)
-
-The inner/middle/outer routines are optional.
-
-:line
-
-10.11 Region styles :link(mod_11),h4
-
-Classes that define geometric regions are derived from the Region
-class.  Regions are used elsewhere in LAMMPS to group atoms, delete
-atoms to create a void, insert atoms in a specified region, etc.  New
-styles can be created to add new region shapes to LAMMPS.
-
-Region_sphere.cpp is an example of a spherical region.
-
-Here is a brief description of methods you define in your new derived
-class.  See region.h for details.
-
-inside: determine whether a point is in the region
-surface_interior: determine if a point is within a cutoff distance inside of surc
-surface_exterior: determine if a point is within a cutoff distance outside of surf
-shape_update : change region shape if set by time-dependent variable :tb(s=:)
-
-:line
-
-10.12 Body styles :link(mod_12),h4
-
-Classes that define body particles are derived from the Body class.
-Body particles can represent complex entities, such as surface meshes
-of discrete points, collections of sub-particles, deformable objects,
-etc.
-
-See "Section 6.14"_Section_howto.html#howto_14 of the manual for
-an overview of using body particles and the "body"_body.html doc page
-for details on the various body styles LAMMPS supports.  New styles
-can be created to add new kinds of body particles to LAMMPS.
-
-Body_nparticle.cpp is an example of a body particle that is treated as
-a rigid body containing N sub-particles.
-
-Here is a brief description of methods you define in your new derived
-class.  See body.h for details.
-
-data_body: process a line from the Bodies section of a data file
-noutrow: number of sub-particles output is generated for
-noutcol: number of values per-sub-particle output is generated for
-output: output values for the Mth sub-particle
-pack_comm_body: body attributes to communicate every timestep
-unpack_comm_body: unpacking of those attributes
-pack_border_body: body attributes to communicate when reneighboring is done
-unpack_border_body: unpacking of those attributes :tb(s=:)
-
-:line
-
-10.13 Thermodynamic output options :link(mod_13),h4
-
-There is one class that computes and prints thermodynamic information
-to the screen and log file; see the file thermo.cpp.
-
-There are two styles defined in thermo.cpp: "one" and "multi".  There
-is also a flexible "custom" style which allows the user to explicitly
-list keywords for quantities to print when thermodynamic info is
-output.  See the "thermo_style"_thermo_style.html command for a list
-of defined quantities.
-
-The thermo styles (one, multi, etc) are simply lists of keywords.
-Adding a new style thus only requires defining a new list of keywords.
-Search for the word "customize" with references to "thermo style" in
-thermo.cpp to see the two locations where code will need to be added.
-
-New keywords can also be added to thermo.cpp to compute new quantities
-for output.  Search for the word "customize" with references to
-"keyword" in thermo.cpp to see the several locations where code will
-need to be added.
-
-Note that the "thermo_style custom"_thermo.html command already allows
-for thermo output of quantities calculated by "fixes"_fix.html,
-"computes"_compute.html, and "variables"_variable.html.  Thus, it may
-be simpler to compute what you wish via one of those constructs, than
-by adding a new keyword to the thermo command.
-
-:line
-
-10.14 Variable options :link(mod_14),h4
-
-There is one class that computes and stores "variable"_variable.html
-information in LAMMPS; see the file variable.cpp.  The value
-associated with a variable can be periodically printed to the screen
-via the "print"_print.html, "fix print"_fix_print.html, or
-"thermo_style custom"_thermo_style.html commands.  Variables of style
-"equal" can compute complex equations that involve the following types
-of arguments:
-
-thermo keywords = ke, vol, atoms, ...
-other variables = v_a, v_myvar, ...
-math functions = div(x,y), mult(x,y), add(x,y), ...
-group functions = mass(group), xcm(group,x), ...
-atom values = x\[123\], y\[3\], vx\[34\], ...
-compute values = c_mytemp\[0\], c_thermo_press\[3\], ... :pre
-
-Adding keywords for the "thermo_style custom"_thermo_style.html command
-(which can then be accessed by variables) was discussed
-"here"_Section_modify.html#mod_13 on this page.
-
-Adding a new math function of one or two arguments can be done by
-editing one section of the Variable::evaluate() method.  Search for
-the word "customize" to find the appropriate location.
-
-Adding a new group function can be done by editing one section of the
-Variable::evaluate() method.  Search for the word "customize" to find
-the appropriate location.  You may need to add a new method to the
-Group class as well (see the group.cpp file).
-
-Accessing a new atom-based vector can be done by editing one section
-of the Variable::evaluate() method.  Search for the word "customize"
-to find the appropriate location.
-
-Adding new "compute styles"_compute.html (whose calculated values can
-then be accessed by variables) was discussed
-"here"_Section_modify.html#mod_3 on this page.
-
-:line
-:line
-
-10.15 Submitting new features for inclusion in LAMMPS :link(mod_15),h4
-
-We encourage users to submit new features or modifications for
-LAMMPS to "the core developers"_http://lammps.sandia.gov/authors.html
-so they can be added to the LAMMPS distribution. The preferred way to
-manage and coordinate this is as of Fall 2016 via the LAMMPS project on
-"GitHub"_https://github.com/lammps/lammps. An alternative is to contact
-the LAMMPS developers or the indicated developer of a package or feature
-directly and send in your contribution via e-mail.
-
-For any larger modifications or programming project, you are encouraged
-to contact the LAMMPS developers ahead of time, in order to discuss
-implementation strategies and coding guidelines, that will make it
-easier to integrate your contribution and result in less work for
-everybody involved. You are also encouraged to search through the list
-of "open issues on GitHub"_https://github.com/lammps/lammps/issues and
-submit a new issue for a planned feature, so you would not duplicate
-the work of others (and possibly get scooped by them) or have your work
-duplicated by others.
-
-How quickly your contribution will be integrated
-depends largely on how much effort it will cause to integrate and test
-it, how much it requires changes to the core codebase, and of how much
-interest it is to the larger LAMMPS community.  Please see below for a
-checklist of typical requirements. Once you have prepared everything,
-see "this tutorial"_tutorial_github.html for instructions on how to
-submit your changes or new files through a GitHub pull request. If you
-prefer to submit patches or full files, you should first make certain,
-that your code works correctly with the latest patch-level version of
-LAMMPS and contains all bugfixes from it. Then create a gzipped tar
-file of all changed or added files or a corresponding patch file using
-'diff -u' or 'diff -c' and compress it with gzip. Please only use
-gzip compression, as this works well on all platforms.
-
-If the new features/files are broadly useful we may add them as core
-files to LAMMPS or as part of a "standard
-package"_Section_start.html#start_3.  Else we will add them as a
-user-contributed file or package.  Examples of user packages are in
-src sub-directories that start with USER.  The USER-MISC package is
-simply a collection of (mostly) unrelated single files, which is the
-simplest way to have your contribution quickly added to the LAMMPS
-distribution.  You can see a list of the both standard and user
-packages by typing "make package" in the LAMMPS src directory.
-
-Note that by providing us files to release, you are agreeing to make
-them open-source, i.e. we can release them under the terms of the GPL,
-used as a license for the rest of LAMMPS.  See "Section
-1.4"_Section_intro.html#intro_4 for details.
-
-With user packages and files, all we are really providing (aside from
-the fame and fortune that accompanies having your name in the source
-code and on the "Authors page"_http://lammps.sandia.gov/authors.html
-of the "LAMMPS WWW site"_lws), is a means for you to distribute your
-work to the LAMMPS user community, and a mechanism for others to
-easily try out your new feature.  This may help you find bugs or make
-contact with new collaborators.  Note that you're also implicitly
-agreeing to support your code which means answer questions, fix bugs,
-and maintain it if LAMMPS changes in some way that breaks it (an
-unusual event).
-
-NOTE: If you prefer to actively develop and support your add-on
-feature yourself, then you may wish to make it available for download
-from your own website, as a user package that LAMMPS users can add to
-their copy of LAMMPS.  See the "Offsite LAMMPS packages and
-tools"_http://lammps.sandia.gov/offsite.html page of the LAMMPS web
-site for examples of groups that do this.  We are happy to advertise
-your package and web site from that page.  Simply email the
-"developers"_http://lammps.sandia.gov/authors.html with info about
-your package and we will post it there.
-
-The previous sections of this doc page describe how to add new "style"
-files of various kinds to LAMMPS.  Packages are simply collections of
-one or more new class files which are invoked as a new style within a
-LAMMPS input script.  If designed correctly, these additions typically
-do not require changes to the main core of LAMMPS; they are simply
-add-on files.  If you think your new feature requires non-trivial
-changes in core LAMMPS files, you'll need to "communicate with the
-developers"_http://lammps.sandia.gov/authors.html, since we may or may
-not want to make those changes.  An example of a trivial change is
-making a parent-class method "virtual" when you derive a new child
-class from it.
-
-Here is a checklist of steps you need to follow to submit a single file
-or user package for our consideration.  Following these steps will save
-both you and us time. See existing files in packages in the src dir for
-examples. If you are uncertain, please ask.
-
-All source files you provide must compile with the most current
-version of LAMMPS with multiple configurations. In particular you
-need to test compiling LAMMPS from scratch with -DLAMMPS_BIGBIG
-set in addition to the default -DLAMMPS_SMALLBIG setting. Your code
-will need to work correctly in serial and in parallel using MPI. :ulb,l
-
-For consistency with the rest of LAMMPS and especially, if you want
-your contribution(s) to be added to main LAMMPS code or one of its
-standard packages, it needs to be written in a style compatible with
-other LAMMPS source files. This means: 2-character indentation per
-level, [no tabs], no lines over 80 characters. I/O is done via
-the C-style stdio library, class header files should not import any
-system headers outside <stdio.h>, STL containers should be avoided
-in headers, and forward declarations used where possible or needed.
-All added code should be placed into the LAMMPS_NS namespace or a
-sub-namespace; global or static variables should be avoided, as they
-conflict with the modular nature of LAMMPS and the C++ class structure.
-Header files must [not] import namespaces with {using}.
-This all is so the developers can more easily understand, integrate,
-and maintain your contribution and reduce conflicts with other parts
-of LAMMPS.  This basically means that the code accesses data
-structures, performs its operations, and is formatted similar to other
-LAMMPS source files, including the use of the error class for error
-and warning messages. :l
-
-If you want your contribution to be added as a user-contributed
-feature, and it's a single file (actually a *.cpp and *.h file) it can
-rapidly be added to the USER-MISC directory.  Send us the one-line
-entry to add to the USER-MISC/README file in that dir, along with the
-2 source files.  You can do this multiple times if you wish to
-contribute several individual features.  :l
-
-If you want your contribution to be added as a user-contribution and
-it is several related features, it is probably best to make it a user
-package directory with a name like USER-FOO.  In addition to your new
-files, the directory should contain a README text file.  The README
-should contain your name and contact information and a brief
-description of what your new package does.  If your files depend on
-other LAMMPS style files also being installed (e.g. because your file
-is a derived class from the other LAMMPS class), then an Install.sh
-file is also needed to check for those dependencies.  See other README
-and Install.sh files in other USER directories as examples.  Send us a
-tarball of this USER-FOO directory. :l
-
-Your new source files need to have the LAMMPS copyright, GPL notice,
-and your name and email address at the top, like other
-user-contributed LAMMPS source files.  They need to create a class
-that is inside the LAMMPS namespace.  If the file is for one of the
-USER packages, including USER-MISC, then we are not as picky about the
-coding style (see above).  I.e. the files do not need to be in the
-same stylistic format and syntax as other LAMMPS files, though that
-would be nice for developers as well as users who try to read your
-code. :l
-
-You [must] also create a [documentation] file for each new command or
-style you are adding to LAMMPS. For simplicity and convenience, the
-documentation of groups of closely related commands or styles may be
-combined into a single file.  This will be one file for a single-file
-feature.  For a package, it might be several files.  These are simple
-text files with a specific markup language, that are then auto-converted
-to HTML and PDF. The tools for this conversion are included in the
-source distribution, and the translation can be as simple as doing
-"make html pdf" in the doc folder.
-Thus the documentation source files must be in the same format and
-style as other *.txt files in the lammps/doc/src directory for similar
-commands and styles; use one or more of them as a starting point.
-A description of the markup can also be found in
-lammps/doc/utils/txt2html/README.html
-As appropriate, the text files can include links to equations
-(see doc/Eqs/*.tex for examples, we auto-create the associated JPG
-files), or figures (see doc/JPG for examples), or even additional PDF
-files with further details (see doc/PDF for examples).  The doc page
-should also include literature citations as appropriate; see the
-bottom of doc/fix_nh.txt for examples and the earlier part of the same
-file for how to format the cite itself.  The "Restrictions" section of
-the doc page should indicate that your command is only available if
-LAMMPS is built with the appropriate USER-MISC or USER-FOO package.
-See other user package doc files for examples of how to do this. The
-prerequisite for building the HTML format files are Python 3.x and
-virtualenv, the requirement for generating the PDF format manual
-is the "htmldoc"_http://www.htmldoc.org/ software. Please run at least
-"make html" and carefully inspect and proofread the resulting HTML format
-doc page before submitting your code. :l
-
-For a new package (or even a single command) you should include one or
-more example scripts demonstrating its use.  These should run in no
-more than a couple minutes, even on a single processor, and not require
-large data files as input.  See directories under examples/USER for
-examples of input scripts other users provided for their packages.
-These example inputs are also required for validating memory accesses
-and testing for memory leaks with valgrind :l
-
-If there is a paper of yours describing your feature (either the
-algorithm/science behind the feature itself, or its initial usage, or
-its implementation in LAMMPS), you can add the citation to the *.cpp
-source file.  See src/USER-EFF/atom_vec_electron.cpp for an example.
-A LaTeX citation is stored in a variable at the top of the file and a
-single line of code that references the variable is added to the
-constructor of the class.  Whenever a user invokes your feature from
-their input script, this will cause LAMMPS to output the citation to a
-log.cite file and prompt the user to examine the file.  Note that you
-should only use this for a paper you or your group authored.
-E.g. adding a cite in the code for a paper by Nose and Hoover if you
-write a fix that implements their integrator is not the intended
-usage.  That kind of citation should just be in the doc page you
-provide. :l
-:ule
-
-Finally, as a general rule-of-thumb, the more clear and
-self-explanatory you make your documentation and README files, and the
-easier you make it for people to get started, e.g. by providing example
-scripts, the more likely it is that users will try out your new feature.
-
-:line
-:line
-
-:link(Foo)
-[(Foo)] Foo, Morefoo, and Maxfoo, J of Classic Potentials, 75, 345 (1997).
diff --git a/doc/src/Section_packages.txt b/doc/src/Section_packages.txt
index 218866e2715b88794c6c0bb46b1fea7658230538..340a77310d81837fa170a21fea14be888b859bc1 100644
--- a/doc/src/Section_packages.txt
+++ b/doc/src/Section_packages.txt
@@ -51,8 +51,7 @@ technical questions about compiling the package. If you have problems
 using a feature provided in a user package, you may need to contact
 the contributor directly to get help.  Information on how to submit
 additions you make to LAMMPS as single files or as a standard or user
-package are given in "this section"_Section_modify.html#mod_15 of the
-manual.
+package are given in the "Modify contribute"_Modify.html doc page.
 
 Following the next two tables is a sub-section for each package.  It
 lists authors (if applicable) and summarizes the package contents.  It
@@ -1179,10 +1178,10 @@ PYTHON package :link(PYTHON),h4
 
 A "python"_python.html command which allow you to execute Python code
 from a LAMMPS input script.  The code can be in a separate file or
-embedded in the input script itself.  See "Section
-11.2"_Section_python.html#py_2 for an overview of using Python from
-LAMMPS in this manner and the entire section for other ways to use
-LAMMPS and Python together.
+embedded in the input script itself.  See the "Python
+call"_Python_call.html doc page for an overview of using Python from
+LAMMPS in this manner and the "Python"_Python.html doc page for other
+ways to use LAMMPS and Python together.
 
 [Install or un-install:]
 
@@ -1203,7 +1202,7 @@ to Makefile.lammps) if the LAMMPS build fails.
 [Supporting info:]
 
 src/PYTHON: filenames -> commands
-"Section 11"_Section_python.html
+"Python call"_Python_call.html
 lib/python/README
 examples/python :ul
 
diff --git a/doc/src/Section_perf.txt b/doc/src/Section_perf.txt
index 9998cb0d9a1371fdcca7c6e927c49925bb6f81d2..f320780129a9fd67bb2dcccb28ef8a7cacfc92f6 100644
--- a/doc/src/Section_perf.txt
+++ b/doc/src/Section_perf.txt
@@ -1,4 +1,6 @@
-"Previous Section"_Section_example.html - "LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc - "Next Section"_Section_tools.html :c
+"Previous Section"_Examples.html - "LAMMPS WWW Site"_lws - "LAMMPS
+Documentation"_ld - "LAMMPS Commands"_lc - "Next Section"_Tools.html
+:c
 
 :link(lws,http://lammps.sandia.gov)
 :link(ld,Manual.html)
diff --git a/doc/src/Section_python.txt b/doc/src/Section_python.txt
deleted file mode 100644
index 5427cd67f28d36bb0344012e6f7cfe593f7aca88..0000000000000000000000000000000000000000
--- a/doc/src/Section_python.txt
+++ /dev/null
@@ -1,867 +0,0 @@
-"Previous Section"_Section_modify.html - "LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc - "Next Section"_Section_errors.html :c
-
-:link(lws,http://lammps.sandia.gov)
-:link(ld,Manual.html)
-:link(lc,Section_commands.html#comm)
-
-:line
-
-11. Python interface to LAMMPS :h2
-
-LAMMPS can work together with Python in three ways.  First, Python can
-wrap LAMMPS through the "LAMMPS library
-interface"_Section_howto.html#howto_19, so that a Python script can
-create one or more instances of LAMMPS and launch one or more
-simulations.  In Python lingo, this is "extending" Python with LAMMPS.
-
-Second, the low-level Python interface can be used indirectly through the
-PyLammps and IPyLammps wrapper classes in Python. These wrappers try to
-simplify the usage of LAMMPS in Python by providing an object-based interface
-to common LAMMPS functionality. It also reduces the amount of code necessary to
-parameterize LAMMPS scripts through Python and makes variables and computes
-directly accessible. See "PyLammps interface"_#py_9 for more details.
-
-Third, LAMMPS can use the Python interpreter, so that a LAMMPS input
-script can invoke Python code, and pass information back-and-forth
-between the input script and Python functions you write.  The Python
-code can also callback to LAMMPS to query or change its attributes.
-In Python lingo, this is "embedding" Python in LAMMPS.
-
-This section describes how to use these three approaches.
-
-11.1 "Overview of running LAMMPS from Python"_#py_1
-11.2 "Overview of using Python from a LAMMPS script"_#py_2
-11.3 "Building LAMMPS as a shared library"_#py_3
-11.4 "Installing the Python wrapper into Python"_#py_4
-11.5 "Extending Python with MPI to run in parallel"_#py_5
-11.6 "Testing the Python-LAMMPS interface"_#py_6
-11.7 "Using LAMMPS from Python"_#py_7
-11.8 "Example Python scripts that use LAMMPS"_#py_8
-11.9 "PyLammps interface"_#py_9 :ul
-
-If you are not familiar with it, "Python"_http://www.python.org is a
-powerful scripting and programming language which can essentially do
-anything that faster, lower-level languages like C or C++ can do, but
-typically with much fewer lines of code.  When used in embedded mode,
-Python can perform operations that the simplistic LAMMPS input script
-syntax cannot.  Python can be also be used as a "glue" language to
-drive a program through its library interface, or to hook multiple
-pieces of software together, such as a simulation package plus a
-visualization package, or to run a coupled multiscale or multiphysics
-model.
-
-See "Section 6.10"_Section_howto.html#howto_10 of the manual and
-the couple directory of the distribution for more ideas about coupling
-LAMMPS to other codes.  See "Section
-6.19"_Section_howto.html#howto_19 for a description of the LAMMPS
-library interface provided in src/library.cpp and src/library.h, and
-how to extend it for your needs.  As described below, that interface
-is what is exposed to Python either when calling LAMMPS from Python or
-when calling Python from a LAMMPS input script and then calling back
-to LAMMPS from Python code.  The library interface is designed to be
-easy to add functions to.  Thus the Python interface to LAMMPS is also
-easy to extend as well.
-
-If you create interesting Python scripts that run LAMMPS or
-interesting Python functions that can be called from a LAMMPS input
-script, that you think would be useful to other users, please "email
-them to the developers"_http://lammps.sandia.gov/authors.html.  We can
-include them in the LAMMPS distribution.
-
-:line
-:line
-
-11.1 Overview of running LAMMPS from Python :link(py_1),h4
-
-The LAMMPS distribution includes a python directory with all you need
-to run LAMMPS from Python.  The python/lammps.py file wraps the LAMMPS
-library interface, with one wrapper function per LAMMPS library
-function.  This file makes it is possible to do the following either
-from a Python script, or interactively from a Python prompt: create
-one or more instances of LAMMPS, invoke LAMMPS commands or give it an
-input script, run LAMMPS incrementally, extract LAMMPS results, an
-modify internal LAMMPS variables.  From a Python script you can do
-this in serial or parallel.  Running Python interactively in parallel
-does not generally work, unless you have a version of Python that
-extends standard Python to enable multiple instances of Python to read
-what you type.
-
-To do all of this, you must first build LAMMPS as a shared library,
-then insure that your Python can find the python/lammps.py file and
-the shared library.  These steps are explained in subsequent sections
-11.3 and 11.4.  Sections 11.5 and 11.6 discuss using MPI from a
-parallel Python program and how to test that you are ready to use
-LAMMPS from Python.  Section 11.7 lists all the functions in the
-current LAMMPS library interface and how to call them from Python.
-
-Section 11.8 gives some examples of coupling LAMMPS to other tools via
-Python.  For example, LAMMPS can easily be coupled to a GUI or other
-visualization tools that display graphs or animations in real time as
-LAMMPS runs.  Examples of such scripts are included in the python
-directory.
-
-Two advantages of using Python to run LAMMPS are how concise the
-language is, and that it can be run interactively, enabling rapid
-development and debugging of programs.  If you use it to mostly invoke
-costly operations within LAMMPS, such as running a simulation for a
-reasonable number of timesteps, then the overhead cost of invoking
-LAMMPS thru Python will be negligible.
-
-The Python wrapper for LAMMPS uses the amazing and magical (to me)
-"ctypes" package in Python, which auto-generates the interface code
-needed between Python and a set of C interface routines for a library.
-Ctypes is part of standard Python for versions 2.5 and later.  You can
-check which version of Python you have installed, by simply typing
-"python" at a shell prompt.
-
-:line
-
-11.2 Overview of using Python from a LAMMPS script :link(py_2),h4
-
-LAMMPS has several commands which can be used to invoke Python
-code directly from an input script:
-
-"python"_python.html
-"variable python"_variable.html
-"fix python/invoke"_fix_python_invoke.html
-"pair_style python"_pair_python.html :ul
-
-The "python"_python.html command which can be used to define and
-execute a Python function that you write the code for.  The Python
-function can also be assigned to a LAMMPS python-style variable via
-the "variable"_variable.html command.  Each time the variable is
-evaluated, either in the LAMMPS input script itself, or by another
-LAMMPS command that uses the variable, this will trigger the Python
-function to be invoked.
-
-The Python code for the function can be included directly in the input
-script or in an auxiliary file.  The function can have arguments which
-are mapped to LAMMPS variables (also defined in the input script) and
-it can return a value to a LAMMPS variable.  This is thus a mechanism
-for your input script to pass information to a piece of Python code,
-ask Python to execute the code, and return information to your input
-script.
-
-Note that a Python function can be arbitrarily complex.  It can import
-other Python modules, instantiate Python classes, call other Python
-functions, etc.  The Python code that you provide can contain more
-code than the single function.  It can contain other functions or
-Python classes, as well as global variables or other mechanisms for
-storing state between calls from LAMMPS to the function.
-
-The Python function you provide can consist of "pure" Python code that
-only performs operations provided by standard Python.  However, the
-Python function can also "call back" to LAMMPS through its
-Python-wrapped library interface, in the manner described in the
-previous section 11.1.  This means it can issue LAMMPS input script
-commands or query and set internal LAMMPS state.  As an example, this
-can be useful in an input script to create a more complex loop with
-branching logic, than can be created using the simple looping and
-branching logic enabled by the "next"_next.html and "if"_if.html
-commands.
-
-See the "python"_python.html doc page and the "variable"_variable.html
-doc page for its python-style variables for more info, including
-examples of Python code you can write for both pure Python operations
-and callbacks to LAMMPS.
-
-The "fix python/invoke"_fix_python_invoke.html command can execute
-Python code at selected timesteps during a simulation run.
-
-The "pair_style python"_pair_python command allows you to define
-pairwise potentials as python code which encodes a single pairwise
-interaction.  This is useful for rapid-developement and debugging of a
-new potential.
-
-To use any of these commands, you only need to build LAMMPS with the
-PYTHON package installed:
-
-make yes-python
-make machine :pre
-
-Note that this will link LAMMPS with the Python library on your
-system, which typically requires several auxiliary system libraries to
-also be linked.  The list of these libraries and the paths to find
-them are specified in the lib/python/Makefile.lammps file.  You need
-to insure that file contains the correct information for your version
-of Python and your machine to successfully build LAMMPS.  See the
-lib/python/README file for more info.
-
-If you want to write Python code with callbacks to LAMMPS, then you
-must also follow the steps overviewed in the preceding section (11.1)
-for running LAMMPS from Python.  I.e. you must build LAMMPS as a
-shared library and insure that Python can find the python/lammps.py
-file and the shared library.
-
-:line
-
-11.3 Building LAMMPS as a shared library :link(py_3),h4
-
-Instructions on how to build LAMMPS as a shared library are given in
-"Section 2.4"_Section_start.html#start_4.  A shared library is one
-that is dynamically loadable, which is what Python requires to wrap
-LAMMPS.  On Linux this is a library file that ends in ".so", not ".a".
-
-From the src directory, type
-
-make foo mode=shlib :pre
-
-where foo is the machine target name, such as linux or g++ or serial.
-This should create the file liblammps_foo.so in the src directory, as
-well as a soft link liblammps.so, which is what the Python wrapper will
-load by default.  Note that if you are building multiple machine
-versions of the shared library, the soft link is always set to the
-most recently built version.
-
-NOTE: If you are building LAMMPS with an MPI or FFT library or other
-auxiliary libraries (used by various packages), then all of these
-extra libraries must also be shared libraries.  If the LAMMPS
-shared-library build fails with an error complaining about this, see
-"Section 2.4"_Section_start.html#start_4 for more details.
-
-:line
-
-11.4 Installing the Python wrapper into Python :link(py_4),h4
-
-For Python to invoke LAMMPS, there are 2 files it needs to know about:
-
-python/lammps.py
-src/liblammps.so :ul
-
-Lammps.py is the Python wrapper on the LAMMPS library interface.
-Liblammps.so is the shared LAMMPS library that Python loads, as
-described above.
-
-You can insure Python can find these files in one of two ways:
-
-set two environment variables
-run the python/install.py script :ul
-
-If you set the paths to these files as environment variables, you only
-have to do it once.  For the csh or tcsh shells, add something like
-this to your ~/.cshrc file, one line for each of the two files:
-
-setenv PYTHONPATH $\{PYTHONPATH\}:/home/sjplimp/lammps/python
-setenv LD_LIBRARY_PATH $\{LD_LIBRARY_PATH\}:/home/sjplimp/lammps/src :pre
-
-If you use the python/install.py script, you need to invoke it every
-time you rebuild LAMMPS (as a shared library) or make changes to the
-python/lammps.py file.
-
-You can invoke install.py from the python directory as
-
-% python install.py \[libdir\] \[pydir\] :pre
-
-The optional libdir is where to copy the LAMMPS shared library to; the
-default is /usr/local/lib.  The optional pydir is where to copy the
-lammps.py file to; the default is the site-packages directory of the
-version of Python that is running the install script.
-
-Note that libdir must be a location that is in your default
-LD_LIBRARY_PATH, like /usr/local/lib or /usr/lib.  And pydir must be a
-location that Python looks in by default for imported modules, like
-its site-packages dir.  If you want to copy these files to
-non-standard locations, such as within your own user space, you will
-need to set your PYTHONPATH and LD_LIBRARY_PATH environment variables
-accordingly, as above.
-
-If the install.py script does not allow you to copy files into system
-directories, prefix the python command with "sudo".  If you do this,
-make sure that the Python that root runs is the same as the Python you
-run.  E.g. you may need to do something like
-
-% sudo /usr/local/bin/python install.py \[libdir\] \[pydir\] :pre
-
-You can also invoke install.py from the make command in the src
-directory as
-
-% make install-python :pre
-
-In this mode you cannot append optional arguments.  Again, you may
-need to prefix this with "sudo".  In this mode you cannot control
-which Python is invoked by root.
-
-Note that if you want Python to be able to load different versions of
-the LAMMPS shared library (see "this section"_#py_5 below), you will
-need to manually copy files like liblammps_g++.so into the appropriate
-system directory.  This is not needed if you set the LD_LIBRARY_PATH
-environment variable as described above.
-
-:line
-
-11.5 Extending Python with MPI to run in parallel :link(py_5),h4
-
-If you wish to run LAMMPS in parallel from Python, you need to extend
-your Python with an interface to MPI.  This also allows you to
-make MPI calls directly from Python in your script, if you desire.
-
-There are several Python packages available that purport to wrap MPI
-as a library and allow MPI functions to be called from Python. However,
-development on most of them seems to be halted except on:
-
-"mpi4py"_https://bitbucket.org/mpi4py/mpi4py
-"PyPar"_https://github.com/daleroberts/pypar :ul
-
-Both packages, PyPar and mpi4py have been successfully tested with
-LAMMPS.  PyPar is simpler and easy to set up and use, but supports
-only a subset of MPI.  Mpi4py is more MPI-feature complete, but also a
-bit more complex to use.  As of version 2.0.0, mpi4py is the only
-python MPI wrapper that allows passing a custom MPI communicator to
-the LAMMPS constructor, which means one can easily run one or more
-LAMMPS instances on subsets of the total MPI ranks.
-
-:line
-
-PyPar requires the ubiquitous "Numpy package"_http://numpy.scipy.org
-be installed in your Python.  After launching Python, type
-
-import numpy :pre
-
-to see if it is installed.  If not, here is how to install it (version
-1.3.0b1 as of April 2009).  Unpack the numpy tarball and from its
-top-level directory, type
-
-python setup.py build
-sudo python setup.py install :pre
-
-The "sudo" is only needed if required to copy Numpy files into your
-Python distribution's site-packages directory.
-
-To install PyPar (version pypar-2.1.4_94 as of Aug 2012), unpack it
-and from its "source" directory, type
-
-python setup.py build
-sudo python setup.py install :pre
-
-Again, the "sudo" is only needed if required to copy PyPar files into
-your Python distribution's site-packages directory.
-
-If you have successfully installed PyPar, you should be able to run
-Python and type
-
-import pypar :pre
-
-without error.  You should also be able to run python in parallel
-on a simple test script
-
-% mpirun -np 4 python test.py :pre
-
-where test.py contains the lines
-
-import pypar
-print "Proc %d out of %d procs" % (pypar.rank(),pypar.size()) :pre
-
-and see one line of output for each processor you run on.
-
-NOTE: To use PyPar and LAMMPS in parallel from Python, you must insure
-both are using the same version of MPI.  If you only have one MPI
-installed on your system, this is not an issue, but it can be if you
-have multiple MPIs.  Your LAMMPS build is explicit about which MPI it
-is using, since you specify the details in your lo-level
-src/MAKE/Makefile.foo file.  PyPar uses the "mpicc" command to find
-information about the MPI it uses to build against.  And it tries to
-load "libmpi.so" from the LD_LIBRARY_PATH.  This may or may not find
-the MPI library that LAMMPS is using.  If you have problems running
-both PyPar and LAMMPS together, this is an issue you may need to
-address, e.g. by moving other MPI installations so that PyPar finds
-the right one.
-
-:line
-
-To install mpi4py (version mpi4py-2.0.0 as of Oct 2015), unpack it
-and from its main directory, type
-
-python setup.py build
-sudo python setup.py install :pre
-
-Again, the "sudo" is only needed if required to copy mpi4py files into
-your Python distribution's site-packages directory. To install with
-user privilege into the user local directory type
-
-python setup.py install --user :pre
-
-If you have successfully installed mpi4py, you should be able to run
-Python and type
-
-from mpi4py import MPI :pre
-
-without error.  You should also be able to run python in parallel
-on a simple test script
-
-% mpirun -np 4 python test.py :pre
-
-where test.py contains the lines
-
-from mpi4py import MPI
-comm = MPI.COMM_WORLD
-print "Proc %d out of %d procs" % (comm.Get_rank(),comm.Get_size()) :pre
-
-and see one line of output for each processor you run on.
-
-NOTE: To use mpi4py and LAMMPS in parallel from Python, you must
-insure both are using the same version of MPI.  If you only have one
-MPI installed on your system, this is not an issue, but it can be if
-you have multiple MPIs.  Your LAMMPS build is explicit about which MPI
-it is using, since you specify the details in your lo-level
-src/MAKE/Makefile.foo file.  Mpi4py uses the "mpicc" command to find
-information about the MPI it uses to build against.  And it tries to
-load "libmpi.so" from the LD_LIBRARY_PATH.  This may or may not find
-the MPI library that LAMMPS is using.  If you have problems running
-both mpi4py and LAMMPS together, this is an issue you may need to
-address, e.g. by moving other MPI installations so that mpi4py finds
-the right one.
-
-:line
-
-11.6 Testing the Python-LAMMPS interface :link(py_6),h4
-
-To test if LAMMPS is callable from Python, launch Python interactively
-and type:
-
->>> from lammps import lammps
->>> lmp = lammps() :pre
-
-If you get no errors, you're ready to use LAMMPS from Python.  If the
-2nd command fails, the most common error to see is
-
-OSError: Could not load LAMMPS dynamic library :pre
-
-which means Python was unable to load the LAMMPS shared library.  This
-typically occurs if the system can't find the LAMMPS shared library or
-one of the auxiliary shared libraries it depends on, or if something
-about the library is incompatible with your Python.  The error message
-should give you an indication of what went wrong.
-
-You can also test the load directly in Python as follows, without
-first importing from the lammps.py file:
-
->>> from ctypes import CDLL
->>> CDLL("liblammps.so") :pre
-
-If an error occurs, carefully go thru the steps in "Section
-2.4"_Section_start.html#start_4 and above about building a shared
-library and about insuring Python can find the necessary two files
-it needs.
-
-[Test LAMMPS and Python in serial:] :h4
-
-To run a LAMMPS test in serial, type these lines into Python
-interactively from the bench directory:
-
->>> from lammps import lammps
->>> lmp = lammps()
->>> lmp.file("in.lj") :pre
-
-Or put the same lines in the file test.py and run it as
-
-% python test.py :pre
-
-Either way, you should see the results of running the in.lj benchmark
-on a single processor appear on the screen, the same as if you had
-typed something like:
-
-lmp_g++ -in in.lj :pre
-
-[Test LAMMPS and Python in parallel:] :h4
-
-To run LAMMPS in parallel, assuming you have installed the
-"PyPar"_https://github.com/daleroberts/pypar package as discussed
-above, create a test.py file containing these lines:
-
-import pypar
-from lammps import lammps
-lmp = lammps()
-lmp.file("in.lj")
-print "Proc %d out of %d procs has" % (pypar.rank(),pypar.size()),lmp
-pypar.finalize() :pre
-
-To run LAMMPS in parallel, assuming you have installed the
-"mpi4py"_https://bitbucket.org/mpi4py/mpi4py package as discussed
-above, create a test.py file containing these lines:
-
-from mpi4py import MPI
-from lammps import lammps
-lmp = lammps()
-lmp.file("in.lj")
-me = MPI.COMM_WORLD.Get_rank()
-nprocs = MPI.COMM_WORLD.Get_size()
-print "Proc %d out of %d procs has" % (me,nprocs),lmp
-MPI.Finalize() :pre
-
-You can either script in parallel as:
-
-% mpirun -np 4 python test.py :pre
-
-and you should see the same output as if you had typed
-
-% mpirun -np 4 lmp_g++ -in in.lj :pre
-
-Note that if you leave out the 3 lines from test.py that specify PyPar
-commands you will instantiate and run LAMMPS independently on each of
-the P processors specified in the mpirun command.  In this case you
-should get 4 sets of output, each showing that a LAMMPS run was made
-on a single processor, instead of one set of output showing that
-LAMMPS ran on 4 processors.  If the 1-processor outputs occur, it
-means that PyPar is not working correctly.
-
-Also note that once you import the PyPar module, PyPar initializes MPI
-for you, and you can use MPI calls directly in your Python script, as
-described in the PyPar documentation.  The last line of your Python
-script should be pypar.finalize(), to insure MPI is shut down
-correctly.
-
-[Running Python scripts:] :h4
-
-Note that any Python script (not just for LAMMPS) can be invoked in
-one of several ways:
-
-% python foo.script
-% python -i foo.script
-% foo.script :pre
-
-The last command requires that the first line of the script be
-something like this:
-
-#!/usr/local/bin/python
-#!/usr/local/bin/python -i :pre
-
-where the path points to where you have Python installed, and that you
-have made the script file executable:
-
-% chmod +x foo.script :pre
-
-Without the "-i" flag, Python will exit when the script finishes.
-With the "-i" flag, you will be left in the Python interpreter when
-the script finishes, so you can type subsequent commands.  As
-mentioned above, you can only run Python interactively when running
-Python on a single processor, not in parallel.
-
-:line
-:line
-
-11.7 Using LAMMPS from Python :link(py_7),h4
-
-As described above, the Python interface to LAMMPS consists of a
-Python "lammps" module, the source code for which is in
-python/lammps.py, which creates a "lammps" object, with a set of
-methods that can be invoked on that object.  The sample Python code
-below assumes you have first imported the "lammps" module in your
-Python script, as follows:
-
-from lammps import lammps :pre
-
-These are the methods defined by the lammps module.  If you look at
-the files src/library.cpp and src/library.h you will see they
-correspond one-to-one with calls you can make to the LAMMPS library
-from a C++ or C or Fortran program, and which are described in
-"Section 6.19"_Section_howto.html#howto_19 of the manual.
-
-The python/examples directory has Python scripts which show how Python
-can run LAMMPS, grab data, change it, and put it back into LAMMPS.
-
-lmp = lammps()           # create a LAMMPS object using the default liblammps.so library
-                         # 4 optional args are allowed: name, cmdargs, ptr, comm
-lmp = lammps(ptr=lmpptr) # use lmpptr as previously created LAMMPS object
-lmp = lammps(comm=split) # create a LAMMPS object with a custom communicator, requires mpi4py 2.0.0 or later
-lmp = lammps(name="g++")   # create a LAMMPS object using the liblammps_g++.so library
-lmp = lammps(name="g++",cmdargs=list)    # add LAMMPS command-line args, e.g. list = \["-echo","screen"\] :pre
-
-lmp.close()              # destroy a LAMMPS object :pre
-
-version = lmp.version()  # return the numerical version id, e.g. LAMMPS 2 Sep 2015 -> 20150902 :pre
-
-lmp.file(file)           # run an entire input script, file = "in.lj"
-lmp.command(cmd)         # invoke a single LAMMPS command, cmd = "run 100"
-lmp.commands_list(cmdlist)     # invoke commands in cmdlist = ["run 10", "run 20"]
-lmp.commands_string(multicmd)  # invoke commands in multicmd = "run 10\nrun 20" :pre
-
-size = lmp.extract_setting(name)     # return data type info :pre
-
-xlo = lmp.extract_global(name,type)  # extract a global quantity
-                                     # name = "boxxlo", "nlocal", etc
-                                     # type = 0 = int
-                                     #        1 = double :pre
-
-boxlo,boxhi,xy,yz,xz,periodicity,box_change = lmp.extract_box()  # extract box info :pre
-
-coords = lmp.extract_atom(name,type)      # extract a per-atom quantity
-                                          # name = "x", "type", etc
-                                          # type = 0 = vector of ints
-                                          #        1 = array of ints
-                                          #        2 = vector of doubles
-                                          #        3 = array of doubles :pre
-
-eng = lmp.extract_compute(id,style,type)  # extract value(s) from a compute
-v3 = lmp.extract_fix(id,style,type,i,j)   # extract value(s) from a fix
-                                          # id = ID of compute or fix
-                                          # style = 0 = global data
-                                          #         1 = per-atom data
-                                          #         2 = local data
-                                          # type = 0 = scalar
-                                          #        1 = vector
-                                          #        2 = array
-                                          # i,j = indices of value in global vector or array :pre
-
-var = lmp.extract_variable(name,group,flag)  # extract value(s) from a variable
-                                             # name = name of variable
-                                             # group = group ID (ignored for equal-style variables)
-                                             # flag = 0 = equal-style variable
-                                             #        1 = atom-style variable :pre
-
-value = lmp.get_thermo(name)              # return current value of a thermo keyword
-natoms = lmp.get_natoms()                 # total # of atoms as int :pre
-
-flag = lmp.set_variable(name,value)       # set existing named string-style variable to value, flag = 0 if successful
-lmp.reset_box(boxlo,boxhi,xy,yz,xz)       # reset the simulation box size :pre
-
-data = lmp.gather_atoms(name,type,count)  # return per-atom property of all atoms gathered into data, ordered by atom ID
-                                          # name = "x", "charge", "type", etc
-data = lmp.gather_atoms_concat(name,type,count)  # ditto, but concatenated atom values from each proc (unordered)
-data = lmp.gather_atoms_subset(name,type,count,ndata,ids)  # ditto, but for subset of Ndata atoms with IDs :pre
-
-lmp.scatter_atoms(name,type,count,data)   # scatter per-atom property to all atoms from data, ordered by atom ID
-                                          # name = "x", "charge", "type", etc
-                                          # count = # of per-atom values, 1 or 3, etc :pre
-lmp.scatter_atoms_subset(name,type,count,ndata,ids,data)  # ditto, but for subset of Ndata atoms with IDs :pre
-
-lmp.create_atoms(n,ids,types,x,v,image,shrinkexceed)   # create N atoms with IDs, types, x, v, and image flags :pre
-
-:line
-
-The lines
-
-from lammps import lammps
-lmp = lammps() :pre
-
-create an instance of LAMMPS, wrapped in a Python class by the lammps
-Python module, and return an instance of the Python class as lmp.  It
-is used to make all subsequent calls to the LAMMPS library.
-
-Additional arguments to lammps() can be used to tell Python the name
-of the shared library to load or to pass arguments to the LAMMPS
-instance, the same as if LAMMPS were launched from a command-line
-prompt.
-
-If the ptr argument is set like this:
-
-lmp = lammps(ptr=lmpptr) :pre
-
-then lmpptr must be an argument passed to Python via the LAMMPS
-"python"_python.html command, when it is used to define a Python
-function that is invoked by the LAMMPS input script.  This mode of
-using Python with LAMMPS is described above in 11.2.  The variable
-lmpptr refers to the instance of LAMMPS that called the embedded
-Python interpreter.  Using it as an argument to lammps() allows the
-returned Python class instance "lmp" to make calls to that instance of
-LAMMPS.  See the "python"_python.html command doc page for examples
-using this syntax.
-
-Note that you can create multiple LAMMPS objects in your Python
-script, and coordinate and run multiple simulations, e.g.
-
-from lammps import lammps
-lmp1 = lammps()
-lmp2 = lammps()
-lmp1.file("in.file1")
-lmp2.file("in.file2") :pre
-
-The file(), command(), commands_list(), commands_string() methods
-allow an input script, a single command, or multiple commands to be
-invoked.
-
-The extract_setting(), extract_global(), extract_box(),
-extract_atom(), extract_compute(), extract_fix(), and
-extract_variable() methods return values or pointers to data
-structures internal to LAMMPS.
-
-For extract_global() see the src/library.cpp file for the list of
-valid names.  New names could easily be added.  A double or integer is
-returned.  You need to specify the appropriate data type via the type
-argument.
-
-For extract_atom(), a pointer to internal LAMMPS atom-based data is
-returned, which you can use via normal Python subscripting.  See the
-extract() method in the src/atom.cpp file for a list of valid names.
-Again, new names could easily be added if the property you want is not
-listed.  A pointer to a vector of doubles or integers, or a pointer to
-an array of doubles (double **) or integers (int **) is returned.  You
-need to specify the appropriate data type via the type argument.
-
-For extract_compute() and extract_fix(), the global, per-atom, or
-local data calculated by the compute or fix can be accessed.  What is
-returned depends on whether the compute or fix calculates a scalar or
-vector or array.  For a scalar, a single double value is returned.  If
-the compute or fix calculates a vector or array, a pointer to the
-internal LAMMPS data is returned, which you can use via normal Python
-subscripting.  The one exception is that for a fix that calculates a
-global vector or array, a single double value from the vector or array
-is returned, indexed by I (vector) or I and J (array).  I,J are
-zero-based indices.  The I,J arguments can be left out if not needed.
-See "Section 6.15"_Section_howto.html#howto_15 of the manual for a
-discussion of global, per-atom, and local data, and of scalar, vector,
-and array data types.  See the doc pages for individual
-"computes"_compute.html and "fixes"_fix.html for a description of what
-they calculate and store.
-
-For extract_variable(), an "equal-style or atom-style
-variable"_variable.html is evaluated and its result returned.
-
-For equal-style variables a single double value is returned and the
-group argument is ignored.  For atom-style variables, a vector of
-doubles is returned, one value per atom, which you can use via normal
-Python subscripting. The values will be zero for atoms not in the
-specified group.
-
-The get_thermo() method returns returns the current value of a thermo
-keyword as a float.
-
-The get_natoms() method returns the total number of atoms in the
-simulation, as an int.
-
-The set_variable() methosd sets an existing string-style variable to a
-new string value, so that subsequent LAMMPS commands can access the
-variable.
-
-The reset_box() emthods resets the size and shape of the simulation
-box, e.g. as part of restoring a previously extracted and saved state
-of a simulation.
-
-The gather methods collect peratom info of the requested type (atom
-coords, atom types, forces, etc) from all processors, and returns the
-same vector of values to each callling processor.  The scatter
-functions do the inverse.  They distribute a vector of peratom values,
-passed by all calling processors, to invididual atoms, which may be
-owned by different processos.
-
-Note that the data returned by the gather methods,
-e.g. gather_atoms("x"), is different from the data structure returned
-by extract_atom("x") in four ways.  (1) Gather_atoms() returns a
-vector which you index as x\[i\]; extract_atom() returns an array
-which you index as x\[i\]\[j\].  (2) Gather_atoms() orders the atoms
-by atom ID while extract_atom() does not.  (3) Gather_atoms() returns
-a list of all atoms in the simulation; extract_atoms() returns just
-the atoms local to each processor.  (4) Finally, the gather_atoms()
-data structure is a copy of the atom coords stored internally in
-LAMMPS, whereas extract_atom() returns an array that effectively
-points directly to the internal data.  This means you can change
-values inside LAMMPS from Python by assigning a new values to the
-extract_atom() array.  To do this with the gather_atoms() vector, you
-need to change values in the vector, then invoke the scatter_atoms()
-method.
-
-For the scatter methods, the array of coordinates passed to must be a
-ctypes vector of ints or doubles, allocated and initialized something
-like this:
-
-from ctypes import *
-natoms = lmp.get_natoms()
-n3 = 3*natoms
-x = (n3*c_double)()
-x\[0\] = x coord of atom with ID 1
-x\[1\] = y coord of atom with ID 1
-x\[2\] = z coord of atom with ID 1
-x\[3\] = x coord of atom with ID 2
-...
-x\[n3-1\] = z coord of atom with ID natoms
-lmp.scatter_atoms("x",1,3,x) :pre
-
-Alternatively, you can just change values in the vector returned by
-the gather methods, since they are also ctypes vectors.
-
-:line
-
-As noted above, these Python class methods correspond one-to-one with
-the functions in the LAMMPS library interface in src/library.cpp and
-library.h.  This means you can extend the Python wrapper via the
-following steps:
-
-Add a new interface function to src/library.cpp and
-src/library.h. :ulb,l
-
-Rebuild LAMMPS as a shared library. :l
-
-Add a wrapper method to python/lammps.py for this interface
-function. :l
-
-You should now be able to invoke the new interface function from a
-Python script.  Isn't ctypes amazing? :l
-:ule
-
-:line
-:line
-
-11.8 Example Python scripts that use LAMMPS :link(py_8),h4
-
-These are the Python scripts included as demos in the python/examples
-directory of the LAMMPS distribution, to illustrate the kinds of
-things that are possible when Python wraps LAMMPS.  If you create your
-own scripts, send them to us and we can include them in the LAMMPS
-distribution.
-
-trivial.py, read/run a LAMMPS input script thru Python,
-demo.py, invoke various LAMMPS library interface routines,
-simple.py, run in parallel, similar to examples/COUPLE/simple/simple.cpp,
-split.py, same as simple.py but running in parallel on a subset of procs,
-gui.py, GUI go/stop/temperature-slider to control LAMMPS,
-plot.py, real-time temperature plot with GnuPlot via Pizza.py,
-viz_tool.py, real-time viz via some viz package,
-vizplotgui_tool.py, combination of viz_tool.py and plot.py and gui.py :tb(c=2)
-
-:line
-
-For the viz_tool.py and vizplotgui_tool.py commands, replace "tool"
-with "gl" or "atomeye" or "pymol" or "vmd", depending on what
-visualization package you have installed.
-
-Note that for GL, you need to be able to run the Pizza.py GL tool,
-which is included in the pizza sub-directory.  See the "Pizza.py doc
-pages"_pizza for more info:
-
-:link(pizza,http://www.sandia.gov/~sjplimp/pizza.html)
-
-Note that for AtomEye, you need version 3, and there is a line in the
-scripts that specifies the path and name of the executable.  See the
-AtomEye WWW pages "here"_atomeye or "here"_atomeye3 for more details:
-
-http://mt.seas.upenn.edu/Archive/Graphics/A
-http://mt.seas.upenn.edu/Archive/Graphics/A3/A3.html :pre
-
-:link(atomeye,http://mt.seas.upenn.edu/Archive/Graphics/A)
-:link(atomeye3,http://mt.seas.upenn.edu/Archive/Graphics/A3/A3.html)
-
-The latter link is to AtomEye 3 which has the scriping
-capability needed by these Python scripts.
-
-Note that for PyMol, you need to have built and installed the
-open-source version of PyMol in your Python, so that you can import it
-from a Python script.  See the PyMol WWW pages "here"_pymolhome or
-"here"_pymolopen for more details:
-
-http://www.pymol.org
-http://sourceforge.net/scm/?type=svn&group_id=4546 :pre
-
-:link(pymolhome,http://www.pymol.org)
-:link(pymolopen,http://sourceforge.net/scm/?type=svn&group_id=4546)
-
-The latter link is to the open-source version.
-
-Note that for VMD, you need a fairly current version (1.8.7 works for
-me) and there are some lines in the pizza/vmd.py script for 4 PIZZA
-variables that have to match the VMD installation on your system.
-
-:line
-
-See the python/README file for instructions on how to run them and the
-source code for individual scripts for comments about what they do.
-
-Here are screenshots of the vizplotgui_tool.py script in action for
-different visualization package options.  Click to see larger images:
-
-:image(JPG/screenshot_gl_small.jpg,JPG/screenshot_gl.jpg)
-:image(JPG/screenshot_atomeye_small.jpg,JPG/screenshot_atomeye.jpg)
-:image(JPG/screenshot_pymol_small.jpg,JPG/screenshot_pymol.jpg)
-:image(JPG/screenshot_vmd_small.jpg,JPG/screenshot_vmd.jpg)
-
-11.9 PyLammps interface :link(py_9),h4
-
-Please see the "PyLammps Tutorial"_tutorial_pylammps.html.
diff --git a/doc/src/Section_start.txt b/doc/src/Section_start.txt
index 7d456171dc5f26a3362b2bbdbb6fe8634a245802..d8f340b17996c25d8e3b3aceb56002e80fc2861b 100644
--- a/doc/src/Section_start.txt
+++ b/doc/src/Section_start.txt
@@ -1,4 +1,6 @@
-"Previous Section"_Section_intro.html - "LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc - "Next Section"_Section_commands.html :c
+"Previous Section"_Section_intro.html - "LAMMPS WWW Site"_lws -
+"LAMMPS Documentation"_ld - "LAMMPS Commands"_lc - "Next
+Section"_Section_commands.html :c
 
 :link(lws,http://lammps.sandia.gov)
 :link(ld,Manual.html)
@@ -930,8 +932,8 @@ Makefile.opt :ul
 LAMMPS can be built as either a static or shared library, which can
 then be called from another application or a scripting language.  See
 "this section"_Section_howto.html#howto_10 for more info on coupling
-LAMMPS to other codes.  See "this section"_Section_python.html for
-more info on wrapping and running LAMMPS from Python.
+LAMMPS to other codes.  See the "Python"_Python.html doc page for more
+info on wrapping and running LAMMPS from Python.
 
 Static library :h4
 
@@ -955,15 +957,15 @@ dynamically loaded, e.g. from Python, type
 make foo mode=shlib :pre
 
 where foo is the machine name.  This kind of library is required when
-wrapping LAMMPS with Python; see "Section 11"_Section_python.html
-for details.  This will use the SHFLAGS and SHLIBFLAGS settings in
+wrapping LAMMPS with Python; see the "Python"_Python.html doc page for
+details.  This will use the SHFLAGS and SHLIBFLAGS settings in
 src/MAKE/Makefile.foo and perform the build in the directory
 Obj_shared_foo.  This is so that each file can be compiled with the
 -fPIC flag which is required for inclusion in a shared library.  The
 build will create the file liblammps_foo.so which another application
-can link to dynamically.  It will also create a soft link liblammps.so,
-which will point to the most recently built shared library.  This is
-the file the Python wrapper loads by default.
+can link to dynamically.  It will also create a soft link
+liblammps.so, which will point to the most recently built shared
+library.  This is the file the Python wrapper loads by default.
 
 Note that for a shared library to be usable by a calling program, all
 the auxiliary libraries it depends on must also exist as shared
@@ -1035,10 +1037,10 @@ src/library.cpp and src/library.h.
 See the sample codes in examples/COUPLE/simple for examples of C++ and
 C and Fortran codes that invoke LAMMPS thru its library interface.
 There are other examples as well in the COUPLE directory which are
-discussed in "Section 6.10"_Section_howto.html#howto_10 of the
-manual.  See "Section 11"_Section_python.html of the manual for a
-description of the Python wrapper provided with LAMMPS that operates
-through the LAMMPS library interface.
+discussed in "Section 6.10"_Section_howto.html#howto_10 of the manual.
+See the "Python"_Python.html doc page for a description of the Python
+wrapper provided with LAMMPS that operates through the LAMMPS library
+interface.
 
 The files src/library.cpp and library.h define the C-style API for
 using LAMMPS as a library.  See "Section
@@ -1177,7 +1179,7 @@ than your working directory, which is probably not what you want.
 
 If LAMMPS encounters errors in the input script or while running a
 simulation it will print an ERROR message and stop or a WARNING
-message and continue.  See "Section 12"_Section_errors.html for a
+message and continue.  See the "Errors"_Errors.html doc page for a
 discussion of the various kinds of errors LAMMPS can or can't detect,
 a list of all ERROR and WARNING messages, and what to do about them.
 
diff --git a/doc/src/Section_tools.txt b/doc/src/Tools.txt
similarity index 89%
rename from doc/src/Section_tools.txt
rename to doc/src/Tools.txt
index 7cc07cbec55a5e7c4f3545c623875be8cc6919cc..4c5fbbd45327f6e68d9ff29704add3ae4de96a12 100644
--- a/doc/src/Section_tools.txt
+++ b/doc/src/Tools.txt
@@ -1,6 +1,6 @@
 "Previous Section"_Section_perf.html - "LAMMPS WWW Site"_lws - "LAMMPS
 Documentation"_ld - "LAMMPS Commands"_lc - "Next
-Section"_Section_modify.html :c
+Section"_Modify.html :c
 
 :link(lws,http://lammps.sandia.gov)
 :link(ld,Manual.html)
@@ -8,33 +8,34 @@ Section"_Section_modify.html :c
 
 :line
 
-9. Additional tools :h2
+Auxiliary tools :h2
 
 LAMMPS is designed to be a computational kernel for performing
 molecular dynamics computations.  Additional pre- and post-processing
-steps are often necessary to setup and analyze a simulation. A
-list of such tools can be found on the LAMMPS home page
-at "http://lammps.sandia.gov/prepost.html"_http://lammps.sandia.gov/prepost.html
+steps are often necessary to setup and analyze a simulation.  A list
+of such tools can be found on the "LAMMPS webpage"_lws at these links:
 
-A few additional tools are provided with the LAMMPS distribution
-and are described in this section.
+"Pre/Post processing"_http://lammps.sandia.gov/prepost.html
+"Offsite LAMMPS packages & tools"_http://lammps.sandia.gov/offsite.html
+"Pizza.py toolkit"_pizza :ul
 
-Our group has also written and released a separate toolkit called
-"Pizza.py"_pizza which provides tools for doing setup, analysis,
-plotting, and visualization for LAMMPS simulations.  Pizza.py is
-written in "Python"_python and is available for download from "the
-Pizza.py WWW site"_pizza.
+The last link for "Pizza.py"_pizza is a Python-based tool developed at
+Sandia which provides tools for doing setup, analysis, plotting, and
+visualization for LAMMPS simulations.
 
-:link(pizza,http://www.sandia.gov/~sjplimp/pizza.html)
+:link(pizza,http://pizza.sandia.gov)
 :link(python,http://www.python.org)
 
+Additional tools included in the LAMMPS distribution are described on
+this page.
+
 Note that many users write their own setup or analysis tools or use
 other existing codes and convert their output to a LAMMPS input format
 or vice versa.  The tools listed here are included in the LAMMPS
 distribution as examples of auxiliary tools.  Some of them are not
-actively supported by Sandia, as they were contributed by LAMMPS
-users.  If you have problems using them, we can direct you to the
-authors.
+actively supported by the LAMMPS developers, as they were contributed
+by LAMMPS users.  If you have problems using them, we can direct you
+to the authors.
 
 The source code for each of these codes is in the tools sub-directory
 of the LAMMPS distribution.  There is a Makefile (which you may need
@@ -71,11 +72,12 @@ own sub-directories with their own Makefiles and/or README files.
 "reax"_#reax_tool
 "smd"_#smd
 "vim"_#vim
-"xmgrace"_#xmgrace
+"xmgrace"_#xmgrace :ul
 
+:line
 :line
 
-amber2lmp tool :h3,link(amber)
+amber2lmp tool :h4,link(amber)
 
 The amber2lmp sub-directory contains two Python scripts for converting
 files back-and-forth between the AMBER MD code and LAMMPS.  See the
@@ -90,7 +92,7 @@ necessary modifications yourself.
 
 :line
 
-binary2txt tool :h3,link(binary)
+binary2txt tool :h4,link(binary)
 
 The file binary2txt.cpp converts one or more binary LAMMPS dump file
 into ASCII text files.  The syntax for running the tool is
@@ -103,7 +105,7 @@ since binary files are not compatible across all platforms.
 
 :line
 
-ch2lmp tool :h3,link(charmm)
+ch2lmp tool :h4,link(charmm)
 
 The ch2lmp sub-directory contains tools for converting files
 back-and-forth between the CHARMM MD code and LAMMPS.
@@ -128,7 +130,7 @@ Chris Lorenz (chris.lorenz at kcl.ac.uk), King's College London.
 
 :line
 
-chain tool :h3,link(chain)
+chain tool :h4,link(chain)
 
 The file chain.f creates a LAMMPS data file containing bead-spring
 polymer chains and/or monomer solvent atoms.  It uses a text file
@@ -145,7 +147,7 @@ system for the "chain benchmark"_Section_perf.html.
 
 :line
 
-colvars tools :h3,link(colvars)
+colvars tools :h4,link(colvars)
 
 The colvars directory contains a collection of tools for postprocessing
 data produced by the colvars collective variable library.
@@ -167,7 +169,7 @@ gmail.com) at ICTP, Italy.
 
 :line
 
-createatoms tool :h3,link(createatoms)
+createatoms tool :h4,link(createatoms)
 
 The tools/createatoms directory contains a Fortran program called
 createAtoms.f which can generate a variety of interesting crystal
@@ -180,7 +182,7 @@ The tool is authored by Xiaowang Zhou (Sandia), xzhou at sandia.gov.
 
 :line
 
-doxygen tool :h3,link(doxygen)
+doxygen tool :h4,link(doxygen)
 
 The tools/doxygen directory contains a shell script called
 doxygen.sh which can generate a call graph and API lists using
@@ -192,7 +194,7 @@ The tool is authored by Nandor Tamaskovics, numericalfreedom at googlemail.com.
 
 :line
 
-drude tool :h3,link(drude)
+drude tool :h4,link(drude)
 
 The tools/drude directory contains a Python script called
 polarizer.py which can add Drude oscillators to a LAMMPS
@@ -205,7 +207,7 @@ at univ-bpclermont.fr, alain.dequidt at univ-bpclermont.fr
 
 :line
 
-eam database tool :h3,link(eamdb)
+eam database tool :h4,link(eamdb)
 
 The tools/eam_database directory contains a Fortran program that will
 generate EAM alloy setfl potential files for any combination of 16
@@ -221,7 +223,7 @@ X. W. Zhou, R. A. Johnson, and H. N. G. Wadley, Phys. Rev. B, 69,
 
 :line
 
-eam generate tool :h3,link(eamgn)
+eam generate tool :h4,link(eamgn)
 
 The tools/eam_generate directory contains several one-file C programs
 that convert an analytic formula into a tabulated "embedded atom
@@ -234,7 +236,7 @@ The source files and potentials were provided by Gerolf Ziegenhain
 
 :line
 
-eff tool :h3,link(eff)
+eff tool :h4,link(eff)
 
 The tools/eff directory contains various scripts for generating
 structures and post-processing output for simulations using the
@@ -245,7 +247,7 @@ These tools were provided by Andres Jaramillo-Botero at CalTech
 
 :line
 
-emacs tool :h3,link(emacs)
+emacs tool :h4,link(emacs)
 
 The tools/emacs directory contains a Lips add-on file for Emacs that
 enables a lammps-mode for editing of input scripts when using Emacs,
@@ -256,7 +258,7 @@ These tools were provided by Aidan Thompson at Sandia
 
 :line
 
-fep tool :h3,link(fep)
+fep tool :h4,link(fep)
 
 The tools/fep directory contains Python scripts useful for
 post-processing results from performing free-energy perturbation
@@ -269,7 +271,7 @@ See README file in the tools/fep directory.
 
 :line
 
-i-pi tool :h3,link(ipi)
+i-pi tool :h4,link(ipi)
 
 The tools/i-pi directory contains a version of the i-PI package, with
 all the LAMMPS-unrelated files removed.  It is provided so that it can
@@ -286,7 +288,7 @@ calculations with LAMMPS.
 
 :line
 
-ipp tool :h3,link(ipp)
+ipp tool :h4,link(ipp)
 
 The tools/ipp directory contains a Perl script ipp which can be used
 to facilitate the creation of a complicated file (say, a lammps input
@@ -300,7 +302,7 @@ tools/createatoms tool's input file.
 
 :line
 
-kate tool :h3,link(kate)
+kate tool :h4,link(kate)
 
 The file in the tools/kate directory is an add-on to the Kate editor
 in the KDE suite that allow syntax highlighting of LAMMPS input
@@ -311,7 +313,7 @@ The file was provided by Alessandro Luigi Sellerio
 
 :line
 
-lmp2arc tool :h3,link(arc)
+lmp2arc tool :h4,link(arc)
 
 The lmp2arc sub-directory contains a tool for converting LAMMPS output
 files to the format for Accelrys' Insight MD code (formerly
@@ -327,7 +329,7 @@ Greathouse at Sandia (jagreat at sandia.gov).
 
 :line
 
-lmp2cfg tool :h3,link(cfg)
+lmp2cfg tool :h4,link(cfg)
 
 The lmp2cfg sub-directory contains a tool for converting LAMMPS output
 files into a series of *.cfg files which can be read into the
@@ -338,7 +340,7 @@ This tool was written by Ara Kooser at Sandia (askoose at sandia.gov).
 
 :line
 
-matlab tool :h3,link(matlab)
+matlab tool :h4,link(matlab)
 
 The matlab sub-directory contains several "MATLAB"_matlabhome scripts for
 post-processing LAMMPS output.  The scripts include readers for log
@@ -356,7 +358,7 @@ These scripts were written by Arun Subramaniyan at Purdue Univ
 
 :line
 
-micelle2d tool :h3,link(micelle)
+micelle2d tool :h4,link(micelle)
 
 The file micelle2d.f creates a LAMMPS data file containing short lipid
 chains in a monomer solution.  It uses a text file containing lipid
@@ -369,11 +371,11 @@ micelle2d < def.micelle2d > data.file :pre
 
 See the def.micelle2d file in the tools directory for an example of a
 definition file.  This tool was used to create the system for the
-"micelle example"_Section_example.html.
+"micelle example"_Examples.html.
 
 :line
 
-moltemplate tool :h3,link(moltemplate)
+moltemplate tool :h4,link(moltemplate)
 
 The moltemplate sub-directory contains a Python-based tool for
 building molecular systems based on a text-file description, and
@@ -387,7 +389,7 @@ supports it.  It has its own WWW page at
 
 :line
 
-msi2lmp tool :h3,link(msi)
+msi2lmp tool :h4,link(msi)
 
 The msi2lmp sub-directory contains a tool for creating LAMMPS template
 input and data files from BIOVIA's Materias Studio files (formerly Accelrys'
@@ -404,7 +406,7 @@ See the README file in the tools/msi2lmp folder for more information.
 
 :line
 
-phonon tool :h3,link(phonon)
+phonon tool :h4,link(phonon)
 
 The phonon sub-directory contains a post-processing tool useful for
 analyzing the output of the "fix phonon"_fix_phonon.html command in
@@ -419,7 +421,7 @@ University.
 
 :line
 
-polybond tool :h3,link(polybond)
+polybond tool :h4,link(polybond)
 
 The polybond sub-directory contains a Python-based tool useful for
 performing "programmable polymer bonding".  The Python file
@@ -433,7 +435,7 @@ This tool was written by Zachary Kraus at Georgia Tech.
 
 :line
 
-pymol_asphere tool :h3,link(pymol)
+pymol_asphere tool :h4,link(pymol)
 
 The pymol_asphere sub-directory contains a tool for converting a
 LAMMPS dump file that contains orientation info for ellipsoidal
@@ -451,7 +453,7 @@ This tool was written by Mike Brown at Sandia.
 
 :line
 
-python tool :h3,link(pythontools)
+python tool :h4,link(pythontools)
 
 The python sub-directory contains several Python scripts
 that perform common LAMMPS post-processing tasks, such as:
@@ -467,7 +469,7 @@ README for more info on Pizza.py and how to use these scripts.
 
 :line
 
-reax tool :h3,link(reax_tool)
+reax tool :h4,link(reax_tool)
 
 The reax sub-directory contains stand-alond codes that can
 post-process the output of the "fix reax/bonds"_fix_reax_bonds.html
@@ -478,7 +480,7 @@ These tools were written by Aidan Thompson at Sandia.
 
 :line
 
-smd tool :h3,link(smd)
+smd tool :h4,link(smd)
 
 The smd sub-directory contains a C++ file dump2vtk_tris.cpp and
 Makefile which can be compiled and used to convert triangle output
@@ -494,7 +496,7 @@ Ernst Mach Institute in Germany (georg.ganzenmueller at emi.fhg.de).
 
 :line
 
-vim tool :h3,link(vim)
+vim tool :h4,link(vim)
 
 The files in the tools/vim directory are add-ons to the VIM editor
 that allow easier editing of LAMMPS input scripts.  See the README.txt
@@ -505,7 +507,7 @@ ziegenhain.com)
 
 :line
 
-xmgrace tool :h3,link(xmgrace)
+xmgrace tool :h4,link(xmgrace)
 
 The files in the tools/xmgrace directory can be used to plot the
 thermodynamic data in LAMMPS log files via the xmgrace plotting
@@ -517,4 +519,3 @@ simulation.
 See the README file for details.
 
 These files were provided by Vikas Varshney (vv0210 at gmail.com)
-
diff --git a/doc/src/atom_style.txt b/doc/src/atom_style.txt
index 5421e467aaf968be0c9d172a06702f5020059fde..442bb5ac700c9dfe02b2f017cf2809348386c035 100644
--- a/doc/src/atom_style.txt
+++ b/doc/src/atom_style.txt
@@ -255,7 +255,7 @@ with another molecular style that stores bond,angle,etc info on a
 per-atom basis.
 
 LAMMPS can be extended with new atom styles as well as new body
-styles; see "this section"_Section_modify.html.
+styles; see the "Modify"_Modify.html doc page.
 
 :line
 
diff --git a/doc/src/body.txt b/doc/src/body.txt
index 8d49efdae40eed30f9c7ec82e704adc3aef44771..4a39ac25d8c2719f3c7a24ba8559439c4003c808 100644
--- a/doc/src/body.txt
+++ b/doc/src/body.txt
@@ -27,19 +27,17 @@ styles supported by LAMMPS are as follows.  The name in the first
 column is used as the {bstyle} argument for the "atom_style
 body"_atom_style.html command.
 
-{nparticle} | rigid body with N sub-particles |
-{rounded/polygon} | 2d convex polygon with N vertices :tb(c=2,s=|)
+{nparticle} : rigid body with N sub-particles
+{rounded/polygon} : 2d polygons with N vertices
+{rounded/polyhedron} : 3d polyhedra with N vertices, E edges and F faces :tb(s=:)
 
 The body style determines what attributes are stored for each body and
 thus how they can be used to compute pairwise body/body or
 bond/non-body (point particle) interactions.  More details of each
 style are described below.
 
-NOTE: The rounded/polygon style listed in the table above and
-described below has not yet been relesed in LAMMPS.  It will be soon.
-
-We hope to add more styles in the future.  See "Section
-10.12"_Section_modify.html#mod_12 for details on how to add a new body
+More styles may be added in the future.  See the "Modify
+body"_Modify_body.html doc page for details on how to add a new body
 style to the code.
 
 :line
@@ -61,7 +59,7 @@ the simple particles.
 By contrast, when body particles are used, LAMMPS treats an entire
 body as a single particle for purposes of computing pairwise
 interactions, building neighbor lists, migrating particles between
-processors, outputting particles to a dump file, etc.  This means that
+processors, output of particles to a dump file, etc.  This means that
 interactions between pairs of bodies or between a body and non-body
 (point) particle need to be encoded in an appropriate pair style.  If
 such a pair style were to mimic the "fix rigid"_fix_rigid.html model,
@@ -72,17 +70,20 @@ single body/body interaction was computed.
 Thus it only makes sense to use body particles and develop such a pair
 style, when particle/particle interactions are more complex than what
 the "fix rigid"_fix_rigid.html command can already calculate.  For
-example, if particles have one or more of the following attributes:
+example, consider particles with one or more of the following
+attributes:
 
 represented by a surface mesh
 represented by a collection of geometric entities (e.g. planes + spheres)
 deformable
 internal stress that induces fragmentation :ul
 
-then the interaction between pairs of particles is likely to be more
-complex than the summation of simple sub-particle interactions.  An
-example is contact or frictional forces between particles with planar
-surfaces that inter-penetrate.
+For these models, the interaction between pairs of particles is likely
+to be more complex than the summation of simple pairwise interactions.
+An example is contact or frictional forces between particles with
+planar surfaces that inter-penetrate.  Likewise, the body particle may
+store internal state, such as a stress tensor used to compute a
+fracture criterion.
 
 These are additional LAMMPS commands that can be used with body
 particles of different styles
@@ -130,7 +131,9 @@ x1 y1 z1
 ...
 xN yN zN :pre
 
-N is the number of sub-particles in the body particle.  M = 6 + 3*N.
+where M = 6 + 3*N, and N is the number of sub-particles in the body
+particle.  
+
 The integer line has a single value N.  The floating point line(s)
 list 6 moments of inertia followed by the coordinates of the N
 sub-particles (x1 to zN) as 3N values.  These values can be listed on
@@ -175,15 +178,18 @@ The {bflag2} argument is ignored.
 
 [Specifics of body style rounded/polygon:]
 
-NOTE: Aug 2016 - This body style has not yet been added to LAMMPS.
-The info below is a placeholder.
+The {rounded/polygon} body style represents body particles as a 2d
+polygon with a variable number of N vertices.  This style can only be
+used for 2d models; see the "boundary"_boundary.html command.  See the
+"pair_style body/rounded/polygon" doc page for a diagram of two
+squares with rounded circles at the vertices.  Special cases for N = 1
+(circle) and N = 2 (rod with rounded ends) can also be specified.
+
+One use of this body style is for 2d discrete element models, as
+described in "Fraige"_#body-Fraige.
 
-The {rounded/polygon} body style represents body particles as a convex
-polygon with a variable number N > 2 of vertices, which can only be
-used for 2d models.  One example use of this body style is for 2d
-discrete element models, as described in "Fraige"_#Fraige.  Similar to
-body style {nparticle}, the atom_style body command for this body
-style takes two additional arguments:
+Similar to body style {nparticle}, the atom_style body command for
+this body style takes two additional arguments:
 
 atom_style body rounded/polygon Nmin Nmax
 Nmin = minimum # of vertices in any body in the system
@@ -203,17 +209,20 @@ x1 y1 z1
 ...
 xN yN zN
 i j j k k ...
-radius :pre
+diameter :pre
 
-N is the number of vertices in the body particle.  M = 6 + 3*N + 2*N +
-1.  The integer line has a single value N.  The floating point line(s)
+where M = 6 + 3*N + 2*N + 1, and N is the number of vertices in the
+body particle.
+
+The integer line has a single value N.  The floating point line(s)
 list 6 moments of inertia followed by the coordinates of the N
-vertices (x1 to zN) as 3N values, followed by 2N vertex indices
-corresponding to the end points of the N edges, followed by a single
-radius value = the smallest circle encompassing the polygon.  That
-last value is used to facilitate the body/body contact detection.
-These floating-point values can be listed on as many lines as you
-wish; see the "read_data"_read_data.html command for more details.
+vertices (x1 to zN) as 3N values (with z = 0.0 for each), followed by
+2N vertex indices corresponding to the end points of the N edges,
+followed by a single diameter value = the rounded diameter of the
+circle that surrounds each vertex. The diameter value can be different
+for each body particle. These floating-point values can be listed on
+as many lines as you wish; see the "read_data"_read_data.html command
+for more details.
 
 The 6 moments of inertia (ixx,iyy,izz,ixy,ixz,iyz) should be the
 values consistent with the current orientation of the rigid body
@@ -225,8 +234,11 @@ from the center-of-mass of the body particle.  The center-of-mass
 position of the particle is specified by the x,y,z values in the
 {Atoms} section of the data file.
 
-For example, the following information would specify a square
-particles whose edge length is sqrt(2):
+For example, the following information would specify a square particle
+whose edge length is sqrt(2) and rounded diameter is 1.0.  The
+orientation of the square is aligned with the xy coordinate axes which
+is consistent with the 6 moments of inertia: ixx iyy izz ixy ixz iyz =
+1 1 4 0 0 0. Note that only Izz matters in 2D simulations.
 
 3 1 27
 4
@@ -235,12 +247,178 @@ particles whose edge length is sqrt(2):
 -0.7071 0.7071 0
 0.7071 0.7071 0
 0.7071 -0.7071 0
-0 1 1 2 2 3 3 0
+0 1
+1 2
+2 3
+3 0
 1.0 :pre
 
+A rod in 2D, whose length is 4.0, mass 1.0, rounded at two ends
+by circles of diameter 0.5, is specified as follows:
+
+1 1 13
+2
+1 1 1.33333 0 0 0
+-2 0 0
+2 0 0
+0.5 :pre
+
+A disk, whose diameter is 3.0, mass 1.0, is specified as follows:
+
+1 1 10
+1
+1 1 4.5 0 0 0
+0 0 0
+3.0 :pre
+
 The "pair_style body/rounded/polygon"_pair_body_rounded_polygon.html
 command can be used with this body style to compute body/body
-interactions.
+interactions.  The "fix wall/body/polygon"_fix_wall_body_polygon.html
+command can be used with this body style to compute the interaction of
+body particles with a wall.
+
+:line
+
+[Specifics of body style rounded/polyhedron:]
+
+The {rounded/polyhedron} body style represents body particles as a 3d
+polyhedron with a variable number of N vertices, E edges and F faces.
+This style can only be used for 3d models; see the
+"boundary"_boundary.html command.  See the "pair_style
+body/rounded/polygon" doc page for a diagram of a two 2d squares with
+rounded circles at the vertices.  A 3d cube with rounded spheres at
+the 8 vertices and 12 rounded edges would be similar.  Special cases
+for N = 1 (sphere) and N = 2 (rod with rounded ends) can also be
+specified.
+
+This body style is for 3d discrete element models, as described in
+"Wang"_#body-Wang.
+
+Similar to body style {rounded/polygon}, the atom_style body command
+for this body style takes two additional arguments:
+
+atom_style body rounded/polyhedron Nmin Nmax
+Nmin = minimum # of vertices in any body in the system
+Nmax = maximum # of vertices in any body in the system :pre
+
+The Nmin and Nmax arguments are used to bound the size of data
+structures used internally by each particle.
+
+When the "read_data"_read_data.html command reads a data file for this
+body style, the following information must be provided for each entry
+in the {Bodies} section of the data file:
+
+atom-ID 3 M
+N E F
+ixx iyy izz ixy ixz iyz
+x1 y1 z1
+...
+xN yN zN
+0 1
+1 2 
+2 3
+...
+0 1 2 -1
+0 2 3 -1
+...
+1 2 3 4
+diameter :pre
+
+where M = 6 + 3*N + 2*E + 4*F + 1, and N is the number of vertices in
+the body particle, E = number of edges, F = number of faces.
+
+The integer line has three values: number of vertices (N), number of
+edges (E) and number of faces (F). The floating point line(s) list 6
+moments of inertia followed by the coordinates of the N vertices (x1
+to zN) as 3N values, followed by 2N vertex indices corresponding to
+the end points of the E edges, then 4*F vertex indices defining F
+faces.  The last value is the diameter value = the rounded diameter of
+the sphere that surrounds each vertex. The diameter value can be
+different for each body particle. These floating-point values can be
+listed on as many lines as you wish; see the
+"read_data"_read_data.html command for more details.  Because the
+maxmimum vertices per face is hard-coded to be 4
+(i.e. quadrilaterals), faces with more than 4 vertices need to be
+split into triangles or quadrilaterals.  For triangular faces, the
+last vertex index should be set to -1.
+
+The ordering of the 4 vertices within a face should follow
+the right-hand rule so that the normal vector of the face points
+outwards from the center of mass.
+
+The 6 moments of inertia (ixx,iyy,izz,ixy,ixz,iyz) should be the
+values consistent with the current orientation of the rigid body
+around its center of mass.  The values are with respect to the
+simulation box XYZ axes, not with respect to the principal axes of the
+rigid body itself.  LAMMPS performs the latter calculation internally.
+The coordinates of each vertex are specified as its x,y,z displacement
+from the center-of-mass of the body particle.  The center-of-mass
+position of the particle is specified by the x,y,z values in the
+{Atoms} section of the data file.
+
+For example, the following information would specify a cubic particle
+whose edge length is 2.0 and rounded diameter is 0.5.
+The orientation of the cube is aligned with the xyz coordinate axes
+which is consistent with the 6 moments of inertia: ixx iyy izz ixy ixz
+iyz = 0.667 0.667 0.667 0 0 0.
+
+1 3 79
+8 12 6
+0.667 0.667 0.667 0 0 0
+1 1 1
+1 -1 1
+-1 -1 1
+-1 1 1
+1 1 -1
+1 -1 -1
+-1 -1 -1
+-1 1 -1
+0 1
+1 2
+2 3
+3 0
+4 5
+5 6
+6 7
+7 4
+0 4
+1 5
+2 6
+3 7
+0 1 2 3
+4 5 6 7
+0 1 5 4
+1 2 6 5
+2 3 7 6
+3 0 4 7
+0.5 :pre
+
+A rod in 3D, whose length is 4.0, mass 1.0 and rounded at two ends
+by circles of diameter 0.5, is specified as follows:
+
+1 1 13
+2
+0 1.33333 1.33333 0 0 0
+-2 0 0
+2 0 0
+0.5 :pre
+
+A sphere whose diameter is 3.0 and mass 1.0, is specified as follows:
+
+1 1 10
+1
+0.9 0.9 0.9 0 0 0
+0 0 0
+3.0 :pre
+
+The "pair_style
+body/rounded/polhedron"_pair_body_rounded_polyhedron.html command can
+be used with this body style to compute body/body interactions.  The
+"fix wall/body/polyhedron"_fix_wall_body_polygon.html command can be
+used with this body style to compute the interaction of body particles
+with a wall.
+
+:line
 
 For output purposes via the "compute
 body/local"_compute_body_local.html and "dump local"_dump.html
@@ -257,10 +435,10 @@ the body particle itself.  These values are calculated using the
 current COM and orientation of the body particle.
 
 For images created by the "dump image"_dump_image.html command, if the
-{body} keyword is set, then each body particle is drawn as a convex
-polygon consisting of N line segments.  Note that the line segments
-are drawn between the N vertices, which does not correspond exactly to
-the physical extent of the body (because the "pair_style
+{body} keyword is set, then each body particle is drawn as a polygon
+consisting of N line segments.  Note that the line segments are drawn
+between the N vertices, which does not correspond exactly to the
+physical extent of the body (because the "pair_style
 rounded/polygon"_pair_body_rounded_polygon.html defines finite-size
 spheres at those point and the line segments between the spheres are
 tangent to the spheres).  The drawn diameter of each line segment is
@@ -269,6 +447,10 @@ determined by the {bflag1} parameter for the {body} keyword.  The
 
 :line
 
-:link(Fraige)
+:link(body-Fraige)
 [(Fraige)] F. Y. Fraige, P. A. Langston, A. J. Matchett, J. Dodds,
 Particuology, 6, 455 (2008).
+
+:link(body-Wang)
+[(Wang)] J. Wang, H. S. Yu, P. A. Langston, F. Y. Fraige, Granular
+Matter, 13, 1 (2011).
diff --git a/doc/src/compute.txt b/doc/src/compute.txt
index c06735d28e3dbe0091b3426eebbf264f1e147ad0..532a5414e38a4f2d3fe7b70790d048703d8987b5 100644
--- a/doc/src/compute.txt
+++ b/doc/src/compute.txt
@@ -153,8 +153,8 @@ via the "compute_modify"_compute_modify.html command.
 
 Computes can be deleted with the "uncompute"_uncompute.html command.
 
-Code for new computes can be added to LAMMPS (see "this
-section"_Section_modify.html of the manual) and the results of their
+Code for new computes can be added to LAMMPS; see the
+"Modify"_Modify.html doc page for details.  The results of their
 calculations accessed in the various ways described above.
 
 :line
diff --git a/doc/src/compute_chunk_atom.txt b/doc/src/compute_chunk_atom.txt
index 3a46f79d160013e96c177c3939454da9a6f4ecc7..00a75f50c439ad4f0896d9e654f332057eacdb02 100644
--- a/doc/src/compute_chunk_atom.txt
+++ b/doc/src/compute_chunk_atom.txt
@@ -275,7 +275,7 @@ previously defined in the input script.  If no bracketed integer is
 appended, the per-atom vector calculated by the compute is used.  If a
 bracketed integer is appended, the Ith column of the per-atom array
 calculated by the compute is used.  Users can also write code for
-their own compute styles and "add them to LAMMPS"_Section_modify.html.
+their own compute styles and "add them to LAMMPS"_Modify.html.
 
 If the style begins with "f_", a fix ID must follow which has been
 previously defined in the input script.  If no bracketed integer is
@@ -285,7 +285,7 @@ calculated by the fix is used.  Note that some fixes only produce
 their values on certain timesteps, which must be compatible with the
 timestep on which this compute accesses the fix, else an error
 results.  Users can also write code for their own fix styles and "add
-them to LAMMPS"_Section_modify.html.
+them to LAMMPS"_Modify.html.
 
 If a value begins with "v_", a variable name for an {atom} or
 {atomfile} style "variable"_variable.html must follow which has been
diff --git a/doc/src/compute_global_atom.txt b/doc/src/compute_global_atom.txt
index 3136b1fd18f849bcf6c69b328983b8aa135d5c50..28b4aa2461b9be2841c5a8cb1253228ab922a5b3 100644
--- a/doc/src/compute_global_atom.txt
+++ b/doc/src/compute_global_atom.txt
@@ -130,7 +130,7 @@ page for details.  If no bracketed integer is appended, the per-atom
 vector calculated by the compute is used.  If a bracketed integer is
 appended, the Ith column of the per-atom array calculated by the
 compute is used.  Users can also write code for their own compute
-styles and "add them to LAMMPS"_Section_modify.html.  See the
+styles and "add them to LAMMPS"_Modify.html.  See the
 discussion above for how I can be specified with a wildcard asterisk
 to effectively specify multiple values.
 
@@ -143,7 +143,7 @@ references the values, else an error results.  If no bracketed integer
 is appended, the per-atom vector calculated by the fix is used.  If a
 bracketed integer is appended, the Ith column of the per-atom array
 calculated by the fix is used.  Users can also write code for their
-own fix style and "add them to LAMMPS"_Section_modify.html.  See the
+own fix style and "add them to LAMMPS"_Modify.html.  See the
 discussion above for how I can be specified with a wildcard asterisk
 to effectively specify multiple values.
 
@@ -168,7 +168,7 @@ page for details.  If no bracketed integer is appended, the vector
 calculated by the compute is used.  If a bracketed integer is
 appended, the Ith column of the array calculated by the compute is
 used.  Users can also write code for their own compute styles and "add
-them to LAMMPS"_Section_modify.html.  See the discussion above for how
+them to LAMMPS"_Modify.html.  See the discussion above for how
 I can be specified with a wildcard asterisk to effectively specify
 multiple values.
 
@@ -181,7 +181,7 @@ global/atom references the values, else an error results.  If no
 bracketed integer is appended, the vector calculated by the fix is
 used.  If a bracketed integer is appended, the Ith column of the array
 calculated by the fix is used.  Users can also write code for their
-own fix style and "add them to LAMMPS"_Section_modify.html.  See the
+own fix style and "add them to LAMMPS"_Modify.html.  See the
 discussion above for how I can be specified with a wildcard asterisk
 to effectively specify multiple values.
 
diff --git a/doc/src/compute_reduce.txt b/doc/src/compute_reduce.txt
index 07d3c3bda7b88e277f36cb2e839398763488ca40..48115a08861e6e272ea71cb86fdb0276c00aedee 100644
--- a/doc/src/compute_reduce.txt
+++ b/doc/src/compute_reduce.txt
@@ -116,7 +116,7 @@ per-atom or local quantities.  See the individual
 is appended, the vector calculated by the compute is used.  If a
 bracketed integer is appended, the Ith column of the array calculated
 by the compute is used.  Users can also write code for their own
-compute styles and "add them to LAMMPS"_Section_modify.html.  See the
+compute styles and "add them to LAMMPS"_Modify.html.  See the
 discussion above for how I can be specified with a wildcard asterisk
 to effectively specify multiple values.
 
@@ -129,9 +129,9 @@ references the values, else an error results.  If no bracketed integer
 is appended, the vector calculated by the fix is used.  If a bracketed
 integer is appended, the Ith column of the array calculated by the fix
 is used.  Users can also write code for their own fix style and "add
-them to LAMMPS"_Section_modify.html.  See the discussion above for how
-I can be specified with a wildcard asterisk to effectively specify
-multiple values.
+them to LAMMPS"_Modify.html.  See the discussion above for how I can
+be specified with a wildcard asterisk to effectively specify multiple
+values.
 
 If a value begins with "v_", a variable name must follow which has
 been previously defined in the input script.  It must be an
diff --git a/doc/src/compute_slice.txt b/doc/src/compute_slice.txt
index e89c05a0f95a0e2b39d2545a512fe158c4bd39e3..13f40ecf9220c3245f6956c2c4d5908d974bb29e 100644
--- a/doc/src/compute_slice.txt
+++ b/doc/src/compute_slice.txt
@@ -58,7 +58,7 @@ page for details.  If no bracketed integer is appended, the vector
 calculated by the compute is used.  If a bracketed integer is
 appended, the Ith column of the array calculated by the compute is
 used.  Users can also write code for their own compute styles and "add
-them to LAMMPS"_Section_modify.html.
+them to LAMMPS"_Modify.html.
 
 If a value begins with "f_", a fix ID must follow which has been
 previously defined in the input script and which generates a global
@@ -69,7 +69,7 @@ the values, else an error results.  If no bracketed integer is
 appended, the vector calculated by the fix is used.  If a bracketed
 integer is appended, the Ith column of the array calculated by the fix
 is used.  Users can also write code for their own fix style and "add
-them to LAMMPS"_Section_modify.html.
+them to LAMMPS"_Modify.html.
 
 If an input value begins with "v_", a variable name must follow which
 has been previously defined in the input script.  Only vector-style
diff --git a/doc/src/dump.txt b/doc/src/dump.txt
index 438ff1d4e074779f22217e851799a81f1f7ff857..ff1bf6424df10a43ffcefa95cae512ecfbf2f631 100644
--- a/doc/src/dump.txt
+++ b/doc/src/dump.txt
@@ -1,4 +1,4 @@
- "LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
+"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
 
 :link(lws,http://lammps.sandia.gov)
 :link(ld,Manual.html)
@@ -184,10 +184,10 @@ file and in what format.  Settings made via the
 individual values and the file itself.
 
 The {atom}, {local}, and {custom} styles create files in a simple text
-format that is self-explanatory when viewing a dump file.  Many of the
-LAMMPS "post-processing tools"_Section_tools.html, including
-"Pizza.py"_http://www.sandia.gov/~sjplimp/pizza.html, work with this
-format, as does the "rerun"_rerun.html command.
+format that is self-explanatory when viewing a dump file.  Some of the
+LAMMPS post-processing tools described on the "Tools"_Tools.html doc
+page, including "Pizza.py"_http://www.sandia.gov/~sjplimp/pizza.html,
+work with this format, as does the "rerun"_rerun.html command.
 
 For post-processing purposes the {atom}, {local}, and {custom} text
 files are self-describing in the following sense.
@@ -413,10 +413,10 @@ If the filename ends with ".bin", the dump file (or files, if "*" or
 will be about the same size as a text version, but will typically
 write out much faster.  Of course, when post-processing, you will need
 to convert it back to text format (see the "binary2txt
-tool"_Section_tools.html#binary) or write your own code to read the
-binary file.  The format of the binary file can be understood by
-looking at the tools/binary2txt.cpp file.  This option is only
-available for the {atom} and {custom} styles.
+tool"_Tools.html#binary) or write your own code to read the binary
+file.  The format of the binary file can be understood by looking at
+the tools/binary2txt.cpp file.  This option is only available for the
+{atom} and {custom} styles.
 
 If the filename ends with ".gz", the dump file (or files, if "*" or "%"
 is also used) is written in gzipped format.  A gzipped dump file will
@@ -625,9 +625,9 @@ The {d_name} and {i_name} attributes allow to output custom per atom
 floating point or integer properties that are managed by
 "fix property/atom"_fix_property_atom.html.
 
-See "Section 10"_Section_modify.html of the manual for information
-on how to add new compute and fix styles to LAMMPS to calculate
-per-atom quantities which could then be output into dump files.
+See the "Modify"_Modify.html doc page for information on how to add
+new compute and fix styles to LAMMPS to calculate per-atom quantities
+which could then be output into dump files.
 
 :line
 
diff --git a/doc/src/dump_image.txt b/doc/src/dump_image.txt
index 3fa267d2b099a252bce78e49d24c69609dffac2a..c1732be972f6502111c71fbc411152e223c9053f 100644
--- a/doc/src/dump_image.txt
+++ b/doc/src/dump_image.txt
@@ -606,9 +606,9 @@ supported. :l
 
 :line
 
-See "Section 10"_Section_modify.html of the manual for information
-on how to add new compute and fix styles to LAMMPS to calculate
-per-atom quantities which could then be output into dump files.
+See the "Modify"_Modify.html doc page for information on how to add
+new compute and fix styles to LAMMPS to calculate per-atom quantities
+which could then be output into dump files.
 
 :line
 
diff --git a/doc/src/fix.txt b/doc/src/fix.txt
index e54a918cd0e2d876088f9cc76a4a52136df71a7e..ba2088576f1b4137d61d89509d2e6089026864f4 100644
--- a/doc/src/fix.txt
+++ b/doc/src/fix.txt
@@ -30,9 +30,9 @@ Set a fix that will be applied to a group of atoms.  In LAMMPS, a
 timestepping or minimization.  Examples include updating of atom
 positions and velocities due to time integration, controlling
 temperature, applying constraint forces to atoms, enforcing boundary
-conditions, computing diagnostics, etc.  There are dozens of fixes
-defined in LAMMPS and new ones can be added; see "this
-section"_Section_modify.html for a discussion.
+conditions, computing diagnostics, etc.  There are hundredes of fixes
+defined in LAMMPS and new ones can be added; see the
+"Modify"_Modify.html doc page for details.
 
 Fixes perform their operations at different stages of the timestep.
 If 2 or more fixes operate at the same stage of the timestep, they are
diff --git a/doc/src/fix_ave_atom.txt b/doc/src/fix_ave_atom.txt
index 3251125a5d2f21e8f9cdeea958112a5a23b59506..23e4ed235b2d21c3c9cde5df0207781b448d69c2 100644
--- a/doc/src/fix_ave_atom.txt
+++ b/doc/src/fix_ave_atom.txt
@@ -124,7 +124,7 @@ appended, the per-atom vector calculated by the compute is used.  If a
 bracketed term containing an index I is appended, the Ith column of
 the per-atom array calculated by the compute is used.  Users can also
 write code for their own compute styles and "add them to
-LAMMPS"_Section_modify.html.  See the discussion above for how I can
+LAMMPS"_Modify.html.  See the discussion above for how I can
 be specified with a wildcard asterisk to effectively specify multiple
 values.
 
@@ -136,8 +136,8 @@ the per-atom array calculated by the fix is used.  Note that some
 fixes only produce their values on certain timesteps, which must be
 compatible with {Nevery}, else an error will result.  Users can also
 write code for their own fix styles and "add them to
-LAMMPS"_Section_modify.html.  See the discussion above for how I can
-be specified with a wildcard asterisk to effectively specify multiple
+LAMMPS"_Modify.html.  See the discussion above for how I can be
+specified with a wildcard asterisk to effectively specify multiple
 values.
 
 If a value begins with "v_", a variable name must follow which has
diff --git a/doc/src/fix_ave_chunk.txt b/doc/src/fix_ave_chunk.txt
index a8691d376772f458d5c0ed82376fcd0154b7a69a..8e2a09e33fb4a4da2872780fad28fb3f3dc54769 100644
--- a/doc/src/fix_ave_chunk.txt
+++ b/doc/src/fix_ave_chunk.txt
@@ -263,7 +263,7 @@ previously defined in the input script.  If no bracketed integer is
 appended, the per-atom vector calculated by the compute is used.  If a
 bracketed integer is appended, the Ith column of the per-atom array
 calculated by the compute is used.  Users can also write code for
-their own compute styles and "add them to LAMMPS"_Section_modify.html.
+their own compute styles and "add them to LAMMPS"_Modify.html.
 See the discussion above for how I can be specified with a wildcard
 asterisk to effectively specify multiple values.
 
@@ -274,7 +274,7 @@ bracketed integer is appended, the Ith column of the per-atom array
 calculated by the fix is used.  Note that some fixes only produce
 their values on certain timesteps, which must be compatible with
 {Nevery}, else an error results.  Users can also write code for their
-own fix styles and "add them to LAMMPS"_Section_modify.html.  See the
+own fix styles and "add them to LAMMPS"_Modify.html.  See the
 discussion above for how I can be specified with a wildcard asterisk
 to effectively specify multiple values.
 
diff --git a/doc/src/fix_ave_correlate.txt b/doc/src/fix_ave_correlate.txt
index 371f2f66a88f5394bac76c74e18a811939eb6961..98f352cb74ea0ed97e05324d2980c46bd7147ca1 100644
--- a/doc/src/fix_ave_correlate.txt
+++ b/doc/src/fix_ave_correlate.txt
@@ -176,7 +176,7 @@ output"_thermo_style.html or other fixes such as "fix nvt"_fix_nh.html
 or "fix temp/rescale"_fix_temp_rescale.html.  See the doc pages for
 these commands which give the IDs of these computes.  Users can also
 write code for their own compute styles and "add them to
-LAMMPS"_Section_modify.html.
+LAMMPS"_Modify.html.
 
 If a value begins with "f_", a fix ID must follow which has been
 previously defined in the input script.  If no bracketed term is
@@ -189,7 +189,7 @@ values.
 Note that some fixes only produce their values on certain timesteps,
 which must be compatible with {Nevery}, else an error will result.
 Users can also write code for their own fix styles and "add them to
-LAMMPS"_Section_modify.html.
+LAMMPS"_Modify.html.
 
 If a value begins with "v_", a variable name must follow which has
 been previously defined in the input script.  Only equal-style or
diff --git a/doc/src/fix_ave_histo.txt b/doc/src/fix_ave_histo.txt
index 043f0e22be3c7dda7b85209b9b6c53c3578c5b30..5155f42e7bca0335d29ac16566051255a2ff3a89 100644
--- a/doc/src/fix_ave_histo.txt
+++ b/doc/src/fix_ave_histo.txt
@@ -183,11 +183,11 @@ Note that there is a "compute reduce"_compute_reduce.html command
 which can sum per-atom quantities into a global scalar or vector which
 can thus be accessed by fix ave/histo.  Or it can be a compute defined
 not in your input script, but by "thermodynamic
-output"_thermo_style.html or other fixes such as "fix
-nvt"_fix_nh.html or "fix temp/rescale"_fix_temp_rescale.html.  See
-the doc pages for these commands which give the IDs of these computes.
-Users can also write code for their own compute styles and "add them
-to LAMMPS"_Section_modify.html.
+output"_thermo_style.html or other fixes such as "fix nvt"_fix_nh.html
+or "fix temp/rescale"_fix_temp_rescale.html.  See the doc pages for
+these commands which give the IDs of these computes.  Users can also
+write code for their own compute styles and "add them to
+LAMMPS"_Modify.html.
 
 If a value begins with "f_", a fix ID must follow which has been
 previously defined in the input script.  If {mode} = scalar, then if
@@ -204,7 +204,7 @@ values.
 Note that some fixes only produce their values on certain timesteps,
 which must be compatible with {Nevery}, else an error will result.
 Users can also write code for their own fix styles and "add them to
-LAMMPS"_Section_modify.html.
+LAMMPS"_Modify.html.
 
 If a value begins with "v_", a variable name must follow which has
 been previously defined in the input script.  If {mode} = scalar, then
diff --git a/doc/src/fix_ave_time.txt b/doc/src/fix_ave_time.txt
index 266e3f0e38488694dfce0b442a607a6851483377..b61f56cf0274ef732216e2dcc1020a1bd8f4d4ee 100644
--- a/doc/src/fix_ave_time.txt
+++ b/doc/src/fix_ave_time.txt
@@ -168,7 +168,7 @@ output"_thermo_style.html or other fixes such as "fix
 nvt"_fix_nh.html or "fix temp/rescale"_fix_temp_rescale.html.  See
 the doc pages for these commands which give the IDs of these computes.
 Users can also write code for their own compute styles and "add them
-to LAMMPS"_Section_modify.html.
+to LAMMPS"_Modify.html.
 
 If a value begins with "f_", a fix ID must follow which has been
 previously defined in the input script.  If {mode} = scalar, then if
@@ -184,7 +184,7 @@ specify multiple values.
 Note that some fixes only produce their values on certain timesteps,
 which must be compatible with {Nevery}, else an error will result.
 Users can also write code for their own fix styles and "add them to
-LAMMPS"_Section_modify.html.
+LAMMPS"_Modify.html.
 
 If a value begins with "v_", a variable name must follow which has
 been previously defined in the input script.  If {mode} = scalar, then
diff --git a/doc/src/fix_controller.txt b/doc/src/fix_controller.txt
index cfb26138fdaa468c3074b1ef6fa1f1dfe6c6eb8c..b8d2cb43be4b2fbc30d70034531969e4325a4709 100644
--- a/doc/src/fix_controller.txt
+++ b/doc/src/fix_controller.txt
@@ -139,7 +139,7 @@ for details.  If no bracketed integer is appended, the scalar
 calculated by the compute is used.  If a bracketed integer is
 appended, the Ith value of the vector calculated by the compute is
 used.  Users can also write code for their own compute styles and "add
-them to LAMMPS"_Section_modify.html.
+them to LAMMPS"_Modify.html.
 
 If {pvar} begins with "f_", a fix ID must follow which has been
 previously defined in the input script and which generates a global
@@ -150,7 +150,7 @@ references the values, or else an error results.  If no bracketed integer
 is appended, the scalar calculated by the fix is used.  If a bracketed
 integer is appended, the Ith value of the vector calculated by the fix
 is used.  Users can also write code for their own fix style and "add
-them to LAMMPS"_Section_modify.html.
+them to LAMMPS"_Modify.html.
 
 If {pvar} begins with "v_", a variable name must follow which has been
 previously defined in the input script.  Only equal-style variables
diff --git a/doc/src/fix_external.txt b/doc/src/fix_external.txt
index b28d33446fe6df61d6efd46017dc37c4cf6f61ee..30e34b48587f2dd276dcd9bb50f398bc95f80a45 100644
--- a/doc/src/fix_external.txt
+++ b/doc/src/fix_external.txt
@@ -34,8 +34,7 @@ This fix allows external programs that are running LAMMPS through its
 "library interface"_Section_howto.html#howto_19 to modify certain
 LAMMPS properties on specific timesteps, similar to the way other
 fixes do.  The external driver can be a "C/C++ or Fortran
-program"_Section_howto.html#howto_19 or a "Python
-script"_Section_python.html.
+program"_Section_howto.html#howto_19 or a "Python script"_Python.html.
 
 :line
 
diff --git a/doc/src/fix_gcmc.txt b/doc/src/fix_gcmc.txt
index 38f0fb95ce0530d425689b0daa9052e6a6995074..191bc32b1499f1f4555330c8347bf49cb2472634 100644
--- a/doc/src/fix_gcmc.txt
+++ b/doc/src/fix_gcmc.txt
@@ -349,7 +349,7 @@ in the context of NVT dynamics.
 NOTE: If the density of the cell is initially very small or zero, and
 increases to a much larger density after a period of equilibration,
 then certain quantities that are only calculated once at the start
-(kspace parameters, tail corrections) may no longer be accurate.  The
+(kspace parameters) may no longer be accurate.  The
 solution is to start a new simulation after the equilibrium density
 has been reached.
 
diff --git a/doc/src/fix_property_atom.txt b/doc/src/fix_property_atom.txt
index 10bb89c94cad5b28414578f621cab34c31266165..95fc2c424db6252553a8cd51583a8aa85bbe5d05 100644
--- a/doc/src/fix_property_atom.txt
+++ b/doc/src/fix_property_atom.txt
@@ -194,9 +194,9 @@ dump 1 all custom 100 tmp.dump id x y z c_1\[1\] c_1\[2\] :pre
 
 If you wish to add new "pair styles"_pair_style.html,
 "fixes"_fix.html, or "computes"_compute.html that use the per-atom
-properties defined by this fix, see "Section
-modify"_Section_modify.html#mod_1 of the manual which has some details
-on how the properties can be accessed from added classes.
+properties defined by this fix, see the "Modify atom"_Modify_atom.html
+doc page which has details on how the properties can be accessed from
+added classes.
 
 :line
 
diff --git a/doc/src/fix_vector.txt b/doc/src/fix_vector.txt
index 47b3cfc67a2dbe667ce2af1799368b50dc741f50..385d24cff19594096b6193443dd88fc8ad3a2f54 100644
--- a/doc/src/fix_vector.txt
+++ b/doc/src/fix_vector.txt
@@ -94,7 +94,7 @@ output"_thermo_style.html or other fixes such as "fix nvt"_fix_nh.html
 or "fix temp/rescale"_fix_temp_rescale.html.  See the doc pages for
 these commands which give the IDs of these computes.  Users can also
 write code for their own compute styles and "add them to
-LAMMPS"_Section_modify.html.
+LAMMPS"_Modify.html.
 
 If a value begins with "f_", a fix ID must follow which has been
 previously defined in the input script.  If no bracketed term is
@@ -105,7 +105,7 @@ calculated by the fix is used.
 Note that some fixes only produce their values on certain timesteps,
 which must be compatible with {Nevery}, else an error will result.
 Users can also write code for their own fix styles and "add them to
-LAMMPS"_Section_modify.html.
+LAMMPS"_Modify.html.
 
 If a value begins with "v_", a variable name must follow which has
 been previously defined in the input script.  An equal-style or
diff --git a/doc/src/fix_wall_body_polygon.txt b/doc/src/fix_wall_body_polygon.txt
new file mode 100644
index 0000000000000000000000000000000000000000..4ba16b56c79fab2c4cecf6798a71a895b862c5cf
--- /dev/null
+++ b/doc/src/fix_wall_body_polygon.txt
@@ -0,0 +1,104 @@
+"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
+
+fix wall/body/polygon command :h3
+
+[Syntax:]
+
+fix ID group-ID wall/body/polygon k_n c_n c_t wallstyle args keyword values ... :pre
+
+ID, group-ID are documented in "fix"_fix.html command :ulb,l
+wall/body/polygon = style name of this fix command :l
+k_n = normal repulsion strength (force/distance or pressure units) :l
+c_n = normal damping coefficient (force/distance or pressure units) :l
+c_t = tangential damping coefficient (force/distance or pressure units) :l
+wallstyle = {xplane} or {yplane} or {zplane} or {zcylinder} :l
+args = list of arguments for a particular style :l
+  {xplane} or {yplane} args = lo hi
+    lo,hi = position of lower and upper plane (distance units), either can be NULL)
+  {zcylinder} args = radius
+    radius = cylinder radius (distance units) :pre
+zero or more keyword/value pairs may be appended to args :l
+keyword = {wiggle} :l
+  {wiggle} values = dim amplitude period
+    dim = {x} or {y} or {z}
+    amplitude = size of oscillation (distance units)
+    period = time of oscillation (time units) :pre
+:ule
+
+[Examples:]
+
+fix 1 all wall/body/polygon 1000.0 20.0 5.0 xplane -10.0 10.0
+
+[Description:]
+
+This fix is for use with 2d models of body particles of style
+{rounded/polygon}.  It bounds the simulation domain with wall(s).  All
+particles in the group interact with the wall when they are close
+enough to touch it.  The nature of the interaction between the wall
+and the polygon particles is the same as that between the polygon
+particles themselves, which is similar to a Hookean potential.  See
+"Section 6.14"_Section_howto.html#howto_14 of the manual and the
+"body"_body.html doc page for more details on using body particles.
+
+The parameters {k_n}, {c_n}, {c_t} have the same meaning and units as
+those specified with the "pair_style
+body/rounded/polygon"_pair_body_rounded_polygon.html command.
+
+The {wallstyle} can be planar or cylindrical.  The 2 planar options
+specify a pair of walls in a dimension.  Wall positions are given by
+{lo} and {hi}.  Either of the values can be specified as NULL if a
+single wall is desired.  For a {zcylinder} wallstyle, the cylinder's
+axis is at x = y = 0.0, and the radius of the cylinder is specified.
+
+Optionally, the wall can be moving, if the {wiggle} keyword is
+appended.
+
+For the {wiggle} keyword, the wall oscillates sinusoidally, similar to
+the oscillations of particles which can be specified by the "fix
+move"_fix_move.html command.  This is useful in packing simulations of
+particles.  The arguments to the {wiggle} keyword specify a dimension
+for the motion, as well as it's {amplitude} and {period}.  Note that
+if the dimension is in the plane of the wall, this is effectively a
+shearing motion.  If the dimension is perpendicular to the wall, it is
+more of a shaking motion.  A {zcylinder} wall can only be wiggled in
+the z dimension.
+
+Each timestep, the position of a wiggled wall in the appropriate {dim}
+is set according to this equation:
+
+position = coord + A - A cos (omega * delta) :pre
+
+where {coord} is the specified initial position of the wall, {A} is
+the {amplitude}, {omega} is 2 PI / {period}, and {delta} is the time
+elapsed since the fix was specified.  The velocity of the wall is set
+to the derivative of this expression.
+
+[Restart, fix_modify, output, run start/stop, minimize info:]
+
+None of the "fix_modify"_fix_modify.html options are relevant to this
+fix.  No global or per-atom quantities are stored by this fix for
+access by various "output commands"_Section_howto.html#howto_15.  No
+parameter of this fix can be used with the {start/stop} keywords of
+the "run"_run.html command.  This fix is not invoked during "energy
+minimization"_minimize.html.
+
+[Restrictions:]
+
+This fix is part of the BODY package.  It is only enabled if LAMMPS
+was built with that package.  See the "Making
+LAMMPS"_Section_start.html#start_3 section for more info.
+
+Any dimension (xy) that has a wall must be non-periodic.
+
+[Related commands:]
+
+"atom_style body"_atom_style.html, "pair_style
+body/rounded/polygon"_pair_body_rounded_polygon.html
+
+[Default:] none
diff --git a/doc/src/fix_wall_body_polyhedron.txt b/doc/src/fix_wall_body_polyhedron.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c937cbdbbc80a6c711c845212a0a47d85d0800be
--- /dev/null
+++ b/doc/src/fix_wall_body_polyhedron.txt
@@ -0,0 +1,103 @@
+"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
+
+fix wall/body/polyhedron command :h3
+
+[Syntax:]
+
+fix ID group-ID wall/body/polyhedron k_n c_n c_t wallstyle args keyword values ... :pre
+
+ID, group-ID are documented in "fix"_fix.html command :ulb,l
+wall/body/polyhedron = style name of this fix command :l
+k_n = normal repulsion strength (force/distance units or pressure units - see discussion below) :l
+c_n = normal damping coefficient (force/distance units or pressure units - see discussion below) :l
+c_t = tangential damping coefficient (force/distance units or pressure units - see discussion below) :l
+wallstyle = {xplane} or {yplane} or {zplane} or {zcylinder} :l
+args = list of arguments for a particular style :l
+  {xplane} or {yplane} args = lo hi
+    lo,hi = position of lower and upper plane (distance units), either can be NULL)
+  {zcylinder} args = radius
+    radius = cylinder radius (distance units) :pre
+zero or more keyword/value pairs may be appended to args :l
+keyword = {wiggle} :l
+  {wiggle} values = dim amplitude period
+    dim = {x} or {y} or {z}
+    amplitude = size of oscillation (distance units)
+    period = time of oscillation (time units) :pre
+:ule
+
+[Examples:]
+
+fix 1 all wall/body/polyhedron 1000.0 20.0 5.0 xplane -10.0 10.0
+
+[Description:]
+
+This fix is for use with 3d models of body particles of style
+{rounded/polyhedron}.  It bounds the simulation domain with wall(s).
+All particles in the group interact with the wall when they are close
+enough to touch it.  The nature of the interaction between the wall
+and the polygon particles is the same as that between the polygon
+particles themselves, which is similar to a Hookean potential.  See
+"Section 6.14"_Section_howto.html#howto_14 of the manual and the
+"body"_body.html doc page for more details on using body particles.
+
+The parameters {k_n}, {c_n}, {c_t} have the same meaning and units as
+those specified with the "pair_style
+body/rounded/polyhedron"_pair_body_rounded_polyhedron.html command.
+
+The {wallstyle} can be planar or cylindrical.  The 3 planar options
+specify a pair of walls in a dimension.  Wall positions are given by
+{lo} and {hi}.  Either of the values can be specified as NULL if a
+single wall is desired.  For a {zcylinder} wallstyle, the cylinder's
+axis is at x = y = 0.0, and the radius of the cylinder is specified.
+
+Optionally, the wall can be moving, if the {wiggle} keyword is appended.
+
+For the {wiggle} keyword, the wall oscillates sinusoidally, similar to
+the oscillations of particles which can be specified by the "fix
+move"_fix_move.html command.  This is useful in packing simulations of
+particles.  The arguments to the {wiggle} keyword specify a dimension
+for the motion, as well as it's {amplitude} and {period}.  Note that
+if the dimension is in the plane of the wall, this is effectively a
+shearing motion.  If the dimension is perpendicular to the wall, it is
+more of a shaking motion.  A {zcylinder} wall can only be wiggled in
+the z dimension.
+
+Each timestep, the position of a wiggled wall in the appropriate {dim}
+is set according to this equation:
+
+position = coord + A - A cos (omega * delta) :pre
+
+where {coord} is the specified initial position of the wall, {A} is
+the {amplitude}, {omega} is 2 PI / {period}, and {delta} is the time
+elapsed since the fix was specified.  The velocity of the wall is set
+to the derivative of this expression.
+
+[Restart, fix_modify, output, run start/stop, minimize info:]
+
+None of the "fix_modify"_fix_modify.html options are relevant to this
+fix.  No global or per-atom quantities are stored by this fix for
+access by various "output commands"_Section_howto.html#howto_15.  No
+parameter of this fix can be used with the {start/stop} keywords of
+the "run"_run.html command.  This fix is not invoked during "energy
+minimization"_minimize.html.
+
+[Restrictions:]
+
+This fix is part of the BODY package.  It is only enabled if
+LAMMPS was built with that package.  See the "Making
+LAMMPS"_Section_start.html#start_3 section for more info.
+
+Any dimension (xyz) that has a wall must be non-periodic.
+
+[Related commands:]
+
+"atom_style body"_atom_style.html, "pair_style
+body/rounded/polyhedron"_pair_body_rounded_polyhedron.html
+
+[Default:] none
diff --git a/doc/src/lammps.book b/doc/src/lammps.book
index 1f181a1bd35bb6e104127e15f66d0c82fa008e70..4274ef48b3be56e6171b48632247b1e4fd2ce415 100644
--- a/doc/src/lammps.book
+++ b/doc/src/lammps.book
@@ -12,12 +12,41 @@ accelerate_kokkos.html
 accelerate_omp.html
 accelerate_opt.html
 Section_howto.html
-Section_example.html
+Examples.html
 Section_perf.html
-Section_tools.html
-Section_modify.html
-Section_python.html
-Section_errors.html
+Tools.html
+Modify.html
+Modify_overview.html
+Modify_contribute.html
+Modify_atom.html
+Modify_pair.html
+Modify_bond.html
+Modify_compute.html
+Modify_fix.html
+Modify_command.html
+Modify_dump.html
+Modify_kspace.html
+Modify_min.html
+Modify_region.html
+Modify_body.html
+Modify_thermo.html
+Modify_variable.html
+Python.html
+Python_overview.html
+Python_run.html
+Python_shlib.html
+Python_install.html
+Python_mpi.html
+Python_test.html
+Python_library.html
+Python_pylammps.html
+Python_examples.html
+Python_call.html
+Errors.html
+Errors_common.html
+Errors_bugs.html
+Errors_messages.html
+Errors_warnings.html
 Section_history.html
 
 lammps_tutorials.html
@@ -283,6 +312,8 @@ fix_vector.html
 fix_viscosity.html
 fix_viscous.html
 fix_wall.html
+fix_wall_body_polygon.html
+fix_wall_body_polyhedron.html
 fix_wall_ees.html
 fix_wall_gran.html
 fix_wall_gran_region.html
@@ -424,8 +455,9 @@ pair_agni.html
 pair_airebo.html
 pair_awpmd.html
 pair_beck.html
-pair_body.html
+pair_body_nparticle.html
 pair_body_rounded_polygon.html
+pair_body_rounded_polyhedron.html
 pair_bop.html
 pair_born.html
 pair_brownian.html
diff --git a/doc/src/package.txt b/doc/src/package.txt
index 5c698934e857bfa31bdceac69bb3296ff76961c3..5fd42f67d3b91b1d67811201b13f5692b17f4761 100644
--- a/doc/src/package.txt
+++ b/doc/src/package.txt
@@ -33,8 +33,10 @@ args = arguments specific to the style :l
         last = ID of last GPU to be used on each node
       {tpa} value = Nthreads
         Nthreads = # of GPU threads used per atom
-      {device} value = device_type
-        device_type = {kepler} or {fermi} or {cypress} or {generic}
+      {device} value = device_type or platform_id:device_type or platform_id:custom,val1,val2,val3,..,val13
+        platform_id = numerical OpenCL platform id (default: -1)
+        device_type = {kepler} or {fermi} or {cypress} or {intel} or {phi} or {generic} or {custom}
+        val1,val2,... = custom OpenCL tune parameters (see below for details)
       {blocksize} value = size
         size = thread block size for pair force computation
   {intel} args = NPhi keyword value ...
@@ -96,6 +98,9 @@ args = arguments specific to the style :l
 package gpu 1
 package gpu 1 split 0.75
 package gpu 2 split -1.0
+package gpu 1 device kepler
+package gpu 1 device 2:generic
+package gpu 1 device custom,32,4,8,256,11,128,256,128,32,64,8,128,128
 package kokkos neigh half comm device
 package omp 0 neigh no
 package omp 4
@@ -244,12 +249,40 @@ the value can improve performance. The number of threads per atom must
 be a power of 2 and currently cannot be greater than 32.
 
 The {device} keyword can be used to tune parameters optimized for a
-specific accelerator, when using OpenCL.  For CUDA, the {device}
-keyword is ignored.  Currently, the device type is limited to NVIDIA
-Kepler, NVIDIA Fermi, AMD Cypress, or a generic device.  More devices
-may be added later.  The default device type can be specified when
-building LAMMPS with the GPU library, via settings in the
-lib/gpu/Makefile that is used.
+specific accelerator and platform when using OpenCL. OpenCL supports
+the concept of a [platform], which represents one or more devices that
+share the same driver (e.g. there would be a different platform for
+GPUs from different vendors or for CPU based accelerator support).
+In LAMMPS only one platform can be active at a time and by default
+the first platform with an accelerator is selected. This is equivalent
+to using a platform ID of -1. The platform ID is a number corresponding
+to the output of the ocl_get_devices tool. The platform ID is passed
+to the GPU library, by prefixing the {device} keyword with that number
+separated by a colon. For CUDA, the {device} keyword is ignored.
+Currently, the device tuning support is limited to NVIDIA Kepler, NVIDIA
+Fermi, AMD Cypress, Intel x86_64 CPU, Intel Xeon Phi, or a generic device.
+More devices may be added later.  The default device type can be
+specified when building LAMMPS with the GPU library, via setting a
+variable in the lib/gpu/Makefile that is used.
+
+In addition, a device type {custom} is available, which is followed by
+13 comma separated numbers, which allows to set those tweakable parameters
+from the package command. It can be combined with the (colon separated)
+platform id. The individual settings are:
+
+MEM_THREADS
+THREADS_PER_ATOM
+THREADS_PER_CHARGE
+BLOCK_PAIR
+MAX_SHARED_TYPES
+BLOCK_NBOR_BUILD
+BLOCK_BIO_PAIR
+BLOCK_ELLIPSE
+WARP_SIZE
+PPPM_BLOCK_1D
+BLOCK_CELL_2D
+BLOCK_CELL_ID
+MAX_BIO_SHARED_TYPES :ul
 
 The {blocksize} keyword allows you to tweak the number of threads used
 per thread block. This number should be a multiple of 32 (for GPUs)
diff --git a/doc/src/pair_body.txt b/doc/src/pair_body_nparticle.txt
similarity index 93%
rename from doc/src/pair_body.txt
rename to doc/src/pair_body_nparticle.txt
index 7899da832bdbf722bb1c5403dd547890bae5cdb1..8c5b6e155d801729a72b99276373ef4b0f525185 100644
--- a/doc/src/pair_body.txt
+++ b/doc/src/pair_body_nparticle.txt
@@ -10,21 +10,21 @@ pair_style body command :h3
 
 [Syntax:]
 
-pair_style body cutoff :pre
+pair_style body/nparticle cutoff :pre
 
 cutoff = global cutoff for interactions (distance units)
 
 [Examples:]
 
-pair_style body 3.0
+pair_style body/nparticle 3.0
 pair_coeff * * 1.0 1.0
 pair_coeff 1 1 1.0 1.5 2.5 :pre
 
 [Description:]
 
-Style {body} is for use with body particles and calculates pairwise
-body/body interactions as well as interactions between body and
-point-particles.  See "Section 6.14"_Section_howto.html#howto_14
+Style {body/nparticle} is for use with body particles and calculates
+pairwise body/body interactions as well as interactions between body
+and point-particles.  See "Section 6.14"_Section_howto.html#howto_14
 of the manual and the "body"_body.html doc page for more details on
 using body particles.
 
diff --git a/doc/src/pair_body_rounded_polygon.txt b/doc/src/pair_body_rounded_polygon.txt
index b6dc2e37b5a80fce04b7b753ffb7e007c4703ae6..9daeb08e9a9e3310380c4b5e40534aecedd59b09 100644
--- a/doc/src/pair_body_rounded_polygon.txt
+++ b/doc/src/pair_body_rounded_polygon.txt
@@ -8,12 +8,127 @@
 
 pair_style body/rounded/polygon command :h3
 
+[Syntax:]
+
+pair_style body/rounded/polygon c_n c_t mu delta_ua cutoff :pre
+
+c_n = normal damping coefficient
+c_t = tangential damping coefficient
+mu = normal friction coefficient during gross sliding
+delta_ua = multiple contact scaling factor
+cutoff = global separation cutoff for interactions (distance units), see below for definition :pre
+
+[Examples:]
+
+pair_style body/rounded/polygon 20.0 5.0 0.0 1.0 0.5
+pair_coeff * * 100.0 1.0
+pair_coeff 1 1 100.0 1.0 :pre
+
 [Description:]
 
-Note: This feature is not yet implemented.
+Style {body/rounded/polygon} is for use with 2d models of body
+particles of style {rounded/polygon}.  It calculates pairwise
+body/body interactions which can include body particles modeled as
+1-vertex circular disks with a specified diameter.  See "Section
+6.14"_Section_howto.html#howto_14 of the manual and the
+"body"_body.html doc page for more details on using body
+rounded/polygon particles.
+
+This pairwise interaction between rounded polygons is described in
+"Fraige"_#pair-Fraige, where a polygon does not have sharp corners,
+but is rounded at its vertices by circles centered on each vertex with
+a specified diameter.  The edges of the polygon are defined between
+pairs of adjacent vertices.  The circle diameter for each polygon is
+specified in the data file read by the "read data"_read_data.html
+command.  This is a 2d discrete element model (DEM) which allows for
+multiple contact points.
+
+Note that when two particles interact, the effective surface of each
+polygon particle is displaced outward from each of its vertices and
+edges by half its circle diameter (as in the diagram below of a gray
+and yellow square particle).  The interaction forces and energies
+between two particles are defined with respect to the separation of
+their respective rounded surfaces, not by the separation of the
+vertices and edges themselves.
+
+This means that the specified cutoff in the pair_style command is the
+cutoff distance, r_c, for the surface separation, \delta_n (see figure
+below).  This is the distance at which two particles no longer
+interact.  If r_c is specified as 0.0, then it is a contact-only
+interaction.  I.e. the two particles must overlap in order to exert a
+repulsive force on each other.  If r_c > 0.0, then the force between
+two particles will be attractive for surface separations from 0 to
+r_c, and repulsive once the particles overlap.
+
+Note that unlike for other pair styles, the specified cutoff is not
+the distance between the centers of two particles at which they stop
+interacting.  This center-to-center distance depends on the shape and
+size of the two particles and their relative orientation.  LAMMPS
+takes that into account when computing the surface separation distance
+and applying the r_c cutoff.
+
+The forces between vertex-vertex, vertex-edge, and edge-edge overlaps
+are given by:
+
+:c,image(Eqs/pair_body_rounded.jpg)
+
+:c,image(JPG/pair_body_rounded.jpg)
+
+Note that F_n and F_t are functions of the surface separation \delta_n
+= d - (R_i + R_j).  In this model, when (R_i + R_j) < d < (R_i + R_j)
++ r_c, that is, 0 < \delta_n < r_c, the cohesive region of the two
+surfaces overlap and the two surfaces are attractive to each other.
+
+In "Fraige"_#pair-Fraige, the tangential friction force between two
+particles that are in contact is modeled differently prior to gross
+sliding (i.e. static friction) and during gross-sliding (kinetic
+friction).  The latter takes place when the tangential deformation
+exceeds the Coulomb frictional limit.  In the current implementation,
+however, we do not take into account frictional history, i.e. we do
+not keep track of how many time steps the two particles have been in
+contact nor calculate the tangential deformation.  Instead, we assume
+that gross sliding takes place as soon as two particles are in
+contact.
+
+The following coefficients must be defined for each pair of atom types
+via the "pair_coeff"_pair_coeff.html command as in the examples above,
+or in the data file read by the "read_data"_read_data.html command:
+
+k_n (energy/distance^2 units)
+k_na (energy/distance^2 units) :ul
+
+Effectively, k_n and k_na are the slopes of the red lines in the plot
+above for force versus surface separation, for \delta_n < 0 and 0 <
+\delta_n < r_c respectively.
+
+[Mixing, shift, table, tail correction, restart, rRESPA info]:
+
+This pair style does not support the "pair_modify"_pair_modify.html
+mix, shift, table, and tail options.
+
+This pair style does not write its information to "binary restart
+files"_restart.html.  Thus, you need to re-specify the pair_style and
+pair_coeff commands in an input script that reads a restart file.
+
+This pair style can only be used via the {pair} keyword of the
+"run_style respa"_run_style.html command.  It does not support the
+{inner}, {middle}, {outer} keywords.
+
+[Restrictions:]
+
+These pair styles are part of the BODY package.  They are only enabled
+if LAMMPS was built with that package.  See the "Making
+LAMMPS"_Section_start.html#start_3 section for more info.
+
+This pair style requires the "newton"_newton.html setting to be "on"
+for pair interactions.
 
 [Related commands:]
 
-"pair_style body"_pair_body.html
+"pair_coeff"_pair_coeff.html
 
 [Default:] none
+
+:link(pair-Fraige)
+[(Fraige)] F. Y. Fraige, P. A. Langston, A. J. Matchett, J. Dodds,
+Particuology, 6, 455 (2008).
diff --git a/doc/src/pair_body_rounded_polyhedron.txt b/doc/src/pair_body_rounded_polyhedron.txt
new file mode 100644
index 0000000000000000000000000000000000000000..dc559feaafb6715e7f4b06800103951725078964
--- /dev/null
+++ b/doc/src/pair_body_rounded_polyhedron.txt
@@ -0,0 +1,130 @@
+"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_style body/rounded/polyhedron command :h3
+
+[Syntax:]
+
+pair_style body/rounded/polyhedron c_n c_t mu delta_ua cutoff :pre
+
+c_n = normal damping coefficient
+c_t = tangential damping coefficient
+mu = normal friction coefficient during gross sliding
+delta_ua = multiple contact scaling factor
+cutoff = global separation cutoff for interactions (distance units), see below for definition :pre
+
+[Examples:]
+
+pair_style body/rounded/polyhedron 20.0 5.0 0.0 1.0 0.5
+pair_coeff * * 100.0 1.0
+pair_coeff 1 1 100.0 1.0 :pre
+
+[Description:]
+
+Style {body/rounded/polygon} is for use with 3d models of body
+particles of style {rounded/polyhedron}.  It calculates pairwise
+body/body interactions which can include body particles modeled as
+1-vertex spheres with a specified diameter.  See "Section
+6.14"_Section_howto.html#howto_14 of the manual and the
+"body"_body.html doc page for more details on using body
+rounded/polyhedron particles.
+
+This pairwise interaction between the rounded polyhedra is described
+in "Wang"_#pair-Wang, where a polyhedron does not have sharp corners
+and edges, but is rounded at its vertices and edges by spheres
+centered on each vertex with a specified diameter.  The edges if the
+polyhedron are defined between pairs of adjacent vertices.  Its faces
+are defined by a loop of edges.  The sphere diameter for each polygon
+is specified in the data file read by the "read data"_read_data.html
+command.  This is a discrete element model (DEM) which allows for
+multiple contact points.
+
+Note that when two particles interact, the effective surface of each
+polyhedron particle is displaced outward from each of its vertices,
+edges, and faces by half its sphere diameter.  The interaction forces
+and energies between two particles are defined with respect to the
+separation of their respective rounded surfaces, not by the separation
+of the vertices, edges, and faces themselves.
+
+This means that the specified cutoff in the pair_style command is the
+cutoff distance, r_c, for the surface separation, \delta_n (see figure
+below).  This is the distance at which two particles no longer
+interact.  If r_c is specified as 0.0, then it is a contact-only
+interaction.  I.e. the two particles must overlap in order to exert a
+repulsive force on each other.  If r_c > 0.0, then the force between
+two particles will be attractive for surface separations from 0 to
+r_c, and repulsive once the particles overlap.
+
+Note that unlike for other pair styles, the specified cutoff is not
+the distance between the centers of two particles at which they stop
+interacting.  This center-to-center distance depends on the shape and
+size of the two particles and their relative orientation.  LAMMPS
+takes that into account when computing the surface separation distance
+and applying the r_c cutoff.
+
+The forces between vertex-vertex, vertex-edge, vertex-face, edge-edge,
+and edge-face overlaps are given by:
+
+:c,image(Eqs/pair_body_rounded.jpg)
+
+:c,image(JPG/pair_body_rounded.jpg)
+
+In "Wang"_#pair-Wang, the tangential friction force between two
+particles that are in contact is modeled differently prior to gross
+sliding (i.e. static friction) and during gross-sliding (kinetic
+friction).  The latter takes place when the tangential deformation
+exceeds the Coulomb frictional limit.  In the current implementation,
+however, we do not take into account frictional history, i.e. we do
+not keep track of how many time steps the two particles have been in
+contact nor calculate the tangential deformation.  Instead, we assume
+that gross sliding takes place as soon as two particles are in
+contact.
+
+The following coefficients must be defined for each pair of atom types
+via the "pair_coeff"_pair_coeff.html command as in the examples above,
+or in the data file read by the "read_data"_read_data.html command:
+
+k_n (energy/distance^2 units)
+k_na (energy/distance^2 units) :ul
+
+Effectively, k_n and k_na are the slopes of the red lines in the plot
+above for force versus surface separation, for \delta_n < 0 and 0 <
+\delta_n < r_c respectively.
+
+[Mixing, shift, table, tail correction, restart, rRESPA info]:
+
+This pair style does not support the "pair_modify"_pair_modify.html
+mix, shift, table, and tail options.
+
+This pair style does not write its information to "binary restart
+files"_restart.html.  Thus, you need to re-specify the pair_style and
+pair_coeff commands in an input script that reads a restart file.
+
+This pair style can only be used via the {pair} keyword of the
+"run_style respa"_run_style.html command.  It does not support the
+{inner}, {middle}, {outer} keywords.
+
+[Restrictions:]
+
+These pair styles are part of the BODY package.  They are only enabled
+if LAMMPS was built with that package.  See the "Making
+LAMMPS"_Section_start.html#start_3 section for more info.
+
+This pair style requires the "newton"_newton.html setting to be "on"
+for pair interactions.
+
+[Related commands:]
+
+"pair_coeff"_pair_coeff.html
+
+[Default:] none
+
+:link(pair-Wang)
+[(Wang)] J. Wang, H. S. Yu, P. A. Langston, F. Y. Fraige, Granular
+Matter, 13, 1 (2011).
+
diff --git a/doc/src/python.txt b/doc/src/python.txt
index 1ac2b48528c073a1b40ea4fd210dfb5dfb91a1ae..d670fcc77f8ef4377c829ae0fa486fa9ba8347a1 100644
--- a/doc/src/python.txt
+++ b/doc/src/python.txt
@@ -99,10 +99,9 @@ They can be substituted for directly in an input script.  Or they can
 be passed to various commands as arguments, so that the variable is
 evaluated during a simulation run.
 
-A broader overview of how Python can be used with LAMMPS is
-given in "Section 11"_Section_python.html.  There is an
-examples/python directory which illustrates use of the python
-command.
+A broader overview of how Python can be used with LAMMPS is given on
+the "Python"_Python.html doc page.  There is an examples/python
+directory which illustrates use of the python command.
 
 :line
 
@@ -331,9 +330,9 @@ to the screen and log file.  Note that since the LAMMPS print command
 itself takes a string in quotes as its argument, the Python string
 must be delimited with a different style of quotes.
 
-"Section 11.7"_Section_python.html#py_7 describes the syntax for how
-Python wraps the various functions included in the LAMMPS library
-interface.
+The "Pytnon library"_Python_library.html doc page describes the syntax
+for how Python wraps the various functions included in the LAMMPS
+library interface.
 
 A more interesting example is in the examples/python/in.python script
 which loads and runs the following function from examples/python/funcs.py:
@@ -484,15 +483,16 @@ building LAMMPS.  LAMMPS must also be built as a shared library and
 your Python function must be able to to load the Python module in
 python/lammps.py that wraps the LAMMPS library interface.  These are
 the same steps required to use Python by itself to wrap LAMMPS.
-Details on these steps are explained in "Section
-python"_Section_python.html.  Note that it is important that the
-stand-alone LAMMPS executable and the LAMMPS shared library be
-consistent (built from the same source code files) in order for this
-to work.  If the two have been built at different times using
-different source files, problems may occur.
+Details on these steps are explained on the "Python"_Python.html doc
+page.  Note that it is important that the stand-alone LAMMPS
+executable and the LAMMPS shared library be consistent (built from the
+same source code files) in order for this to work.  If the two have
+been built at different times using different source files, problems
+may occur.
 
 [Related commands:]
 
-"shell"_shell.html, "variable"_variable.html, "fix python/invoke"_fix_python_invoke.html
+"shell"_shell.html, "variable"_variable.html, "fix
+python/invoke"_fix_python_invoke.html
 
 [Default:] none
diff --git a/doc/src/read_dump.txt b/doc/src/read_dump.txt
index 23f6274582ee9d1ef579ce96ce9692a892866f29..21c6df5017a50b8bf35ef43198c659f60ae4fb51 100644
--- a/doc/src/read_dump.txt
+++ b/doc/src/read_dump.txt
@@ -282,11 +282,11 @@ conditions are applied to remap an atom back into the simulation box.
 
 NOTE: If you get a warning about inconsistent image flags after
 reading in a dump snapshot, it means one or more pairs of bonded atoms
-now have inconsistent image flags.  As discussed in "Section
-errors"_Section_errors.html this may or may not cause problems for
-subsequent simulations, One way this can happen is if you read image
-flag fields from the dump file but do not also use the dump file box
-parameters.
+now have inconsistent image flags.  As discussed on the "Errors
+common"_Errors_common.html doc page this may or may not cause problems
+for subsequent simulations.  One way this can happen is if you read
+image flag fields from the dump file but do not also use the dump file
+box parameters.
 
 LAMMPS knows how to compute unscaled and remapped coordinates for the
 snapshot column labels discussed above, e.g. {x}, {xs}, {xu}, {xsu}.
diff --git a/doc/src/read_restart.txt b/doc/src/read_restart.txt
index a5a2bfcc9743d7402eeb57bfa3dcda678f357829..6f6a82822929d26afd5d0a10ad9c28aa3bd252f7 100644
--- a/doc/src/read_restart.txt
+++ b/doc/src/read_restart.txt
@@ -76,8 +76,7 @@ different than if the run had continued.  These pair styles include
 
 If a restarted run is immediately different than the run which
 produced the restart file, it could be a LAMMPS bug, so consider
-"reporting it"_Section_errors.html#err_2 if you think the behavior is
-wrong.
+"reporting it"_Errors_bugs.html if you think the behavior is a bug.
 
 Because restart files are binary, they may not be portable to other
 machines.  In this case, you can use the "-restart command-line
diff --git a/doc/src/run.txt b/doc/src/run.txt
index 311560d66b57585c0dfb9e0fae8c64d8f39ea236..913d81bb4d05c46274d5127bed7e6fb483732507 100644
--- a/doc/src/run.txt
+++ b/doc/src/run.txt
@@ -126,9 +126,8 @@ and interleaving commands in your input script.  For example, a
 be redefined, e.g. to reset a thermostat temperature.  Or this could
 be useful for invoking a command you have added to LAMMPS that wraps
 some other code (e.g. as a library) to perform a computation
-periodically during a long LAMMPS run.  See "this
-section"_Section_modify.html of the documentation for info about how
-to add new commands to LAMMPS.  See "this
+periodically during a long LAMMPS run.  See the "Modify"_Modify.html
+doc page for info about how to add new commands to LAMMPS.  See "this
 section"_Section_howto.html#howto_10 of the documentation for ideas
 about how to couple LAMMPS to other codes.
 
diff --git a/doc/src/thermo_style.txt b/doc/src/thermo_style.txt
index 6102169ee363ca2bdb9dc41d1663f9c1dcb442aa..18c5ad5ba1ce9ecedf74156c8f78a073101e8374 100644
--- a/doc/src/thermo_style.txt
+++ b/doc/src/thermo_style.txt
@@ -108,12 +108,11 @@ Style {custom} is the most general setting and allows you to specify
 which of the keywords listed above you want printed on each
 thermodynamic timestep.  Note that the keywords c_ID, f_ID, v_name are
 references to "computes"_compute.html, "fixes"_fix.html, and
-equal-style "variables"_variable.html that have been defined
-elsewhere in the input script or can even be new styles which users
-have added to LAMMPS (see the "Section 10"_Section_modify.html
-section of the documentation).  Thus the {custom} style provides a
-flexible means of outputting essentially any desired quantity as a
-simulation proceeds.
+equal-style "variables"_variable.html that have been defined elsewhere
+in the input script or can even be new styles which users have added
+to LAMMPS.  See the "Modify"_Modify.html doc page for details on the
+latter.  Thus the {custom} style provides a flexible means of
+outputting essentially any desired quantity as a simulation proceeds.
 
 All styles except {custom} have {vol} appended to their list of
 outputs if the simulation box volume changes during the simulation.
diff --git a/doc/src/tutorial_github.txt b/doc/src/tutorial_github.txt
index 3e10b821aecf3b8bce1f1f9e54198720bd521ce5..fc261bdb958e18bdb19511f4a0ec8ecad8ad8c3e 100644
--- a/doc/src/tutorial_github.txt
+++ b/doc/src/tutorial_github.txt
@@ -25,8 +25,8 @@ or improvements to LAMMPS, as it significantly reduces the amount of
 work required by the LAMMPS developers. Consequently, creating a pull
 request will increase your chances to have your contribution included
 and will reduce the time until the integration is complete. For more
-information on the requirements to have your code included into LAMMPS
-please see "Section 10.15"_Section_modify.html#mod_15
+information on the requirements to have your code included in LAMMPS,
+see the "Modify contribute"_Modify_contribute.html doc page.
 
 :line
 
diff --git a/examples/body/data.cubes b/examples/body/data.cubes
new file mode 100644
index 0000000000000000000000000000000000000000..c1323ca3503bb10745df9a9bc176ce531850a4eb
--- /dev/null
+++ b/examples/body/data.cubes
@@ -0,0 +1,76 @@
+LAMMPS data file for polygons: cubes, moment of inertia I = m edge^2/ 6
+2 atoms
+2 bodies
+1 atom types
+0 6 xlo xhi
+0 6 ylo yhi
+0 6 zlo zhi
+
+Atoms
+
+1 1 1 1 1.5 1.5 1.5
+2 1 1 1 4.0 4.0 4.0
+
+Bodies
+
+1 3 79
+8 12 6
+0.667 0.667 0.667 0 0 0
+1 1 1
+1 -1 1
+-1 -1 1
+-1 1 1
+1 1 -1
+1 -1 -1
+-1 -1 -1
+-1 1 -1
+0 1
+1 2
+2 3
+3 0
+4 5
+5 6
+6 7
+7 4
+0 4
+1 5
+2 6
+3 7
+0 1 2 3
+4 5 6 7
+0 1 5 4
+1 2 6 5
+2 3 7 6
+3 0 4 7
+0.5
+2 3 79
+8 12 6
+0.667 0.667 0.667 0 0 0
+1 1 1
+1 -1 1
+-1 -1 1
+-1 1 1
+1 1 -1
+1 -1 -1
+-1 -1 -1
+-1 1 -1
+0 1
+1 2
+2 3
+3 0
+4 5
+5 6
+6 7
+7 4
+0 4
+1 5
+2 6
+3 7
+0 1 2 3
+4 5 6 7
+0 1 5 4
+1 2 6 5
+2 3 7 6
+3 0 4 7
+0.5
+
diff --git a/examples/body/data.squares b/examples/body/data.squares
new file mode 100755
index 0000000000000000000000000000000000000000..6b198fd422dc0e5d8f736d70bcd9906ca133898e
--- /dev/null
+++ b/examples/body/data.squares
@@ -0,0 +1,32 @@
+LAMMPS data file for polygons: squares of edge length L: Izz = 1/6mL^2
+2 atoms
+2 bodies
+1 atom types
+0 12 xlo xhi
+0 12 ylo yhi
+-0.5 0.5 zlo zhi
+
+Atoms
+
+1 1 1 1 4 5 0
+2 1 1 1 9 6 0
+
+Bodies
+
+1 1 19
+4
+1 1 2.67 0 0 0
+-2 -2 0
+-2 2 0
+2 2 0
+2 -2 0
+0.5
+2 1 19
+4
+1 1 2.67 0 0 0
+-2 -2 0
+-2 2 0
+2 2 0
+2 -2 0
+0.5
+
diff --git a/examples/body/in.body b/examples/body/in.body
index 5879ed5e45bc8810e82df81fdac0928306ae9e23..815b8531545a4348fb54dd1553abcfb642f44bf5 100644
--- a/examples/body/in.body
+++ b/examples/body/in.body
@@ -8,7 +8,7 @@ read_data       data.body
 
 velocity	all create 1.44 87287 loop geom
 
-pair_style	body 5.0
+pair_style	body/nparticle 5.0
 pair_coeff	* * 1.0 1.0
 
 neighbor	0.5 bin
diff --git a/examples/body/in.cubes b/examples/body/in.cubes
new file mode 100644
index 0000000000000000000000000000000000000000..a22599fe9607873aab7bc2214f59b8268415814d
--- /dev/null
+++ b/examples/body/in.cubes
@@ -0,0 +1,53 @@
+# 3d rounded cubes
+
+variable    r     index 3
+variable    steps index 10000
+
+units       lj
+dimension   3
+
+atom_style  body rounded/polyhedron 1 10
+
+read_data   data.cubes
+
+replicate   $r $r $r
+
+velocity    all create 1.2 187287 dist gaussian mom yes rot yes
+
+variable cut_inner  equal 0.5
+variable k_n        equal 100
+variable k_na       equal 1
+variable c_n        equal 20
+variable c_t        equal 5
+variable mu         equal 0
+variable A_ua       equal 1
+
+pair_style body/rounded/polyhedron ${c_n} ${c_t} ${mu} ${A_ua} ${cut_inner}
+pair_coeff * * ${k_n} ${k_na}
+
+comm_modify vel yes
+
+neighbor     0.5 bin
+neigh_modify every 1 delay 0 check yes
+
+timestep     0.001
+
+#fix          1 all nve/body
+fix          1 all nvt/body temp 1.2 1.2 0.1
+#fix          1 all npt/body temp 1.2 1.2 0.1 iso 0.002 0.02 1.0
+
+compute      p2 all pressure 1_temp
+
+#compute      1 all body/local id 1 2 3
+#dump         1 all local 1000 dump.* index c_1[1] c_1[2] c_1[3] c_1[4]
+
+#dump         2 all image 1000 image.*.jpg type type &
+#             zoom 1.5 adiam 1.5 body type 0 0 view 60 15
+#dump_modify  2 pad 6
+
+thermo_style custom step ke pe etotal c_p2 c_1_temp
+
+thermo       1000
+
+run          ${steps}
+
diff --git a/examples/body/in.pour3d b/examples/body/in.pour3d
new file mode 100644
index 0000000000000000000000000000000000000000..bcba950e593606065837cdbaeb85a4376fd0c4c4
--- /dev/null
+++ b/examples/body/in.pour3d
@@ -0,0 +1,57 @@
+# pouring 3d rounded polyhedron bodies
+
+variable    steps index 6000
+
+units       lj
+boundary    p p fm
+comm_modify vel yes
+
+atom_style  body rounded/polyhedron 1 8
+atom_modify map array
+
+region		reg block 0 50 0 50 0 50 units box
+create_box	4 reg
+
+variable cut_inner  equal 0.5
+variable k_n        equal 100
+variable k_na       equal 5
+variable c_n        equal 20
+variable c_t        equal 5
+variable mu         equal 0
+variable A_ua       equal 1
+
+pair_style body/rounded/polyhedron ${c_n} ${c_t} ${mu} ${A_ua} ${cut_inner}
+pair_coeff * * ${k_n} ${k_na}
+
+neighbor     0.5 bin
+neigh_modify every 1 delay 0 check yes
+
+timestep     0.001
+
+fix          1 all nve/body
+fix          2 all gravity 1.0 spherical 0.0 -180.0
+
+molecule     object molecule.cube molecule.tetra toff 1 &
+             molecule.rod3d toff 2 molecule.point3d toff 3
+
+region       slab block 5 45 5 45 25 35 units box
+fix          ins all pour 500 0 4767548 vol 0.4 10 region slab mol object &
+             molfrac 0.25 0.25 0.25 0.25
+
+fix          4 all wall/body/polyhedron 2000 50 50 zplane 0.0 NULL
+
+#compute      1 all body/local type 1 2 3
+#dump         1 all local 1000 dump.polyhedron index c_1[1] c_1[2] c_1[3] c_1[4]
+#dump         10 all custom 1000 tmp.dump id type x y z radius
+
+thermo_style custom step atoms ke pe etotal press
+
+thermo       1000
+
+#dump	     2 all image 500 image.*.jpg type type &
+#	     zoom 1.5 adiam 1.5 body type 0 0 view 75 15
+#dump_modify  2 pad 6
+
+run	     ${steps}
+
+
diff --git a/examples/body/in.squares b/examples/body/in.squares
new file mode 100755
index 0000000000000000000000000000000000000000..3b05b5cead88cd6265b17ce2772873b97c475383
--- /dev/null
+++ b/examples/body/in.squares
@@ -0,0 +1,55 @@
+# 2d rounded polygon bodies
+
+variable    r     index 4
+variable    steps index 100000
+variable    T     index 0.5
+variable    P     index 0.1
+variable    seed  index 980411
+
+units       lj
+dimension   2
+
+atom_style  body rounded/polygon 1 6
+atom_modify map array
+read_data   data.squares
+
+replicate   $r $r 1
+
+velocity    all create $T ${seed} dist gaussian mom yes rot yes
+
+variable cut_inner  equal 0.5
+variable k_n        equal 100
+variable k_na       equal 2
+variable c_n        equal 1
+variable c_t        equal 1
+variable mu         equal 0.1
+variable delta_ua   equal 0.5
+
+pair_style body/rounded/polygon ${c_n} ${c_t} ${mu} ${delta_ua} ${cut_inner}
+pair_coeff * * ${k_n} ${k_na}
+
+comm_modify vel yes
+
+neighbor     0.5 bin
+neigh_modify every 1 delay 0 check yes
+
+timestep     0.001
+
+#fix         1 all nve/body
+#fix         1 all nvt/body temp $T $T 1.0
+fix          1 all npt/body temp $T $T 1.0 x 0.001 $P 1.0 &
+             y 0.001 $P 1.0 couple xy fixedpoint 0 0 0
+
+fix          2 all enforce2d
+
+#compute      1 all body/local id 1 2 3
+#dump         1 all local 100000 dump.polygon.* index c_1[1] c_1[2] c_1[3] c_1[4]
+
+thermo_style custom step ke pe etotal press
+thermo       1000
+
+#dump	     2 all image 10000 image.*.jpg type type zoom 2.0 &
+#             adiam 1.5 body type 0 0
+#dump_modify  2 pad 6
+
+run          ${steps}
diff --git a/examples/body/in.wall2d b/examples/body/in.wall2d
new file mode 100755
index 0000000000000000000000000000000000000000..04e7f31cb6810151570f164353f683ac6b675afa
--- /dev/null
+++ b/examples/body/in.wall2d
@@ -0,0 +1,57 @@
+# 2d rounded polygon bodies
+
+variable    r     index 4
+variable    steps index 100000
+variable    T     index 0.5
+variable    P     index 0.1
+variable    seed  index 980411
+
+units       lj
+dimension   2
+
+atom_style  body rounded/polygon 1 6
+atom_modify map array
+read_data   data.squares
+
+replicate   $r $r 1
+
+velocity    all create $T ${seed} dist gaussian mom yes rot yes
+
+change_box  all boundary p f p
+
+variable cut_inner  equal 0.5
+variable k_n        equal 100
+variable k_na       equal 2
+variable c_n        equal 0.1
+variable c_t        equal 0.1
+variable mu         equal 0.1
+variable delta_ua   equal 0.5
+
+pair_style body/rounded/polygon ${c_n} ${c_t} ${mu} ${delta_ua} ${cut_inner}
+pair_coeff * * ${k_n} ${k_na}
+
+comm_modify vel yes
+
+neighbor     0.5 bin
+neigh_modify every 1 delay 0 check yes
+
+timestep     0.001
+
+#fix         1 all nve/body
+#fix         1 all nvt/body temp $T $T 1.0
+fix          1 all npt/body temp $T $T 1.0 x 0.001 $P 1.0 fixedpoint 0 0 0
+
+fix          2 all enforce2d
+fix          3 all wall/body/polygon 2000 50 50 yplane 0.0 48.0
+
+#compute      1 all body/local id 1 2 3
+#dump         1 all local 100000 dump.polygon.* index c_1[1] c_1[2] c_1[3] c_1[4]
+
+thermo_style custom step ke pe etotal press
+thermo       1000
+
+#dump	     2 all image 10000 image.*.jpg type type zoom 2.0 &
+#             adiam 1.5 body type 0 0
+#dump_modify  2 pad 6
+
+run          ${steps}
diff --git a/examples/body/log.9Jul18.body.cubes.g++.1 b/examples/body/log.9Jul18.body.cubes.g++.1
new file mode 100644
index 0000000000000000000000000000000000000000..c9a799c0b51192a5420fb75fb8aeaa32a0b1a3df
--- /dev/null
+++ b/examples/body/log.9Jul18.body.cubes.g++.1
@@ -0,0 +1,125 @@
+LAMMPS (29 Jun 2018)
+# 3d rounded cubes
+
+variable    r     index 3
+variable    steps index 10000
+
+units       lj
+dimension   3
+
+atom_style  body rounded/polyhedron 1 10
+
+read_data   data.cubes
+  orthogonal box = (0 0 0) to (6 6 6)
+  1 by 1 by 1 MPI processor grid
+  reading atoms ...
+  2 atoms
+  2 bodies
+
+replicate   $r $r $r
+replicate   3 $r $r
+replicate   3 3 $r
+replicate   3 3 3
+  orthogonal box = (0 0 0) to (18 18 18)
+  1 by 1 by 1 MPI processor grid
+  54 atoms
+  Time spent = 0.000217915 secs
+
+velocity    all create 1.2 187287 dist gaussian mom yes rot yes
+
+variable cut_inner  equal 0.5
+variable k_n        equal 100
+variable k_na       equal 1
+variable c_n        equal 20
+variable c_t        equal 5
+variable mu         equal 0
+variable A_ua       equal 1
+
+pair_style body/rounded/polyhedron ${c_n} ${c_t} ${mu} ${A_ua} ${cut_inner}
+pair_style body/rounded/polyhedron 20 ${c_t} ${mu} ${A_ua} ${cut_inner}
+pair_style body/rounded/polyhedron 20 5 ${mu} ${A_ua} ${cut_inner}
+pair_style body/rounded/polyhedron 20 5 0 ${A_ua} ${cut_inner}
+pair_style body/rounded/polyhedron 20 5 0 1 ${cut_inner}
+pair_style body/rounded/polyhedron 20 5 0 1 0.5
+pair_coeff * * ${k_n} ${k_na}
+pair_coeff * * 100 ${k_na}
+pair_coeff * * 100 1
+
+comm_modify vel yes
+
+neighbor     0.5 bin
+neigh_modify every 1 delay 0 check yes
+
+timestep     0.001
+
+#fix          1 all nve/body
+fix          1 all nvt/body temp 1.2 1.2 0.1
+#fix          1 all npt/body temp 1.2 1.2 0.1 iso 0.002 0.02 1.0
+
+compute      p2 all pressure 1_temp
+
+#compute      1 all body/local id 1 2 3
+#dump         1 all local 1000 dump.* index c_1[1] c_1[2] c_1[3] c_1[4]
+
+#dump         2 all image 1000 image.*.jpg type type #             zoom 1.5 adiam 1.5 body type 0 0 view 60 15
+#dump_modify  2 pad 6
+
+thermo_style custom step ke pe etotal c_p2 c_1_temp
+
+thermo       1000
+
+run          ${steps}
+run          10000
+Neighbor list info ...
+  update every 1 steps, delay 0 steps, check yes
+  max neighbors/atom: 2000, page size: 100000
+  master list distance cutoff = 3.9641
+  ghost atom cutoff = 3.9641
+  binsize = 1.98205, bins = 10 10 10
+  1 neighbor lists, perpetual/occasional/extra = 1 0 0
+  (1) pair body/rounded/polyhedron, perpetual
+      attributes: half, newton on
+      pair build: half/bin/atomonly/newton
+      stencil: half/bin/3d/newton
+      bin: standard
+Per MPI rank memory allocation (min/avg/max) = 4.952 | 4.952 | 4.952 Mbytes
+Step KinEng PotEng TotEng c_p2 c_1_temp 
+       0    1.7666667            0    1.7666667   0.01090535   0.59439252 
+    1000    3.1462962   0.17392649    3.3202227   0.02361912    1.1654694 
+    2000    2.9311648   0.13836102    3.0695258  0.021748224    1.1950624 
+    3000     3.090491   0.16511199     3.255603  0.018691142      1.23672 
+    4000    2.7401565   0.17792155    2.9180781  0.015093853    1.1180839 
+    5000    3.0880849   0.17587085    3.2639557  0.030563042    1.2831154 
+    6000    3.2180776   0.19732251    3.4154001  0.028338151     1.258839 
+    7000    2.9514882   0.25088882     3.202377  0.025296925    1.1746326 
+    8000    3.0101226   0.28825968    3.2983823  0.027273454    1.2138056 
+    9000    3.0164253    0.1901733    3.2065986  0.033228915    1.3095914 
+   10000    2.3780401   0.34082434    2.7188644  0.031838531    1.0208679 
+Loop time of 38.5686 on 1 procs for 10000 steps with 54 atoms
+
+Performance: 22401.653 tau/day, 259.278 timesteps/s
+100.0% CPU use with 1 MPI tasks x no OpenMP threads
+
+MPI task timing breakdown:
+Section |  min time  |  avg time  |  max time  |%varavg| %total
+---------------------------------------------------------------
+Pair    | 38.426     | 38.426     | 38.426     |   0.0 | 99.63
+Neigh   | 0.0043154  | 0.0043154  | 0.0043154  |   0.0 |  0.01
+Comm    | 0.047616   | 0.047616   | 0.047616   |   0.0 |  0.12
+Output  | 0.00017595 | 0.00017595 | 0.00017595 |   0.0 |  0.00
+Modify  | 0.082948   | 0.082948   | 0.082948   |   0.0 |  0.22
+Other   |            | 0.007761   |            |       |  0.02
+
+Nlocal:    54 ave 54 max 54 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+Nghost:    96 ave 96 max 96 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+Neighs:    100 ave 100 max 100 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+
+Total # of neighbors = 100
+Ave neighs/atom = 1.85185
+Neighbor list builds = 268
+Dangerous builds = 0
+
+Total wall time: 0:00:38
diff --git a/examples/body/log.9Jul18.body.cubes.g++.4 b/examples/body/log.9Jul18.body.cubes.g++.4
new file mode 100644
index 0000000000000000000000000000000000000000..e2407e972532938d39ba0e62964d74dc9c69740f
--- /dev/null
+++ b/examples/body/log.9Jul18.body.cubes.g++.4
@@ -0,0 +1,125 @@
+LAMMPS (29 Jun 2018)
+# 3d rounded cubes
+
+variable    r     index 3
+variable    steps index 10000
+
+units       lj
+dimension   3
+
+atom_style  body rounded/polyhedron 1 10
+
+read_data   data.cubes
+  orthogonal box = (0 0 0) to (6 6 6)
+  1 by 2 by 2 MPI processor grid
+  reading atoms ...
+  2 atoms
+  2 bodies
+
+replicate   $r $r $r
+replicate   3 $r $r
+replicate   3 3 $r
+replicate   3 3 3
+  orthogonal box = (0 0 0) to (18 18 18)
+  1 by 2 by 2 MPI processor grid
+  54 atoms
+  Time spent = 0.00103807 secs
+
+velocity    all create 1.2 187287 dist gaussian mom yes rot yes
+
+variable cut_inner  equal 0.5
+variable k_n        equal 100
+variable k_na       equal 1
+variable c_n        equal 20
+variable c_t        equal 5
+variable mu         equal 0
+variable A_ua       equal 1
+
+pair_style body/rounded/polyhedron ${c_n} ${c_t} ${mu} ${A_ua} ${cut_inner}
+pair_style body/rounded/polyhedron 20 ${c_t} ${mu} ${A_ua} ${cut_inner}
+pair_style body/rounded/polyhedron 20 5 ${mu} ${A_ua} ${cut_inner}
+pair_style body/rounded/polyhedron 20 5 0 ${A_ua} ${cut_inner}
+pair_style body/rounded/polyhedron 20 5 0 1 ${cut_inner}
+pair_style body/rounded/polyhedron 20 5 0 1 0.5
+pair_coeff * * ${k_n} ${k_na}
+pair_coeff * * 100 ${k_na}
+pair_coeff * * 100 1
+
+comm_modify vel yes
+
+neighbor     0.5 bin
+neigh_modify every 1 delay 0 check yes
+
+timestep     0.001
+
+#fix          1 all nve/body
+fix          1 all nvt/body temp 1.2 1.2 0.1
+#fix          1 all npt/body temp 1.2 1.2 0.1 iso 0.002 0.02 1.0
+
+compute      p2 all pressure 1_temp
+
+#compute      1 all body/local id 1 2 3
+#dump         1 all local 1000 dump.* index c_1[1] c_1[2] c_1[3] c_1[4]
+
+#dump         2 all image 1000 image.*.jpg type type #             zoom 1.5 adiam 1.5 body type 0 0 view 60 15
+#dump_modify  2 pad 6
+
+thermo_style custom step ke pe etotal c_p2 c_1_temp
+
+thermo       1000
+
+run          ${steps}
+run          10000
+Neighbor list info ...
+  update every 1 steps, delay 0 steps, check yes
+  max neighbors/atom: 2000, page size: 100000
+  master list distance cutoff = 3.9641
+  ghost atom cutoff = 3.9641
+  binsize = 1.98205, bins = 10 10 10
+  1 neighbor lists, perpetual/occasional/extra = 1 0 0
+  (1) pair body/rounded/polyhedron, perpetual
+      attributes: half, newton on
+      pair build: half/bin/atomonly/newton
+      stencil: half/bin/3d/newton
+      bin: standard
+Per MPI rank memory allocation (min/avg/max) = 4.879 | 5.068 | 5.256 Mbytes
+Step KinEng PotEng TotEng c_p2 c_1_temp 
+       0    1.7666667            0    1.7666667   0.01090535   0.59439252 
+    1000    3.1462962   0.17392649    3.3202227   0.02361912    1.1654694 
+    2000    2.9311648   0.13836102    3.0695258  0.021748224    1.1950624 
+    3000     3.090491   0.16511199     3.255603  0.018691142      1.23672 
+    4000    2.7401565   0.17792155    2.9180781  0.015093853    1.1180839 
+    5000    3.0880849   0.17587085    3.2639557  0.030563042    1.2831154 
+    6000    3.2180776   0.19732251    3.4154001  0.028338151     1.258839 
+    7000    2.9514882   0.25088882     3.202377  0.025296925    1.1746326 
+    8000    3.0101226   0.28825968    3.2983823  0.027273454    1.2138056 
+    9000    3.0164253    0.1901733    3.2065986  0.033228915    1.3095914 
+   10000    2.3780401   0.34082434    2.7188644  0.031838531    1.0208679 
+Loop time of 20.5306 on 4 procs for 10000 steps with 54 atoms
+
+Performance: 42083.509 tau/day, 487.078 timesteps/s
+100.0% CPU use with 4 MPI tasks x no OpenMP threads
+
+MPI task timing breakdown:
+Section |  min time  |  avg time  |  max time  |%varavg| %total
+---------------------------------------------------------------
+Pair    | 7.5288     | 10.878     | 19.952     | 159.0 | 52.98
+Neigh   | 0.0014424  | 0.0016552  | 0.0021195  |   0.7 |  0.01
+Comm    | 0.50623    | 9.5805     | 12.93      | 169.4 | 46.66
+Output  | 0.00011921 | 0.00014341 | 0.00021386 |   0.0 |  0.00
+Modify  | 0.044663   | 0.047684   | 0.05382    |   1.6 |  0.23
+Other   |            | 0.023      |            |       |  0.11
+
+Nlocal:    13.5 ave 17 max 9 min
+Histogram: 1 0 0 1 0 0 0 0 1 1
+Nghost:    63.5 ave 68 max 58 min
+Histogram: 1 0 0 1 0 0 0 0 0 2
+Neighs:    25 ave 38 max 6 min
+Histogram: 1 0 0 0 0 1 0 0 1 1
+
+Total # of neighbors = 100
+Ave neighs/atom = 1.85185
+Neighbor list builds = 268
+Dangerous builds = 0
+
+Total wall time: 0:00:20
diff --git a/examples/body/log.9Jul18.body.pour3d.g++.1 b/examples/body/log.9Jul18.body.pour3d.g++.1
new file mode 100644
index 0000000000000000000000000000000000000000..213dd2e18fa9959a87ca922760e53508cace973d
--- /dev/null
+++ b/examples/body/log.9Jul18.body.pour3d.g++.1
@@ -0,0 +1,138 @@
+LAMMPS (29 Jun 2018)
+# pouring 3d rounded polyhedron bodies
+
+variable    steps index 6000
+
+units       lj
+boundary    p p fm
+comm_modify vel yes
+
+atom_style  body rounded/polyhedron 1 8
+atom_modify map array
+
+region		reg block 0 50 0 50 0 50 units box
+create_box	4 reg
+Created orthogonal box = (0 0 0) to (50 50 50)
+  1 by 1 by 1 MPI processor grid
+
+variable cut_inner  equal 0.5
+variable k_n        equal 100
+variable k_na       equal 5
+variable c_n        equal 20
+variable c_t        equal 5
+variable mu         equal 0
+variable A_ua       equal 1
+
+pair_style body/rounded/polyhedron ${c_n} ${c_t} ${mu} ${A_ua} ${cut_inner}
+pair_style body/rounded/polyhedron 20 ${c_t} ${mu} ${A_ua} ${cut_inner}
+pair_style body/rounded/polyhedron 20 5 ${mu} ${A_ua} ${cut_inner}
+pair_style body/rounded/polyhedron 20 5 0 ${A_ua} ${cut_inner}
+pair_style body/rounded/polyhedron 20 5 0 1 ${cut_inner}
+pair_style body/rounded/polyhedron 20 5 0 1 0.5
+pair_coeff * * ${k_n} ${k_na}
+pair_coeff * * 100 ${k_na}
+pair_coeff * * 100 5
+
+neighbor     0.5 bin
+neigh_modify every 1 delay 0 check yes
+
+timestep     0.001
+
+fix          1 all nve/body
+fix          2 all gravity 1.0 spherical 0.0 -180.0
+
+molecule     object molecule.cube molecule.tetra toff 1              molecule.rod3d toff 2 molecule.point3d toff 3
+Read molecule object:
+  1 atoms with max type 1
+  0 bonds with max type 0
+  0 angles with max type 0
+  0 dihedrals with max type 0
+  0 impropers with max type 0
+Read molecule object:
+  1 atoms with max type 2
+  0 bonds with max type 0
+  0 angles with max type 0
+  0 dihedrals with max type 0
+  0 impropers with max type 0
+Read molecule object:
+  1 atoms with max type 3
+  0 bonds with max type 0
+  0 angles with max type 0
+  0 dihedrals with max type 0
+  0 impropers with max type 0
+Read molecule object:
+  1 atoms with max type 4
+  0 bonds with max type 0
+  0 angles with max type 0
+  0 dihedrals with max type 0
+  0 impropers with max type 0
+
+region       slab block 5 45 5 45 25 35 units box
+fix          ins all pour 500 0 4767548 vol 0.4 10 region slab mol object              molfrac 0.25 0.25 0.25 0.25
+Particle insertion: 134 every 4472 steps, 500 by step 13417
+
+fix          4 all wall/body/polyhedron 2000 50 50 zplane 0.0 NULL
+
+#compute      1 all body/local type 1 2 3
+#dump         1 all local 1000 dump.polyhedron index c_1[1] c_1[2] c_1[3] c_1[4]
+#dump         10 all custom 1000 tmp.dump id type x y z radius
+
+thermo_style custom step atoms ke pe etotal press
+
+thermo       1000
+
+#dump	     2 all image 500 image.*.jpg type type #	     zoom 1.5 adiam 1.5 body type 0 0 view 75 15
+#dump_modify  2 pad 6
+
+run	     ${steps}
+run	     6000
+Neighbor list info ...
+  update every 1 steps, delay 0 steps, check yes
+  max neighbors/atom: 2000, page size: 100000
+  master list distance cutoff = 5
+  ghost atom cutoff = 5
+  binsize = 2.5, bins = 20 20 20
+  1 neighbor lists, perpetual/occasional/extra = 1 0 0
+  (1) pair body/rounded/polyhedron, perpetual
+      attributes: half, newton on
+      pair build: half/bin/atomonly/newton
+      stencil: half/bin/3d/newton
+      bin: standard
+Per MPI rank memory allocation (min/avg/max) = 0.5065 | 0.5065 | 0.5065 Mbytes
+Step Atoms KinEng PotEng TotEng Press 
+       0        0           -0            0            0            0 
+    1000      134           -0 0.00083010524 0.00083010524 -2.1515152e-06 
+    2000      134           -0 -0.00069962476 -0.00069962476 -1.4170663e-08 
+    3000      134           -0 -0.00069962687 -0.00069962687 -4.1478181e-11 
+    4000      134           -0 -0.00069962687 -0.00069962687 -1.2141026e-13 
+    5000      268           -0  0.014969705  0.014969705 3.0797164e-05 
+    6000      268           -0  0.042467887  0.042467887 0.00056148005 
+Loop time of 0.634737 on 1 procs for 6000 steps with 268 atoms
+
+Performance: 816716.196 tau/day, 9452.734 timesteps/s
+100.0% CPU use with 1 MPI tasks x no OpenMP threads
+
+MPI task timing breakdown:
+Section |  min time  |  avg time  |  max time  |%varavg| %total
+---------------------------------------------------------------
+Pair    | 0.41391    | 0.41391    | 0.41391    |   0.0 | 65.21
+Neigh   | 0.010547   | 0.010547   | 0.010547   |   0.0 |  1.66
+Comm    | 0.0030921  | 0.0030921  | 0.0030921  |   0.0 |  0.49
+Output  | 0.00011492 | 0.00011492 | 0.00011492 |   0.0 |  0.02
+Modify  | 0.19736    | 0.19736    | 0.19736    |   0.0 | 31.09
+Other   |            | 0.009719   |            |       |  1.53
+
+Nlocal:    268 ave 268 max 268 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+Nghost:    3 ave 3 max 3 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+Neighs:    68 ave 68 max 68 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+
+Total # of neighbors = 68
+Ave neighs/atom = 0.253731
+Neighbor list builds = 168
+Dangerous builds = 0
+
+
+Total wall time: 0:00:00
diff --git a/examples/body/log.9Jul18.body.squares.g++.1 b/examples/body/log.9Jul18.body.squares.g++.1
new file mode 100644
index 0000000000000000000000000000000000000000..7b539797bd6d399ade37eeb28d580447c8721d9e
--- /dev/null
+++ b/examples/body/log.9Jul18.body.squares.g++.1
@@ -0,0 +1,221 @@
+LAMMPS (29 Jun 2018)
+# 2d rounded polygon bodies
+
+variable    r     index 4
+variable    steps index 100000
+variable    T     index 0.5
+variable    P     index 0.1
+variable    seed  index 980411
+
+units       lj
+dimension   2
+
+atom_style  body rounded/polygon 1 6
+atom_modify map array
+read_data   data.squares
+  orthogonal box = (0 0 -0.5) to (12 12 0.5)
+  1 by 1 by 1 MPI processor grid
+  reading atoms ...
+  2 atoms
+  2 bodies
+
+replicate   $r $r 1
+replicate   4 $r 1
+replicate   4 4 1
+  orthogonal box = (0 0 -0.5) to (48 48 0.5)
+  1 by 1 by 1 MPI processor grid
+  32 atoms
+  Time spent = 0.00020504 secs
+
+velocity    all create $T ${seed} dist gaussian mom yes rot yes
+velocity    all create 0.5 ${seed} dist gaussian mom yes rot yes
+velocity    all create 0.5 980411 dist gaussian mom yes rot yes
+
+variable cut_inner  equal 0.5
+variable k_n        equal 100
+variable k_na       equal 2
+variable c_n        equal 1
+variable c_t        equal 1
+variable mu         equal 0.1
+variable delta_ua   equal 0.5
+
+pair_style body/rounded/polygon ${c_n} ${c_t} ${mu} ${delta_ua} ${cut_inner}
+pair_style body/rounded/polygon 1 ${c_t} ${mu} ${delta_ua} ${cut_inner}
+pair_style body/rounded/polygon 1 1 ${mu} ${delta_ua} ${cut_inner}
+pair_style body/rounded/polygon 1 1 0.1 ${delta_ua} ${cut_inner}
+pair_style body/rounded/polygon 1 1 0.1 0.5 ${cut_inner}
+pair_style body/rounded/polygon 1 1 0.1 0.5 0.5
+pair_coeff * * ${k_n} ${k_na}
+pair_coeff * * 100 ${k_na}
+pair_coeff * * 100 2
+
+comm_modify vel yes
+
+neighbor     0.5 bin
+neigh_modify every 1 delay 0 check yes
+
+timestep     0.001
+
+#fix         1 all nve/body
+#fix         1 all nvt/body temp $T $T 1.0
+fix          1 all npt/body temp $T $T 1.0 x 0.001 $P 1.0              y 0.001 $P 1.0 couple xy fixedpoint 0 0 0
+fix          1 all npt/body temp 0.5 $T 1.0 x 0.001 $P 1.0              y 0.001 $P 1.0 couple xy fixedpoint 0 0 0
+fix          1 all npt/body temp 0.5 0.5 1.0 x 0.001 $P 1.0              y 0.001 $P 1.0 couple xy fixedpoint 0 0 0
+fix          1 all npt/body temp 0.5 0.5 1.0 x 0.001 0.1 1.0              y 0.001 $P 1.0 couple xy fixedpoint 0 0 0
+fix          1 all npt/body temp 0.5 0.5 1.0 x 0.001 0.1 1.0              y 0.001 0.1 1.0 couple xy fixedpoint 0 0 0
+
+fix          2 all enforce2d
+
+#compute      1 all body/local id 1 2 3
+#dump         1 all local 100000 dump.polygon.* index c_1[1] c_1[2] c_1[3] c_1[4]
+
+thermo_style custom step ke pe etotal press
+thermo       1000
+
+#dump	     2 all image 10000 image.*.jpg type type zoom 2.0 #             adiam 1.5 body type 0 0
+#dump_modify  2 pad 6
+
+run          ${steps}
+run          100000
+Neighbor list info ...
+  update every 1 steps, delay 0 steps, check yes
+  max neighbors/atom: 2000, page size: 100000
+  master list distance cutoff = 6.15685
+  ghost atom cutoff = 6.15685
+  binsize = 3.07843, bins = 16 16 1
+  1 neighbor lists, perpetual/occasional/extra = 1 0 0
+  (1) pair body/rounded/polygon, perpetual
+      attributes: half, newton on
+      pair build: half/bin/atomonly/newton
+      stencil: half/bin/2d/newton
+      bin: standard
+Per MPI rank memory allocation (min/avg/max) = 4.781 | 4.781 | 4.781 Mbytes
+Step KinEng PotEng TotEng Press 
+       0     0.484375         0.25     0.734375 0.0067274306 
+    1000   0.39423376 0.0017918048   0.39602557 0.0021941612 
+    2000   0.42284177   0.01346585   0.43630762 0.0029377883 
+    3000   0.58154405  0.011321689   0.59286574  0.003667871 
+    4000   0.73518304  0.034603175   0.76978621 0.0018689207 
+    5000   0.84367476  0.025292163   0.86896692 0.0089161373 
+    6000   0.70803236 0.0085631016   0.71659546 0.0045552895 
+    7000   0.56206452   0.10453031   0.66659483  0.010255161 
+    8000   0.64538994  0.088817673   0.73420761 0.0037633655 
+    9000   0.90540819  0.063696004   0.96910419 0.0077673359 
+   10000   0.68632042  0.093265016   0.77958544 0.0057864838 
+   11000   0.59118074  0.025654748   0.61683549  0.012518759 
+   12000   0.67522767  0.038176401   0.71340407   0.01741153 
+   13000    0.7644843   0.10429844   0.86878274  0.013161339 
+   14000   0.56152694  0.067836655   0.62936359  0.016852121 
+   15000   0.41895506  0.019513348   0.43846841  0.015225695 
+   16000   0.55799421    0.1564559   0.71445011  0.011703561 
+   17000   0.59391964  0.034450221   0.62836986  0.026215002 
+   18000   0.75911858  0.030885726    0.7900043  0.018396366 
+   19000   0.64417995   0.12110912   0.76528907  0.010247952 
+   20000   0.57751435   0.16965651   0.74717086  0.023392323 
+   21000    0.7613368   0.13405354   0.89539034  0.021498982 
+   22000   0.57676692   0.18011879   0.75688571  0.024469161 
+   23000   0.54043723   0.11842026   0.65885749  0.019799067 
+   24000   0.62276061  0.038967924   0.66172853  0.019080086 
+   25000   0.53157536   0.11651937   0.64809473  0.017019298 
+   26000   0.72213293  0.039012448   0.76114538  0.015434904 
+   27000   0.62157832   0.13697494   0.75855326  0.028711011 
+   28000   0.41323738   0.16301101   0.57624839  0.041792632 
+   29000   0.45774328   0.17569066   0.63343394  0.019975231 
+   30000   0.78901796  0.099791386   0.88880934  0.024116947 
+   31000   0.85205397   0.11977547   0.97182945  0.026667489 
+   32000   0.37137095    0.1232622   0.49463315 0.00087637364 
+   33000   0.26860871   0.26056381   0.52917252  0.036110517 
+   34000    0.3018636   0.21336905   0.51523265  0.040315549 
+   35000   0.39915129   0.28245957   0.68161085  0.034876856 
+   36000   0.25761236    0.2352705   0.49288286  0.022772767 
+   37000    0.1071233   0.31692858   0.42405188  0.017994666 
+   38000  0.083729577   0.28473145   0.36846103 -0.0045370431 
+   39000  0.070355565   0.26682083   0.33717639  0.017921556 
+   40000  0.075894079   0.20077896   0.27667304  0.014873186 
+   41000   0.05891028   0.15989064   0.21880092  0.025547873 
+   42000    0.1225107   0.16583605   0.28834675  0.038842785 
+   43000   0.17049189   0.14323991    0.3137318  0.029550161 
+   44000   0.26823939   0.15208257   0.42032196  0.028113612 
+   45000   0.10172203    0.1729706   0.27469264 -0.013769913 
+   46000   0.14841355   0.19085074   0.33926429 -0.00073741985 
+   47000   0.27654927   0.19097937   0.46752864   0.04021431 
+   48000   0.53432331  0.080769923   0.61509323  0.029932845 
+   49000   0.69111634   0.13064951   0.82176585  0.028985406 
+   50000   0.24520806   0.18317453   0.42838258   0.05179746 
+   51000   0.23541368   0.14281364   0.37822732  0.071884238 
+   52000   0.25464996  0.095730242    0.3503802  0.034488204 
+   53000   0.53677633    0.1058745   0.64265084  0.059932498 
+   54000   0.32970921   0.27979128   0.60950049  0.062869716 
+   55000   0.49094054  0.096735015   0.58767556   0.04728005 
+   56000   0.54398249    0.2216472   0.76562969  0.056712022 
+   57000   0.60869068    0.2338422   0.84253288  0.077143302 
+   58000   0.72175509   0.18687368   0.90862877  0.019357656 
+   59000   0.79442757  0.092502981   0.88693055  0.066882632 
+   60000    0.6810555  0.077699385   0.75875488  0.095975173 
+   61000   0.63178834   0.05071143   0.68249977  0.043586668 
+   62000   0.76589344  0.044615704   0.81050914  0.085718411 
+   63000   0.84815889  0.030527848   0.87868674  0.053072795 
+   64000    0.7309043  0.051938637   0.78284294  0.058887766 
+   65000   0.62498816  0.034474465   0.65946262  0.068446407 
+   66000   0.69817494  0.068546004   0.76672094  0.062634433 
+   67000   0.86444275  0.010184259   0.87462701  0.073635055 
+   68000   0.77820319 0.0079319524   0.78613515  0.090330925 
+   69000   0.56938919 0.0092629332   0.57865213  0.061838729 
+   70000   0.61870712  0.010047381    0.6287545  0.066501338 
+   71000   0.71651803 0.0088366199   0.72535465  0.079136316 
+   72000   0.76278925  0.008828151   0.77161741  0.063672771 
+   73000   0.75447428 0.0083985526   0.76287283  0.078256913 
+   74000   0.66185251 0.0091910052   0.67104351  0.069840511 
+   75000   0.58458829 0.0097671568   0.59435544  0.076123422 
+   76000    0.7487564    0.0100022    0.7587586  0.076171741 
+   77000   0.89505465  0.009250681   0.90430533  0.074921699 
+   78000   0.73738164 0.0092029279   0.74658457  0.078835344 
+   79000   0.65735281  0.010099528   0.66745233  0.077940627 
+   80000   0.70247542  0.010306464   0.71278189  0.079560093 
+   81000   0.74839505  0.010199092   0.75859415  0.080835104 
+   82000   0.75193767  0.010274058   0.76221173  0.081086684 
+   83000   0.71392598  0.010495573   0.72442156  0.082746145 
+   84000   0.58498928  0.011027388   0.59601667   0.08356465 
+   85000   0.59022869  0.011729474   0.60195817  0.084519397 
+   86000   0.81753578  0.011208964   0.82874475  0.085490261 
+   87000   0.83480682  0.010542579    0.8453494  0.086268527 
+   88000   0.67322538  0.011170734   0.68439611   0.08751623 
+   89000   0.62637389  0.012033316    0.6384072  0.088548094 
+   90000   0.92828557  0.011750388   0.94003596  0.089199823 
+   91000   0.96072564  0.010324509   0.97105015  0.090204803 
+   92000   0.72105071  0.011484152   0.73253486   0.09140819 
+   93000   0.65762527  0.012558219   0.67018349  0.092453474 
+   94000   0.73991591   0.01261909     0.752535  0.093373477 
+   95000   0.91791653  0.011980455   0.92989699  0.094182136 
+   96000   0.76562561  0.011807085    0.7774327  0.095323684 
+   97000   0.57292104  0.013610205   0.58653124  0.096505977 
+   98000   0.68141076  0.013863204   0.69527396  0.097380069 
+   99000   0.82390969  0.013002341   0.83691203  0.098235926 
+  100000   0.77639728  0.012989342   0.78938662  0.099274147 
+Loop time of 3.88899 on 1 procs for 100000 steps with 32 atoms
+
+Performance: 2221655.884 tau/day, 25713.610 timesteps/s
+99.9% CPU use with 1 MPI tasks x no OpenMP threads
+
+MPI task timing breakdown:
+Section |  min time  |  avg time  |  max time  |%varavg| %total
+---------------------------------------------------------------
+Pair    | 3.056      | 3.056      | 3.056      |   0.0 | 78.58
+Neigh   | 0.0051048  | 0.0051048  | 0.0051048  |   0.0 |  0.13
+Comm    | 0.091444   | 0.091444   | 0.091444   |   0.0 |  2.35
+Output  | 0.0011995  | 0.0011995  | 0.0011995  |   0.0 |  0.03
+Modify  | 0.69909    | 0.69909    | 0.69909    |   0.0 | 17.98
+Other   |            | 0.03616    |            |       |  0.93
+
+Nlocal:    32 ave 32 max 32 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+Nghost:    21 ave 21 max 21 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+Neighs:    57 ave 57 max 57 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+
+Total # of neighbors = 57
+Ave neighs/atom = 1.78125
+Neighbor list builds = 1445
+Dangerous builds = 0
+Total wall time: 0:00:03
diff --git a/examples/body/log.9Jul18.body.squares.g++.4 b/examples/body/log.9Jul18.body.squares.g++.4
new file mode 100644
index 0000000000000000000000000000000000000000..56d7734b7ba2a1919c1581799bb2eb83660aa4c9
--- /dev/null
+++ b/examples/body/log.9Jul18.body.squares.g++.4
@@ -0,0 +1,221 @@
+LAMMPS (29 Jun 2018)
+# 2d rounded polygon bodies
+
+variable    r     index 4
+variable    steps index 100000
+variable    T     index 0.5
+variable    P     index 0.1
+variable    seed  index 980411
+
+units       lj
+dimension   2
+
+atom_style  body rounded/polygon 1 6
+atom_modify map array
+read_data   data.squares
+  orthogonal box = (0 0 -0.5) to (12 12 0.5)
+  2 by 2 by 1 MPI processor grid
+  reading atoms ...
+  2 atoms
+  2 bodies
+
+replicate   $r $r 1
+replicate   4 $r 1
+replicate   4 4 1
+  orthogonal box = (0 0 -0.5) to (48 48 0.5)
+  2 by 2 by 1 MPI processor grid
+  32 atoms
+  Time spent = 0.000324011 secs
+
+velocity    all create $T ${seed} dist gaussian mom yes rot yes
+velocity    all create 0.5 ${seed} dist gaussian mom yes rot yes
+velocity    all create 0.5 980411 dist gaussian mom yes rot yes
+
+variable cut_inner  equal 0.5
+variable k_n        equal 100
+variable k_na       equal 2
+variable c_n        equal 1
+variable c_t        equal 1
+variable mu         equal 0.1
+variable delta_ua   equal 0.5
+
+pair_style body/rounded/polygon ${c_n} ${c_t} ${mu} ${delta_ua} ${cut_inner}
+pair_style body/rounded/polygon 1 ${c_t} ${mu} ${delta_ua} ${cut_inner}
+pair_style body/rounded/polygon 1 1 ${mu} ${delta_ua} ${cut_inner}
+pair_style body/rounded/polygon 1 1 0.1 ${delta_ua} ${cut_inner}
+pair_style body/rounded/polygon 1 1 0.1 0.5 ${cut_inner}
+pair_style body/rounded/polygon 1 1 0.1 0.5 0.5
+pair_coeff * * ${k_n} ${k_na}
+pair_coeff * * 100 ${k_na}
+pair_coeff * * 100 2
+
+comm_modify vel yes
+
+neighbor     0.5 bin
+neigh_modify every 1 delay 0 check yes
+
+timestep     0.001
+
+#fix         1 all nve/body
+#fix         1 all nvt/body temp $T $T 1.0
+fix          1 all npt/body temp $T $T 1.0 x 0.001 $P 1.0              y 0.001 $P 1.0 couple xy fixedpoint 0 0 0
+fix          1 all npt/body temp 0.5 $T 1.0 x 0.001 $P 1.0              y 0.001 $P 1.0 couple xy fixedpoint 0 0 0
+fix          1 all npt/body temp 0.5 0.5 1.0 x 0.001 $P 1.0              y 0.001 $P 1.0 couple xy fixedpoint 0 0 0
+fix          1 all npt/body temp 0.5 0.5 1.0 x 0.001 0.1 1.0              y 0.001 $P 1.0 couple xy fixedpoint 0 0 0
+fix          1 all npt/body temp 0.5 0.5 1.0 x 0.001 0.1 1.0              y 0.001 0.1 1.0 couple xy fixedpoint 0 0 0
+
+fix          2 all enforce2d
+
+#compute      1 all body/local id 1 2 3
+#dump         1 all local 100000 dump.polygon.* index c_1[1] c_1[2] c_1[3] c_1[4]
+
+thermo_style custom step ke pe etotal press
+thermo       1000
+
+#dump	     2 all image 10000 image.*.jpg type type zoom 2.0 #             adiam 1.5 body type 0 0
+#dump_modify  2 pad 6
+
+run          ${steps}
+run          100000
+Neighbor list info ...
+  update every 1 steps, delay 0 steps, check yes
+  max neighbors/atom: 2000, page size: 100000
+  master list distance cutoff = 6.15685
+  ghost atom cutoff = 6.15685
+  binsize = 3.07843, bins = 16 16 1
+  1 neighbor lists, perpetual/occasional/extra = 1 0 0
+  (1) pair body/rounded/polygon, perpetual
+      attributes: half, newton on
+      pair build: half/bin/atomonly/newton
+      stencil: half/bin/2d/newton
+      bin: standard
+Per MPI rank memory allocation (min/avg/max) = 4.774 | 4.774 | 4.774 Mbytes
+Step KinEng PotEng TotEng Press 
+       0     0.484375         0.25     0.734375 0.0067274306 
+    1000   0.39423376 0.0017918048   0.39602557 0.0021941612 
+    2000   0.42284177   0.01346585   0.43630762 0.0029377883 
+    3000   0.58154405  0.011321689   0.59286574  0.003667871 
+    4000   0.73518304  0.034603175   0.76978621 0.0018689207 
+    5000   0.84367476  0.025292163   0.86896692 0.0089161373 
+    6000   0.70803236 0.0085631016   0.71659546 0.0045552895 
+    7000   0.56206452   0.10453031   0.66659483  0.010255161 
+    8000   0.64538994  0.088817673   0.73420761 0.0037633655 
+    9000   0.90540819  0.063696004   0.96910419 0.0077673359 
+   10000   0.68632042  0.093265016   0.77958544 0.0057864837 
+   11000   0.59118074  0.025654748   0.61683549  0.012518759 
+   12000   0.67522767  0.038176401   0.71340407   0.01741153 
+   13000    0.7644843   0.10429844   0.86878274  0.013161339 
+   14000   0.56152694  0.067836656    0.6293636  0.016852113 
+   15000   0.41895505  0.019513353   0.43846841  0.015225696 
+   16000   0.55799443   0.15645637    0.7144508  0.011703646 
+   17000   0.59385248   0.03451986   0.62837234  0.025482966 
+   18000   0.75902169  0.031103586   0.79012527  0.018263354 
+   19000   0.64266826   0.12535314   0.76802141  0.014884119 
+   20000   0.57836261   0.16581188   0.74417449  0.024667165 
+   21000   0.78281936   0.11877527   0.90159464 -0.0090089213 
+   22000    0.5312006   0.13300874   0.66420934  0.025797278 
+   23000   0.56458861  0.084369128   0.64895774  0.024630917 
+   24000   0.65126875   0.06122992   0.71249867  0.034377198 
+   25000   0.55173441   0.15694886   0.70868327  0.021634086 
+   26000   0.59121615   0.17071182   0.76192797  0.024758366 
+   27000    0.6394843   0.17442949   0.81391378  0.034919937 
+   28000   0.31144221   0.41243036   0.72387256  0.074115225 
+   29000   0.13516917    0.3075419   0.44271107  0.023861298 
+   30000   0.14094934   0.24407203   0.38502137  0.037030438 
+   31000   0.26313749  0.087395422   0.35053291  0.042347005 
+   32000   0.51602457  0.063012079   0.57903664  0.018550299 
+   33000   0.55628829     0.200213   0.75650129  0.026507686 
+   34000   0.97399408  0.082504517    1.0564986  0.037889878 
+   35000   0.64710533   0.17662002   0.82372535  0.058295508 
+   36000   0.45769083   0.08241194   0.54010277  0.014957415 
+   37000   0.72850105  0.053874061   0.78237512  0.037194593 
+   38000   0.44177995   0.28939498   0.73117493  0.045194029 
+   39000   0.46828451  0.077630686   0.54591519  0.089849009 
+   40000   0.46786451  0.092828423   0.56069294  0.028042052 
+   41000   0.71861856  0.097085715   0.81570427  0.036473296 
+   42000   0.74121021   0.10553127   0.84674148  0.054058843 
+   43000   0.62945489   0.12770673   0.75716161  0.047267994 
+   44000   0.49900638  0.085150056   0.58415644  0.054798793 
+   45000   0.70199572  0.063415877    0.7654116  0.038363546 
+   46000   0.49513142   0.10649384   0.60162526  0.059392561 
+   47000    0.3858898  0.079458749   0.46534855  0.051825764 
+   48000   0.62585854  0.028585902   0.65444444  0.054074424 
+   49000   0.65934482   0.51865062    1.1779954 -0.035272836 
+   50000    0.5420438  0.082056756   0.62410056  0.031187494 
+   51000   0.36685223   0.14224019   0.50909241  0.073790397 
+   52000   0.19044627   0.15368389   0.34413016  0.059034266 
+   53000   0.26847678  0.075693324    0.3441701  0.032276915 
+   54000    0.3593711   0.19034549   0.54971659  0.070827883 
+   55000   0.21659198    0.1929074   0.40949939  0.035916364 
+   56000   0.28242715   0.12313241   0.40555956  0.062083926 
+   57000   0.34067475   0.14711992   0.48779467  0.059321458 
+   58000    0.4842796   0.16143425   0.64571385  0.059048247 
+   59000   0.84438871  0.076546849   0.92093556  0.048046901 
+   60000   0.92794849  0.054331626   0.98228012  0.058392272 
+   61000    0.6916736  0.076168342   0.76784194  0.058654987 
+   62000   0.63317965  0.094506389   0.72768604  0.061044719 
+   63000   0.63317266  0.038785593   0.67195825  0.097236147 
+   64000   0.81696668     0.121811   0.93877769  0.064935373 
+   65000   0.82644758   0.25188344     1.078331  0.093352359 
+   66000   0.64975019   0.17930857   0.82905876  0.058805254 
+   67000   0.63487678   0.16877059   0.80364737  0.070254696 
+   68000   0.79140717   0.11631004    0.9077172  0.064646394 
+   69000   0.85687272  0.057835331   0.91470805  0.071057291 
+   70000   0.67785976  0.040686768   0.71854653  0.074687222 
+   71000   0.60594577  0.032193155   0.63813893  0.069349268 
+   72000   0.77586745  0.024068533   0.79993598  0.083394193 
+   73000   0.88877625  0.025746326   0.91452258  0.081511105 
+   74000   0.73507888  0.036574786   0.77165367  0.075360233 
+   75000   0.68787782  0.042098622   0.72997644  0.068651098 
+   76000   0.72515745   0.04360868   0.76876613  0.069594624 
+   77000   0.77580944  0.041826702   0.81763614  0.071937144 
+   78000   0.76640394  0.039285046   0.80568899  0.074274921 
+   79000   0.62504309  0.039593585   0.66463667  0.076443295 
+   80000   0.60001642  0.043468215   0.64348464  0.094547719 
+   81000   0.82175037  0.045608873   0.86735924  0.080186295 
+   82000   0.85783276  0.042692576   0.90052534  0.081576548 
+   83000   0.71367707  0.042172193   0.75584926   0.08256625 
+   84000   0.68532406  0.044724759   0.73004882  0.083672013 
+   85000   0.72576789  0.046982462   0.77275035  0.084789331 
+   86000   0.75597701   0.04765086   0.80362787  0.085758056 
+   87000   0.74190598  0.047629096   0.78953507  0.086679976 
+   88000   0.60967704  0.049906172   0.65958321  0.085526191 
+   89000   0.54490288  0.054768238   0.59967112  0.090604027 
+   90000   0.75398341  0.057153453   0.81113686  0.091900858 
+   91000   0.84577472  0.052753512   0.89852823  0.091913909 
+   92000    0.7176235  0.050677427   0.76830093  0.092032507 
+   93000   0.61699446  0.054097013   0.67109147  0.092071275 
+   94000   0.76330752  0.057398618   0.82070614  0.092435043 
+   95000   0.98754458  0.053801311    1.0413459  0.093526707 
+   96000    0.7405897  0.052135628   0.79272533  0.095011929 
+   97000   0.65587599  0.057011962   0.71288795  0.096692123 
+   98000   0.72345634  0.060700171   0.78415651  0.097510345 
+   99000   0.88283624  0.061795247   0.94463149   0.09799633 
+  100000   0.86303812  0.058912988   0.92195111   0.09892993 
+Loop time of 2.80074 on 4 procs for 100000 steps with 32 atoms
+
+Performance: 3084895.573 tau/day, 35704.810 timesteps/s
+99.9% CPU use with 4 MPI tasks x no OpenMP threads
+
+MPI task timing breakdown:
+Section |  min time  |  avg time  |  max time  |%varavg| %total
+---------------------------------------------------------------
+Pair    | 0.81169    | 0.89466    | 0.97669    |   8.4 | 31.94
+Neigh   | 0.0017524  | 0.0018129  | 0.0018773  |   0.1 |  0.06
+Comm    | 0.91307    | 0.99193    | 1.0691     |   7.3 | 35.42
+Output  | 0.00076914 | 0.00093722 | 0.0013936  |   0.0 |  0.03
+Modify  | 0.75335    | 0.75779    | 0.76346    |   0.4 | 27.06
+Other   |            | 0.1536     |            |       |  5.48
+
+Nlocal:    8 ave 10 max 4 min
+Histogram: 1 0 0 0 0 0 1 0 0 2
+Nghost:    17.25 ave 19 max 15 min
+Histogram: 1 0 1 0 0 0 0 0 0 2
+Neighs:    13.5 ave 21 max 5 min
+Histogram: 1 0 0 0 1 0 1 0 0 1
+
+Total # of neighbors = 54
+Ave neighs/atom = 1.6875
+Neighbor list builds = 1443
+Dangerous builds = 0
+Total wall time: 0:00:02
diff --git a/examples/body/log.9Jul18.body.wall2d.g++.1 b/examples/body/log.9Jul18.body.wall2d.g++.1
new file mode 100644
index 0000000000000000000000000000000000000000..f22c3663802a487158fffc74c13931f9d83a9416
--- /dev/null
+++ b/examples/body/log.9Jul18.body.wall2d.g++.1
@@ -0,0 +1,223 @@
+LAMMPS (29 Jun 2018)
+# 2d rounded polygon bodies
+
+variable    r     index 4
+variable    steps index 100000
+variable    T     index 0.5
+variable    P     index 0.1
+variable    seed  index 980411
+
+units       lj
+dimension   2
+
+atom_style  body rounded/polygon 1 6
+atom_modify map array
+read_data   data.squares
+  orthogonal box = (0 0 -0.5) to (12 12 0.5)
+  1 by 1 by 1 MPI processor grid
+  reading atoms ...
+  2 atoms
+  2 bodies
+
+replicate   $r $r 1
+replicate   4 $r 1
+replicate   4 4 1
+  orthogonal box = (0 0 -0.5) to (48 48 0.5)
+  1 by 1 by 1 MPI processor grid
+  32 atoms
+  Time spent = 0.00029707 secs
+
+velocity    all create $T ${seed} dist gaussian mom yes rot yes
+velocity    all create 0.5 ${seed} dist gaussian mom yes rot yes
+velocity    all create 0.5 980411 dist gaussian mom yes rot yes
+
+change_box  all boundary p f p
+
+variable cut_inner  equal 0.5
+variable k_n        equal 100
+variable k_na       equal 2
+variable c_n        equal 0.1
+variable c_t        equal 0.1
+variable mu         equal 0.1
+variable delta_ua   equal 0.5
+
+pair_style body/rounded/polygon ${c_n} ${c_t} ${mu} ${delta_ua} ${cut_inner}
+pair_style body/rounded/polygon 0.1 ${c_t} ${mu} ${delta_ua} ${cut_inner}
+pair_style body/rounded/polygon 0.1 0.1 ${mu} ${delta_ua} ${cut_inner}
+pair_style body/rounded/polygon 0.1 0.1 0.1 ${delta_ua} ${cut_inner}
+pair_style body/rounded/polygon 0.1 0.1 0.1 0.5 ${cut_inner}
+pair_style body/rounded/polygon 0.1 0.1 0.1 0.5 0.5
+pair_coeff * * ${k_n} ${k_na}
+pair_coeff * * 100 ${k_na}
+pair_coeff * * 100 2
+
+comm_modify vel yes
+
+neighbor     0.5 bin
+neigh_modify every 1 delay 0 check yes
+
+timestep     0.001
+
+#fix         1 all nve/body
+#fix         1 all nvt/body temp $T $T 1.0
+fix          1 all npt/body temp $T $T 1.0 x 0.001 $P 1.0 fixedpoint 0 0 0
+fix          1 all npt/body temp 0.5 $T 1.0 x 0.001 $P 1.0 fixedpoint 0 0 0
+fix          1 all npt/body temp 0.5 0.5 1.0 x 0.001 $P 1.0 fixedpoint 0 0 0
+fix          1 all npt/body temp 0.5 0.5 1.0 x 0.001 0.1 1.0 fixedpoint 0 0 0
+
+fix          2 all enforce2d
+fix          3 all wall/body/polygon 2000 50 50 yplane 0.0 48.0
+
+#compute      1 all body/local id 1 2 3
+#dump         1 all local 100000 dump.polygon.* index c_1[1] c_1[2] c_1[3] c_1[4]
+
+thermo_style custom step ke pe etotal press
+thermo       1000
+
+#dump	     2 all image 10000 image.*.jpg type type zoom 2.0 #             adiam 1.5 body type 0 0
+#dump_modify  2 pad 6
+
+run          ${steps}
+run          100000
+Neighbor list info ...
+  update every 1 steps, delay 0 steps, check yes
+  max neighbors/atom: 2000, page size: 100000
+  master list distance cutoff = 6.15685
+  ghost atom cutoff = 6.15685
+  binsize = 3.07843, bins = 16 16 1
+  1 neighbor lists, perpetual/occasional/extra = 1 0 0
+  (1) pair body/rounded/polygon, perpetual
+      attributes: half, newton on
+      pair build: half/bin/atomonly/newton
+      stencil: half/bin/2d/newton
+      bin: standard
+Per MPI rank memory allocation (min/avg/max) = 4.771 | 4.771 | 4.771 Mbytes
+Step KinEng PotEng TotEng Press 
+       0     0.484375         0.25     0.734375 0.0067274306 
+    1000   0.49241101 0.0031318767   0.49554289  0.017768281 
+    2000   0.56118632 0.0026068888   0.56379321  0.003410416 
+    3000   0.75565115  0.025578366   0.78122951 0.0071862988 
+    4000   0.72298647  0.093150646   0.81613712  0.003190158 
+    5000   0.51684166  0.049164868   0.56600653 0.0096960168 
+    6000   0.56627905  0.048132853    0.6144119  0.020733586 
+    7000   0.58122129  0.018223718   0.59944501 0.0038160759 
+    8000   0.64297977  0.025934821   0.66891459 0.0041091784 
+    9000   0.41748404 0.0077890042   0.42527305 0.0039270065 
+   10000   0.35738377  0.078487805   0.43587158 3.9079782e-05 
+   11000   0.41529308   0.13619284   0.55148592 -0.0067482285 
+   12000   0.43274718  0.071315497   0.50406268  0.007006378 
+   13000    0.4748331  0.069904647   0.54473775 0.0010384372 
+   14000    0.6287791   0.12721033   0.75598943 0.0047792448 
+   15000    0.4692413   0.12344005   0.59268136  0.018033616 
+   16000   0.43157074   0.14306789   0.57463862  0.042356676 
+   17000   0.53085999   0.22126296   0.75212294  0.027509646 
+   18000   0.52688968   0.13225282    0.6591425 0.0021558013 
+   19000   0.55032328   0.12513047   0.67545375  0.025036251 
+   20000   0.48465097    0.1431055   0.62775647  0.017193781 
+   21000   0.53166734   0.21928574   0.75095307  0.011564317 
+   22000   0.62177353   0.09296159   0.71473512  0.017660922 
+   23000    0.6972939   0.12434123   0.82163514  0.024432327 
+   24000   0.42767372   0.22152311   0.64919684 -0.013712449 
+   25000    0.4816037   0.19272865   0.67433236  0.052386055 
+   26000   0.72642579   0.19697046   0.92339625  0.020407694 
+   27000   0.39649144   0.15058326    0.5470747  0.023705766 
+   28000   0.44896324   0.18500106    0.6339643 -0.0089410286 
+   29000    0.5565759   0.11085772   0.66743362  0.048437166 
+   30000   0.58173584   0.21773281   0.79946865 0.0057357773 
+   31000   0.49199415   0.23601982   0.72801397  0.046744152 
+   32000   0.55665496   0.20542161   0.76207658 -0.0038756805 
+   33000   0.62730739   0.24460524   0.87191263  0.045330682 
+   34000   0.58107044   0.16395278   0.74502322 -0.0049496051 
+   35000   0.56838849   0.21842922   0.78681771 0.0062086036 
+   36000   0.45910273   0.28464172   0.74374445 -0.011700747 
+   37000   0.37092037   0.27646862     0.647389  0.022305679 
+   38000    0.7278047   0.30674438    1.0345491   0.07698342 
+   39000    0.5132923   0.27395066   0.78724295  0.026898634 
+   40000   0.62348649   0.24424644   0.86773293  0.039403899 
+   41000    0.3658401   0.15512326   0.52096337  0.022559003 
+   42000    0.4912253   0.35712978   0.84835508 -0.010336341 
+   43000   0.70225957   0.36314638    1.0654059  0.004148866 
+   44000   0.56958157   0.25488927   0.82447084  0.067537066 
+   45000   0.45854352   0.30149439   0.76003791 -0.017002401 
+   46000   0.62787247   0.34567995   0.97355242   0.11894801 
+   47000   0.61348914   0.29378625   0.90727539  0.067873976 
+   48000   0.71301829   0.34135284    1.0543711  0.021077736 
+   49000   0.53520804   0.30593196   0.84113999 0.0059257647 
+   50000   0.44966403   0.35370793   0.80337195 0.0020395669 
+   51000    0.5236113   0.32296924   0.84658054 -0.051011506 
+   52000   0.53905573     0.351771   0.89082672  0.013720106 
+   53000   0.55978158   0.41293947   0.97272106  0.068558589 
+   54000   0.52170459    0.2718066    0.7935112 0.0093138985 
+   55000   0.61078876   0.43353897    1.0443277  0.045377392 
+   56000   0.51300655   0.33182278   0.84482933 -0.018418487 
+   57000   0.54882822   0.38380093   0.93262915   0.10249946 
+   58000   0.72106212   0.45361279    1.1746749  0.030313481 
+   59000   0.55871447   0.63823029    1.1969448  0.019079703 
+   60000   0.49395192   0.58283102    1.0767829    0.0179349 
+   61000   0.45991079   0.62540573    1.0853165  0.074398804 
+   62000    0.4655788   0.60862262    1.0742014   0.11472976 
+   63000   0.55634524   0.63069255    1.1870378 -0.0025676135 
+   64000   0.57688903   0.45435264    1.0312417 0.0083813852 
+   65000   0.57168922   0.42217005   0.99385927  0.044931269 
+   66000    0.6206044   0.46727538    1.0878798  0.019686229 
+   67000   0.61037155   0.41840109    1.0287726    0.0195109 
+   68000   0.63848598   0.41305347    1.0515395  0.072940144 
+   69000   0.49244916    0.3834095   0.87585866   0.07963677 
+   70000   0.41847062   0.51907975   0.93755037   0.18447904 
+   71000   0.45198986   0.52973709   0.98172695  0.078419371 
+   72000   0.47064262   0.37808165   0.84872427 -0.00046308054 
+   73000    0.6690143   0.37549359    1.0445079  0.061208432 
+   74000   0.60444955   0.33779636   0.94224592 -0.068840321 
+   75000   0.61762382    0.3916421    1.0092659   0.16253292 
+   76000   0.63657961   0.50277989    1.1393595  0.013857508 
+   77000   0.52524028   0.43597896   0.96121924  -0.03296482 
+   78000   0.43803533   0.33172284   0.76975817  0.078763029 
+   79000   0.67156089   0.55272177    1.2242827  0.080822223 
+   80000   0.68678238   0.46061627    1.1473987 0.0027036992 
+   81000   0.64956678   0.44959229    1.0991591   0.11201483 
+   82000   0.51060477   0.43508342    0.9456882  0.028000608 
+   83000   0.59550548   0.69026083    1.2857663 -0.0015809004 
+   84000   0.64222145   0.38768816    1.0299096  0.014153173 
+   85000    0.7661229   0.43445261    1.2005755  0.048034534 
+   86000   0.60025257   0.53027929    1.1305319 0.0056865157 
+   87000   0.46220939   0.47470035   0.93690974  0.075311946 
+   88000   0.54123847   0.62899839    1.1702369   0.13260162 
+   89000   0.61212272    0.6114241    1.2235468  0.033284822 
+   90000   0.63924773    0.6916249    1.3308726  0.045088296 
+   91000   0.49316865   0.51037033     1.003539  0.023203598 
+   92000   0.57572123   0.43496319    1.0106844     0.297092 
+   93000   0.65187559   0.56815972    1.2200353    0.1538215 
+   94000   0.64107331   0.58948521    1.2305585  0.031117778 
+   95000   0.64584158    0.6364688    1.2823104  0.096154676 
+   96000   0.60509093     0.601487    1.2065779   0.03457172 
+   97000   0.68837218   0.77974186     1.468114   0.17801164 
+   98000   0.62725266   0.64137144    1.2686241   0.17449001 
+   99000   0.46861221   0.67000291    1.1386151    0.2429588 
+  100000    0.5879119    0.7140612    1.3019731  0.064634257 
+Loop time of 2.50594 on 1 procs for 100000 steps with 32 atoms
+
+Performance: 3447804.126 tau/day, 39905.140 timesteps/s
+100.0% CPU use with 1 MPI tasks x no OpenMP threads
+
+MPI task timing breakdown:
+Section |  min time  |  avg time  |  max time  |%varavg| %total
+---------------------------------------------------------------
+Pair    | 1.5639     | 1.5639     | 1.5639     |   0.0 | 62.41
+Neigh   | 0.0086911  | 0.0086911  | 0.0086911  |   0.0 |  0.35
+Comm    | 0.058926   | 0.058926   | 0.058926   |   0.0 |  2.35
+Output  | 0.0012379  | 0.0012379  | 0.0012379  |   0.0 |  0.05
+Modify  | 0.83537    | 0.83537    | 0.83537    |   0.0 | 33.34
+Other   |            | 0.03781    |            |       |  1.51
+
+Nlocal:    32 ave 32 max 32 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+Nghost:    20 ave 20 max 20 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+Neighs:    57 ave 57 max 57 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+
+Total # of neighbors = 57
+Ave neighs/atom = 1.78125
+Neighbor list builds = 2705
+Dangerous builds = 0
+Total wall time: 0:00:02
diff --git a/examples/body/log.9Jul18.body.wall2d.g++.4 b/examples/body/log.9Jul18.body.wall2d.g++.4
new file mode 100644
index 0000000000000000000000000000000000000000..7239fd4dcd4fc6a55886d0bfd11a401ab3e97f23
--- /dev/null
+++ b/examples/body/log.9Jul18.body.wall2d.g++.4
@@ -0,0 +1,223 @@
+LAMMPS (29 Jun 2018)
+# 2d rounded polygon bodies
+
+variable    r     index 4
+variable    steps index 100000
+variable    T     index 0.5
+variable    P     index 0.1
+variable    seed  index 980411
+
+units       lj
+dimension   2
+
+atom_style  body rounded/polygon 1 6
+atom_modify map array
+read_data   data.squares
+  orthogonal box = (0 0 -0.5) to (12 12 0.5)
+  2 by 2 by 1 MPI processor grid
+  reading atoms ...
+  2 atoms
+  2 bodies
+
+replicate   $r $r 1
+replicate   4 $r 1
+replicate   4 4 1
+  orthogonal box = (0 0 -0.5) to (48 48 0.5)
+  2 by 2 by 1 MPI processor grid
+  32 atoms
+  Time spent = 0.000386 secs
+
+velocity    all create $T ${seed} dist gaussian mom yes rot yes
+velocity    all create 0.5 ${seed} dist gaussian mom yes rot yes
+velocity    all create 0.5 980411 dist gaussian mom yes rot yes
+
+change_box  all boundary p f p
+
+variable cut_inner  equal 0.5
+variable k_n        equal 100
+variable k_na       equal 2
+variable c_n        equal 0.1
+variable c_t        equal 0.1
+variable mu         equal 0.1
+variable delta_ua   equal 0.5
+
+pair_style body/rounded/polygon ${c_n} ${c_t} ${mu} ${delta_ua} ${cut_inner}
+pair_style body/rounded/polygon 0.1 ${c_t} ${mu} ${delta_ua} ${cut_inner}
+pair_style body/rounded/polygon 0.1 0.1 ${mu} ${delta_ua} ${cut_inner}
+pair_style body/rounded/polygon 0.1 0.1 0.1 ${delta_ua} ${cut_inner}
+pair_style body/rounded/polygon 0.1 0.1 0.1 0.5 ${cut_inner}
+pair_style body/rounded/polygon 0.1 0.1 0.1 0.5 0.5
+pair_coeff * * ${k_n} ${k_na}
+pair_coeff * * 100 ${k_na}
+pair_coeff * * 100 2
+
+comm_modify vel yes
+
+neighbor     0.5 bin
+neigh_modify every 1 delay 0 check yes
+
+timestep     0.001
+
+#fix         1 all nve/body
+#fix         1 all nvt/body temp $T $T 1.0
+fix          1 all npt/body temp $T $T 1.0 x 0.001 $P 1.0 fixedpoint 0 0 0
+fix          1 all npt/body temp 0.5 $T 1.0 x 0.001 $P 1.0 fixedpoint 0 0 0
+fix          1 all npt/body temp 0.5 0.5 1.0 x 0.001 $P 1.0 fixedpoint 0 0 0
+fix          1 all npt/body temp 0.5 0.5 1.0 x 0.001 0.1 1.0 fixedpoint 0 0 0
+
+fix          2 all enforce2d
+fix          3 all wall/body/polygon 2000 50 50 yplane 0.0 48.0
+
+#compute      1 all body/local id 1 2 3
+#dump         1 all local 100000 dump.polygon.* index c_1[1] c_1[2] c_1[3] c_1[4]
+
+thermo_style custom step ke pe etotal press
+thermo       1000
+
+#dump	     2 all image 10000 image.*.jpg type type zoom 2.0 #             adiam 1.5 body type 0 0
+#dump_modify  2 pad 6
+
+run          ${steps}
+run          100000
+Neighbor list info ...
+  update every 1 steps, delay 0 steps, check yes
+  max neighbors/atom: 2000, page size: 100000
+  master list distance cutoff = 6.15685
+  ghost atom cutoff = 6.15685
+  binsize = 3.07843, bins = 16 16 1
+  1 neighbor lists, perpetual/occasional/extra = 1 0 0
+  (1) pair body/rounded/polygon, perpetual
+      attributes: half, newton on
+      pair build: half/bin/atomonly/newton
+      stencil: half/bin/2d/newton
+      bin: standard
+Per MPI rank memory allocation (min/avg/max) = 4.773 | 4.773 | 4.773 Mbytes
+Step KinEng PotEng TotEng Press 
+       0     0.484375         0.25     0.734375 0.0067274306 
+    1000   0.49241101 0.0031318767   0.49554289  0.017768281 
+    2000   0.56118632 0.0026068888   0.56379321  0.003410416 
+    3000   0.75565115  0.025578366   0.78122951 0.0071862988 
+    4000   0.72298647  0.093150646   0.81613712  0.003190158 
+    5000   0.51684166  0.049164868   0.56600653 0.0096960168 
+    6000   0.56627905  0.048132853    0.6144119  0.020733586 
+    7000   0.58122129  0.018223718   0.59944501 0.0038160759 
+    8000   0.64297977  0.025934821   0.66891459 0.0041091784 
+    9000   0.41748404 0.0077890042   0.42527305 0.0039270065 
+   10000   0.35738377  0.078487805   0.43587158 3.9079865e-05 
+   11000   0.41529307   0.13619284   0.55148591 -0.0067482285 
+   12000   0.43274718  0.071315527   0.50406271  0.007006369 
+   13000    0.4748324  0.069905666   0.54473807 0.0010385254 
+   14000   0.62603727  0.098905625    0.7249429 0.0048876764 
+   15000   0.44512086   0.10415235   0.54927321   0.01902062 
+   16000   0.47460177   0.18053316   0.65513493  0.045013976 
+   17000   0.52742676   0.10110706   0.62853382  0.013615471 
+   18000   0.46111734  0.096118795   0.55723613 0.0073676834 
+   19000   0.59668439   0.13652292   0.73320731  0.029403553 
+   20000   0.46840192   0.11611719   0.58451911 -0.00034412499 
+   21000   0.53550533  0.096457461    0.6319628 0.0019785732 
+   22000   0.46599715   0.13206373   0.59806087  0.031970672 
+   23000   0.49280776   0.20404726   0.69685501   0.03657433 
+   24000   0.60901688   0.18255214   0.79156902  0.044955017 
+   25000   0.47345185   0.13671357   0.61016542  0.020313539 
+   26000   0.47653832   0.12448225   0.60102057   0.01878099 
+   27000   0.50008212   0.24740634   0.74748845  0.021862639 
+   28000   0.41627204    0.2519463   0.66821834  0.054683701 
+   29000   0.55608273   0.23100212   0.78708485 -0.0043318497 
+   30000   0.53884537    0.3001584   0.83900377 -0.012838186 
+   31000   0.53036238    0.2300328   0.76039518 -0.0061688449 
+   32000   0.42666792   0.20536256   0.63203048  0.045305282 
+   33000   0.62908185    0.1652033   0.79428515 0.0072777588 
+   34000   0.47028154     0.388736   0.85901754   0.04332288 
+   35000   0.54602322    0.2775624   0.82358562   0.02898206 
+   36000   0.59860544   0.21824655   0.81685199 0.0025936194 
+   37000   0.62467827   0.11983499   0.74451326  0.050052743 
+   38000   0.72594229   0.36584781    1.0917901   0.04280621 
+   39000   0.51129656   0.23859043   0.74988699  0.050817447 
+   40000   0.53263836   0.24212889   0.77476725  0.036245922 
+   41000   0.50288088   0.36668283   0.86956371  0.018381415 
+   42000   0.46653688   0.21974887   0.68628574  0.012661062 
+   43000   0.61738785   0.32131037   0.93869821  0.012709433 
+   44000   0.56603903   0.26515554   0.83119457   0.03315102 
+   45000   0.56231638   0.32111693   0.88343331   0.06079756 
+   46000    0.7096208    0.2570131   0.96663391  0.048770468 
+   47000     0.588755    0.1880748    0.7768298  0.035962604 
+   48000   0.56296339   0.25783519   0.82079858  0.053019928 
+   49000     0.419885   0.42328618   0.84317118  0.038105269 
+   50000   0.63073351   0.41426285    1.0449964 0.0015271048 
+   51000   0.59357935     0.184222   0.77780136  0.015996218 
+   52000   0.60608471   0.36247533   0.96856003   0.10984665 
+   53000    0.5227842   0.27686739   0.79965159   0.02761699 
+   54000   0.39435923   0.34197355   0.73633278  0.061183263 
+   55000   0.46748455   0.34230903   0.80979358  0.077441382 
+   56000   0.59819827   0.29212061   0.89031889  0.043772353 
+   57000   0.61682559   0.32788566   0.94471124   0.03992069 
+   58000   0.52702478   0.24891506   0.77593984  0.058480883 
+   59000   0.66925719    0.4109031    1.0801603  0.072434423 
+   60000   0.66807714   0.39233068    1.0604078  0.082370324 
+   61000    0.5724275   0.43308567    1.0055132 0.0072945426 
+   62000   0.49433556   0.38453743   0.87887299 0.0036097443 
+   63000   0.57575143   0.54067119    1.1164226  0.073339638 
+   64000   0.68045383   0.38246533    1.0629192  0.025314593 
+   65000   0.59843527   0.42928622    1.0277215 -0.030096445 
+   66000   0.60274797   0.50186417    1.1046121  0.069797184 
+   67000   0.47450407   0.52689807    1.0014021  0.008758012 
+   68000    0.5514135   0.64113187    1.1925454  0.093863314 
+   69000   0.52008074   0.45749565   0.97757639 -0.066061381 
+   70000   0.69042662   0.50416006    1.1945867  0.014128617 
+   71000   0.63925854   0.35153425    0.9907928  -0.01134957 
+   72000   0.52088835   0.47626986   0.99715821   0.10198133 
+   73000   0.46333852    0.5515537    1.0148922 0.00060582772 
+   74000   0.53481418   0.50409531    1.0389095   0.00919451 
+   75000   0.67182749   0.50380162    1.1756291  0.043301985 
+   76000   0.70492289    0.4112122    1.1161351   0.14880484 
+   77000   0.59781817   0.50197661    1.0997948 -0.057111711 
+   78000   0.51677429    0.4348232   0.95159749 -0.0074619446 
+   79000   0.50663297   0.55000424    1.0566372 0.0052071216 
+   80000   0.59392006   0.48394003    1.0778601 -0.018990234 
+   81000   0.66323593   0.40358336    1.0668193  -0.02961345 
+   82000   0.61596979   0.49177944    1.1077492    0.1314853 
+   83000   0.63917554   0.61656584    1.2557414   0.11908351 
+   84000   0.49305291   0.46161646   0.95466937  0.033558488 
+   85000   0.52552044   0.54250555     1.068026   0.13015174 
+   86000   0.55140914   0.38924725   0.94065638  0.047412499 
+   87000   0.60952504   0.52603688    1.1355619  0.039230066 
+   88000   0.50119735     0.547539    1.0487364  0.019659933 
+   89000   0.40331401   0.50331134   0.90662535 -0.056906034 
+   90000   0.47067839   0.51306911    0.9837475   0.11918166 
+   91000   0.45564995   0.38693455    0.8425845   0.12040045 
+   92000   0.64163032   0.34232532   0.98395564 0.0057051641 
+   93000   0.70375593   0.53646186    1.2402178   0.16044241 
+   94000   0.53378112   0.51971406    1.0534952   0.11389004 
+   95000   0.47055342   0.50396004   0.97451346  0.079424215 
+   96000   0.59543473   0.40204536   0.99748009  0.096813093 
+   97000   0.64821917   0.50051728    1.1487365  0.054071312 
+   98000   0.55723937    0.4945909    1.0518303  0.047316424 
+   99000   0.56044424   0.50773312    1.0681774    0.0149959 
+  100000   0.68254229   0.32704484    1.0095871 0.0069212661 
+Loop time of 2.20043 on 4 procs for 100000 steps with 32 atoms
+
+Performance: 3926501.701 tau/day, 45445.622 timesteps/s
+100.0% CPU use with 4 MPI tasks x no OpenMP threads
+
+MPI task timing breakdown:
+Section |  min time  |  avg time  |  max time  |%varavg| %total
+---------------------------------------------------------------
+Pair    | 0.41008    | 0.41366    | 0.41719    |   0.4 | 18.80
+Neigh   | 0.0027823  | 0.0030481  | 0.0034747  |   0.5 |  0.14
+Comm    | 0.74581    | 0.7675     | 0.78684    |   2.0 | 34.88
+Output  | 0.00082111 | 0.0010884  | 0.0016899  |   1.1 |  0.05
+Modify  | 0.83828    | 0.85329    | 0.86656    |   1.4 | 38.78
+Other   |            | 0.1618     |            |       |  7.36
+
+Nlocal:    8 ave 9 max 7 min
+Histogram: 1 0 0 0 0 2 0 0 0 1
+Nghost:    12.75 ave 14 max 12 min
+Histogram: 2 0 0 0 0 1 0 0 0 1
+Neighs:    11 ave 19 max 5 min
+Histogram: 1 0 0 2 0 0 0 0 0 1
+
+Total # of neighbors = 44
+Ave neighs/atom = 1.375
+Neighbor list builds = 2663
+Dangerous builds = 0
+Total wall time: 0:00:02
diff --git a/examples/body/molecule.cube b/examples/body/molecule.cube
new file mode 100644
index 0000000000000000000000000000000000000000..2a8a7bca5023155889095b303b22d3aef201d2cc
--- /dev/null
+++ b/examples/body/molecule.cube
@@ -0,0 +1,52 @@
+# 3d polygon body: cubes, moment of inertia I = m edge^2/ 6
+
+1 atoms
+3 79 body
+
+Coords
+
+1 0 0 0
+
+Types
+
+1 1
+
+Masses
+
+1 1.0
+
+Body Integers
+
+8 12 6
+
+Body Doubles
+
+0.667 0.667 0.667 0 0 0
+1 1 1
+1 -1 1
+-1 -1 1
+-1 1 1
+1 1 -1
+1 -1 -1
+-1 -1 -1
+-1 1 -1
+0 1
+1 2
+2 3
+3 0
+4 5
+5 6
+6 7
+7 4
+0 4
+1 5
+2 6
+3 7
+0 1 2 3
+4 5 6 7
+0 1 5 4
+1 2 6 5
+2 3 7 6
+3 0 4 7
+0.5
+
diff --git a/examples/body/molecule.point3d b/examples/body/molecule.point3d
new file mode 100644
index 0000000000000000000000000000000000000000..d22bfbe6fa9d58e0df10b2cba22dd1b402185e9a
--- /dev/null
+++ b/examples/body/molecule.point3d
@@ -0,0 +1,26 @@
+# 2d polygon body: disks Izz = 1/2 m radius^2
+
+1 atoms
+3 10 body
+
+Coords
+
+1 0 0 0
+
+Types
+
+1 1
+
+Masses
+
+1 1.0
+
+Body Integers
+
+1 0 0
+
+Body Doubles
+
+1 1 1.125 0 0 0
+0 0 0 
+3.0
diff --git a/examples/body/molecule.rod3d b/examples/body/molecule.rod3d
new file mode 100644
index 0000000000000000000000000000000000000000..1c8a0a8cd3eecfa325d2a1c99a38edca26d0a789
--- /dev/null
+++ b/examples/body/molecule.rod3d
@@ -0,0 +1,27 @@
+# 2d polygon body: rods Izz = 1/12 m length^2
+
+1 atoms
+3 13 body
+
+Coords
+
+1 0 0 0
+
+Types
+
+1 1
+
+Masses
+
+1 1.0
+
+Body Integers
+
+2 1 0
+
+Body Doubles
+
+1 1 1.333 0 0 0
+-2 0 0
+2 0 0
+0.5
diff --git a/examples/body/molecule.tetra b/examples/body/molecule.tetra
new file mode 100644
index 0000000000000000000000000000000000000000..d67ec906c64868521eaae59f8284697e18ff7d72
--- /dev/null
+++ b/examples/body/molecule.tetra
@@ -0,0 +1,39 @@
+# 3d polygon body: regular tetrahedra, moment of inertia I = m edge^2/ 20
+
+1 atoms
+3 47 body
+
+Coords
+
+1 0 0 0
+
+Types
+
+1 1
+
+Masses
+
+1 1.0
+
+Body Integers
+
+4 6 4
+
+Body Doubles
+
+0.4 0.4 0.4 0 0 0
+1 1 1
+1 -1 -1
+-1 1 -1
+-1 -1 1
+0 1
+0 2
+0 3
+1 2
+2 3
+3 1
+0 1 2 -1
+0 1 3 -1
+0 2 3 -1
+1 2 3 -1
+0.5
diff --git a/lib/gpu/geryon/nvd_device.h b/lib/gpu/geryon/nvd_device.h
index 2d2a751f85b47dbef4e08bb0ec69858a8ecc4798..129bdbbdef7b6af52792ccec44fb0446744e7c0e 100644
--- a/lib/gpu/geryon/nvd_device.h
+++ b/lib/gpu/geryon/nvd_device.h
@@ -260,6 +260,9 @@ class UCL_Device {
   /// List all devices along with all properties
   inline void print_all(std::ostream &out);
 
+  /// Select the platform that has accelerators (for compatibility with OpenCL)
+  inline int set_platform_accelerator(int pid=-1) { return UCL_SUCCESS; }
+
  private:
   int _device, _num_devices;
   std::vector<NVDProperties> _properties;
diff --git a/lib/gpu/geryon/ocl_device.h b/lib/gpu/geryon/ocl_device.h
index 2b2367545e837427527cad44843a5cb31fd09d30..14455e38a50740784fe2c28fc3ae5a6673c85796 100644
--- a/lib/gpu/geryon/ocl_device.h
+++ b/lib/gpu/geryon/ocl_device.h
@@ -165,8 +165,8 @@ class UCL_Device {
   /// Get the current OpenCL device name
   inline std::string name() { return name(_device); }
   /// Get the OpenCL device name
-  inline std::string name(const int i)
-    { return std::string(_properties[i].name); }
+  inline std::string name(const int i) {
+    return std::string(_properties[i].name); }
 
   /// Get a string telling the type of the current device
   inline std::string device_type_name() { return device_type_name(_device); }
@@ -281,7 +281,7 @@ class UCL_Device {
   inline cl_device_id & cl_device() { return _cl_device; }
 
   /// Select the platform that has accelerators
-  inline void set_platform_accelerator(int pid=-1);
+  inline int set_platform_accelerator(int pid=-1);
 
  private:
   int _num_platforms;          // Number of platforms
@@ -324,6 +324,7 @@ UCL_Device::~UCL_Device() {
 
 void UCL_Device::clear() {
   _properties.clear();
+  _cl_devices.clear();
   if (_device>-1) {
     for (size_t i=0; i<_cq.size(); i++) {
       CL_DESTRUCT_CALL(clReleaseCommandQueue(_cq.back()));
@@ -520,8 +521,6 @@ int UCL_Device::device_type(const int i) {
 
 // Set the CUDA device to the specified device number
 int UCL_Device::set(int num) {
-  clear();
-
   cl_device_id *device_list = new cl_device_id[_num_devices];
   cl_uint n;
   CL_SAFE_CALL(clGetDeviceIDs(_cl_platform,CL_DEVICE_TYPE_ALL,_num_devices,
@@ -612,7 +611,7 @@ void UCL_Device::print_all(std::ostream &out) {
 
 // Select the platform that is associated with accelerators
 // if pid < 0, select the first platform
-void UCL_Device::set_platform_accelerator(int pid) {
+int UCL_Device::set_platform_accelerator(int pid) {
   if (pid < 0) {
     int found = 0;
     for (int n=0; n<_num_platforms; n++) {
@@ -625,10 +624,11 @@ void UCL_Device::set_platform_accelerator(int pid) {
           break;
         }
       }
-      if (found) break;
+      if (found) return UCL_SUCCESS;
     }
+    return UCL_ERROR;
   } else {
-    set_platform(pid);
+    return set_platform(pid);
   }
 }
 
diff --git a/lib/gpu/geryon/ocl_timer.h b/lib/gpu/geryon/ocl_timer.h
index 66b79dcab101db3cbc31bbaa00263d5b563081f8..1f56aeb364ccc73c3b6ce22fa2644f0c9413f64b 100644
--- a/lib/gpu/geryon/ocl_timer.h
+++ b/lib/gpu/geryon/ocl_timer.h
@@ -49,8 +49,6 @@ class UCL_Timer {
   inline void clear() {
     if (_initialized) {
       CL_DESTRUCT_CALL(clReleaseCommandQueue(_cq));
-      clReleaseEvent(start_event);
-      clReleaseEvent(stop_event);
       _initialized=false;
       _total_time=0.0;
     }
@@ -107,6 +105,8 @@ class UCL_Timer {
     CL_SAFE_CALL(clGetEventProfilingInfo(start_event,
                                          CL_PROFILING_COMMAND_END,
                                          sizeof(cl_ulong), &tstart, NULL));
+    clReleaseEvent(start_event);
+    clReleaseEvent(stop_event);
     return (tend-tstart)*t_factor;
   }
 
diff --git a/lib/gpu/lal_atom.h b/lib/gpu/lal_atom.h
index f6a0b109f2143889e5cde02f546de6e017d15561..57880d7ca976c029ab7006b9c2a5035da8018cfc 100644
--- a/lib/gpu/lal_atom.h
+++ b/lib/gpu/lal_atom.h
@@ -322,10 +322,12 @@ class Atom {
 
   // Copy charges to device asynchronously
   inline void add_q_data() {
+    time_q.start();
     if (_q_avail==false) {
       q.update_device(_nall,true);
       _q_avail=true;
     }
+    time_q.stop();
   }
 
   // Cast quaternions to write buffer
@@ -347,10 +349,12 @@ class Atom {
   // Copy quaternions to device
   /** Copies nall()*4 elements **/
   inline void add_quat_data() {
+    time_quat.start();
     if (_quat_avail==false) {
       quat.update_device(_nall*4,true);
       _quat_avail=true;
     }
+    time_quat.stop();
   }
 
   /// Cast velocities and tags to write buffer
diff --git a/lib/gpu/lal_device.cpp b/lib/gpu/lal_device.cpp
index 0ea128a5b38a0b5007052e14d23cc24019eab8d4..6b4d0ab2a504e404a72af7bf35d3bc436f9fdd8a 100644
--- a/lib/gpu/lal_device.cpp
+++ b/lib/gpu/lal_device.cpp
@@ -34,8 +34,8 @@ using namespace LAMMPS_AL;
 
 template <class numtyp, class acctyp>
 DeviceT::Device() : _init_count(0), _device_init(false),
-                                  _gpu_mode(GPU_FORCE), _first_device(0),
-                                  _last_device(0), _compiled(false) {
+                    _gpu_mode(GPU_FORCE), _first_device(0),
+                    _last_device(0), _platform_id(-1), _compiled(false) {
 }
 
 template <class numtyp, class acctyp>
@@ -67,6 +67,17 @@ int DeviceT::init_device(MPI_Comm world, MPI_Comm replica, const int first_gpu,
   _particle_split=p_split;
   _cell_size=cell_size;
   _block_pair=block_pair;
+  // support selecting platform though "package device" keyword.
+  // "0:generic" will select platform 0 and tune for generic device
+  // "1:fermi" will select platform 1 and tune for Nvidia Fermi gpu
+  if (ocl_vendor) {
+    char *sep = NULL;
+    if ((sep = strstr(ocl_vendor,":"))) {
+      *sep = '\0';
+      _platform_id = atoi(ocl_vendor);
+      ocl_vendor = sep+1;
+    }
+  }
 
   // Get the rank/size within the world
   MPI_Comm_rank(_comm_world,&_world_me);
@@ -119,8 +130,16 @@ int DeviceT::init_device(MPI_Comm world, MPI_Comm replica, const int first_gpu,
 
   // Time on the device only if 1 proc per gpu
   _time_device=true;
+
+#if 0
+  // XXX: the following setting triggers a memory leak with OpenCL and MPI
+  //      setting _time_device=true for all processes doesn't seem to be a
+  //      problem with either (no segfault, no (large) memory leak.
+  //      thus keeping this disabled for now. may need to review later.
+  //      2018-07-23 <akohlmey@gmail.com>
   if (_procs_per_gpu>1)
     _time_device=false;
+#endif
 
   // Set up a per device communicator
   MPI_Comm_split(node_comm,my_gpu,0,&_comm_gpu);
@@ -135,6 +154,9 @@ int DeviceT::init_device(MPI_Comm world, MPI_Comm replica, const int first_gpu,
     return -7;
   #endif
 
+  if (gpu->set_platform_accelerator(_platform_id)!=UCL_SUCCESS)
+    return -12;
+
   if (gpu->set(my_gpu)!=UCL_SUCCESS)
     return -6;
 
@@ -191,13 +213,15 @@ int DeviceT::set_ocl_params(char *ocl_vendor) {
     _ocl_vendor_string="-DUSE_OPENCL";
     int token_count=0;
     std::string params[13];
-    char *pch = strtok(ocl_vendor,"\" ");
+    char *pch = strtok(ocl_vendor,",");
+    pch = strtok(NULL,",");
+    if (pch == NULL) return -11;
     while (pch != NULL) {
       if (token_count==13)
         return -11;
       params[token_count]=pch;
       token_count++;
-      pch = strtok(NULL,"\" ");
+      pch = strtok(NULL,",");
     }
     _ocl_vendor_string+=" -DMEM_THREADS="+params[0]+
                         " -DTHREADS_PER_ATOM="+params[1]+
@@ -656,7 +680,7 @@ int DeviceT::compile_kernels() {
   dev_program=new UCL_Program(*gpu);
   int success=dev_program->load_string(device,compile_string().c_str());
   if (success!=UCL_SUCCESS)
-    return -4;
+    return -6;
   k_zero.set_function(*dev_program,"kernel_zero");
   k_info.set_function(*dev_program,"kernel_info");
   _compiled=true;
diff --git a/lib/gpu/lal_device.h b/lib/gpu/lal_device.h
index 95e9f2a4309fa755bf10458f6c07ae12a8196191..695b0a62f9236f9f4e16119391ce05c6eafbf8e8 100644
--- a/lib/gpu/lal_device.h
+++ b/lib/gpu/lal_device.h
@@ -292,7 +292,7 @@ class Device {
   MPI_Comm _comm_world, _comm_replica, _comm_gpu;
   int _procs_per_gpu, _gpu_rank, _world_me, _world_size, _replica_me,
       _replica_size;
-  int _gpu_mode, _first_device, _last_device, _nthreads;
+  int _gpu_mode, _first_device, _last_device, _platform_id, _nthreads;
   double _particle_split;
   double _cpu_full;
   double _ptx_arch;
diff --git a/lib/gpu/lal_neighbor.cpp b/lib/gpu/lal_neighbor.cpp
index 04e08c3e9c25d07b7a637b100b1d9ed4c3c3a01a..3e128bcf57349d39399f5cf625e5f863186a3630 100644
--- a/lib/gpu/lal_neighbor.cpp
+++ b/lib/gpu/lal_neighbor.cpp
@@ -127,10 +127,10 @@ void Neighbor::alloc(bool &success) {
     dev_packed.clear();
     success=success && (dev_packed.alloc((_max_nbors+2)*_max_atoms,*dev,
                                          _packed_permissions)==UCL_SUCCESS);
-    dev_acc.clear();
-    success=success && (dev_acc.alloc(_max_atoms,*dev,
+    dev_ilist.clear();
+    success=success && (dev_ilist.alloc(_max_atoms,*dev,
                                       UCL_READ_WRITE)==UCL_SUCCESS);
-    _c_bytes+=dev_packed.row_bytes()+dev_acc.row_bytes();
+    _c_bytes+=dev_packed.row_bytes()+dev_ilist.row_bytes();
   }
   if (_max_host>0) {
     nbor_host.clear();
@@ -197,7 +197,7 @@ void Neighbor::clear() {
 
     host_packed.clear();
     host_acc.clear();
-    dev_acc.clear();
+    dev_ilist.clear();
     dev_nbor.clear();
     nbor_host.clear();
     dev_packed.clear();
@@ -281,7 +281,7 @@ void Neighbor::get_host(const int inum, int *ilist, int *numj,
   }
   UCL_D_Vec<int> acc_view;
   acc_view.view_offset(inum,dev_nbor,inum*2);
-  ucl_copy(acc_view,host_acc,true);
+  ucl_copy(acc_view,host_acc,inum*2,true);
 
   UCL_H_Vec<int> host_view;
   host_view.alloc(_max_atoms,*dev,UCL_READ_WRITE);
@@ -289,7 +289,7 @@ void Neighbor::get_host(const int inum, int *ilist, int *numj,
     int i=ilist[ii];
     host_view[i] = ii;
   }
-  ucl_copy(dev_acc,host_view,true);
+  ucl_copy(dev_ilist,host_view,true);
 
   time_nbor.stop();
 
@@ -364,7 +364,7 @@ void Neighbor::get_host3(const int inum, const int nlist, int *ilist, int *numj,
   }
   UCL_D_Vec<int> acc_view;
   acc_view.view_offset(inum,dev_nbor,inum*2);
-  ucl_copy(acc_view,host_acc,true);
+  ucl_copy(acc_view,host_acc,inum*2,true);
   time_nbor.stop();
 
   if (_use_packing==false) {
diff --git a/lib/gpu/lal_neighbor.h b/lib/gpu/lal_neighbor.h
index 05168834c6034a3cc336ef429242d441a63c9945..996deaff6d12bbbfa6789ac12dae0910b7f7f699 100644
--- a/lib/gpu/lal_neighbor.h
+++ b/lib/gpu/lal_neighbor.h
@@ -110,7 +110,7 @@ class Neighbor {
       }
       if (_time_device) {
         time_nbor.add_to_total();
-        time_kernel.add_to_total();
+        if (_use_packing==false) time_kernel.add_to_total();
         if (_gpu_nbor==2) {
           time_hybrid1.add_to_total();
           time_hybrid2.add_to_total();
@@ -200,7 +200,7 @@ class Neighbor {
   /// Host storage for nbor counts (row 1) & accumulated neighbor counts (row2)
   UCL_H_Vec<int> host_acc;
   /// Device storage for accessing atom indices from the neighbor list (3-body)
-  UCL_D_Vec<int> dev_acc;
+  UCL_D_Vec<int> dev_ilist;
 
   // ----------------- Data for GPU Neighbor Calculation ---------------
 
diff --git a/lib/gpu/lal_sw.cpp b/lib/gpu/lal_sw.cpp
index 24984e48785d665c63ad9cae54dc45812846a5f2..46b6382a6097aeaab518a2cc509b6eeb5d92e41b 100644
--- a/lib/gpu/lal_sw.cpp
+++ b/lib/gpu/lal_sw.cpp
@@ -243,7 +243,7 @@ void SWT::loop(const bool _eflag, const bool _vflag, const int evatom) {
     this->k_three_end_vatom.run(&this->atom->x, &sw1, &sw2, &sw3,
                           &map, &elem2param, &_nelements,
                           &this->nbor->dev_nbor, &this->_nbor_data->begin(),
-                          &this->nbor->dev_acc, &this->dev_short_nbor,
+                          &this->nbor->dev_ilist, &this->dev_short_nbor,
                           &end_ans->force, &end_ans->engv, &eflag, &vflag, &ainum,
                           &nbor_pitch, &this->_threads_per_atom, &this->_gpu_nbor);
 
@@ -252,7 +252,7 @@ void SWT::loop(const bool _eflag, const bool _vflag, const int evatom) {
     this->k_three_end.run(&this->atom->x, &sw1, &sw2, &sw3,
                           &map, &elem2param, &_nelements,
                           &this->nbor->dev_nbor, &this->_nbor_data->begin(),
-                          &this->nbor->dev_acc, &this->dev_short_nbor,
+                          &this->nbor->dev_ilist, &this->dev_short_nbor,
                           &end_ans->force, &end_ans->engv, &eflag, &vflag, &ainum,
                           &nbor_pitch, &this->_threads_per_atom, &this->_gpu_nbor);
 
diff --git a/lib/gpu/lal_sw.cu b/lib/gpu/lal_sw.cu
index 517de70691cd735cac9c9dab5cc849a257f5d373..3b6de5a683d603e74f53b8c2364942fd0f83f2cf 100644
--- a/lib/gpu/lal_sw.cu
+++ b/lib/gpu/lal_sw.cu
@@ -544,7 +544,7 @@ __kernel void k_sw_three_end(const __global numtyp4 *restrict x_,
                              const int nelements,
                              const __global int * dev_nbor,
                              const __global int * dev_packed,
-                             const __global int * dev_acc,
+                             const __global int * dev_ilist,
                              const __global int * dev_short_nbor,
                              __global acctyp4 *restrict ans,
                              __global acctyp *restrict engv,
@@ -614,13 +614,13 @@ __kernel void k_sw_three_end(const __global numtyp4 *restrict x_,
       int nbor_k,numk;
       if (dev_nbor==dev_packed) {
         if (gpu_nbor) nbor_k=j+nbor_pitch;
-        else nbor_k=dev_acc[j]+nbor_pitch;
+        else nbor_k=dev_ilist[j]+nbor_pitch;
         numk=dev_nbor[nbor_k];
         nbor_k+=nbor_pitch+fast_mul(j,t_per_atom-1);
         k_end=nbor_k+fast_mul(numk/t_per_atom,n_stride)+(numk & (t_per_atom-1));
         nbor_k+=offset_k;
       } else {
-        nbor_k=dev_acc[j]+nbor_pitch;
+        nbor_k=dev_ilist[j]+nbor_pitch;
         numk=dev_nbor[nbor_k];
         nbor_k+=nbor_pitch;
         nbor_k=dev_nbor[nbor_k];
@@ -698,7 +698,7 @@ __kernel void k_sw_three_end_vatom(const __global numtyp4 *restrict x_,
                              const int nelements,
                              const __global int * dev_nbor,
                              const __global int * dev_packed,
-                             const __global int * dev_acc,
+                             const __global int * dev_ilist,
                              const __global int * dev_short_nbor,
                              __global acctyp4 *restrict ans,
                              __global acctyp *restrict engv,
@@ -768,13 +768,13 @@ __kernel void k_sw_three_end_vatom(const __global numtyp4 *restrict x_,
       int nbor_k,numk;
       if (dev_nbor==dev_packed) {
         if (gpu_nbor) nbor_k=j+nbor_pitch;
-        else nbor_k=dev_acc[j]+nbor_pitch;
+        else nbor_k=dev_ilist[j]+nbor_pitch;
         numk=dev_nbor[nbor_k];
         nbor_k+=nbor_pitch+fast_mul(j,t_per_atom-1);
         k_end=nbor_k+fast_mul(numk/t_per_atom,n_stride)+(numk & (t_per_atom-1));
         nbor_k+=offset_k;
       } else {
-        nbor_k=dev_acc[j]+nbor_pitch;
+        nbor_k=dev_ilist[j]+nbor_pitch;
         numk=dev_nbor[nbor_k];
         nbor_k+=nbor_pitch;
         nbor_k=dev_nbor[nbor_k];
diff --git a/lib/gpu/lal_tersoff.cpp b/lib/gpu/lal_tersoff.cpp
index a63d286d9c16a9120ee9e300f16d9fda4e5ecdfc..ef55b98a2dba21347cc9830858f9663f0ff21b31 100644
--- a/lib/gpu/lal_tersoff.cpp
+++ b/lib/gpu/lal_tersoff.cpp
@@ -272,7 +272,7 @@ void TersoffT::loop(const bool _eflag, const bool _vflag, const int evatom) {
                    &map, &elem2param, &_nelements, &_nparams, &_zetaij,
                    &this->nbor->dev_nbor, &this->_nbor_data->begin(),
                    &this->dev_short_nbor,
-                   &_eflag, &this->_ainum, &nbor_pitch, &this->_threads_per_atom);
+                   &eflag, &this->_ainum, &nbor_pitch, &this->_threads_per_atom);
 
   ainum=this->ans->inum();
   nbor_pitch=this->nbor->nbor_pitch();
@@ -311,7 +311,7 @@ void TersoffT::loop(const bool _eflag, const bool _vflag, const int evatom) {
     this->k_three_end_vatom.run(&this->atom->x, &ts1, &ts2, &ts4, &cutsq,
                           &map, &elem2param, &_nelements, &_nparams, &_zetaij,
                           &this->nbor->dev_nbor, &this->_nbor_data->begin(),
-                          &this->nbor->dev_acc, &this->dev_short_nbor,
+                          &this->nbor->dev_ilist, &this->dev_short_nbor,
                           &end_ans->force, &end_ans->engv, &eflag, &vflag, &ainum,
                           &nbor_pitch, &this->_threads_per_atom, &this->_gpu_nbor);
 
@@ -320,7 +320,7 @@ void TersoffT::loop(const bool _eflag, const bool _vflag, const int evatom) {
     this->k_three_end.run(&this->atom->x, &ts1, &ts2, &ts4, &cutsq,
                           &map, &elem2param, &_nelements, &_nparams, &_zetaij,
                           &this->nbor->dev_nbor, &this->_nbor_data->begin(),
-                          &this->nbor->dev_acc, &this->dev_short_nbor,
+                          &this->nbor->dev_ilist, &this->dev_short_nbor,
                           &end_ans->force, &end_ans->engv, &eflag, &vflag, &ainum,
                           &nbor_pitch, &this->_threads_per_atom, &this->_gpu_nbor);
   }
diff --git a/lib/gpu/lal_tersoff.cu b/lib/gpu/lal_tersoff.cu
index cec0ccc44341c10f9678e57b8de628d169980262..836f05660d7b066dcaf7398ed11e10e96eec7b07 100644
--- a/lib/gpu/lal_tersoff.cu
+++ b/lib/gpu/lal_tersoff.cu
@@ -696,7 +696,7 @@ __kernel void k_tersoff_three_end(const __global numtyp4 *restrict x_,
                                   const __global acctyp4 *restrict zetaij,
                                   const __global int * dev_nbor,
                                   const __global int * dev_packed,
-                                  const __global int * dev_acc,
+                                  const __global int * dev_ilist,
                                   const __global int * dev_short_nbor,
                                   __global acctyp4 *restrict ans,
                                   __global acctyp *restrict engv,
@@ -777,13 +777,13 @@ __kernel void k_tersoff_three_end(const __global numtyp4 *restrict x_,
       int nbor_k,numk;
       if (dev_nbor==dev_packed) {
         if (gpu_nbor) nbor_k=j+nbor_pitch;
-        else nbor_k=dev_acc[j]+nbor_pitch;
+        else nbor_k=dev_ilist[j]+nbor_pitch;
         numk=dev_nbor[nbor_k];
         nbor_k+=nbor_pitch+fast_mul(j,t_per_atom-1);
         k_end=nbor_k+fast_mul(numk/t_per_atom,n_stride)+(numk & (t_per_atom-1));
         nbor_k+=offset_k;
       } else {
-        nbor_k=dev_acc[j]+nbor_pitch;
+        nbor_k=dev_ilist[j]+nbor_pitch;
         numk=dev_nbor[nbor_k];
         nbor_k+=nbor_pitch;
         nbor_k=dev_nbor[nbor_k];
@@ -941,7 +941,7 @@ __kernel void k_tersoff_three_end_vatom(const __global numtyp4 *restrict x_,
                                         const __global acctyp4 *restrict zetaij,
                                         const __global int * dev_nbor,
                                         const __global int * dev_packed,
-                                        const __global int * dev_acc,
+                                        const __global int * dev_ilist,
                                         const __global int * dev_short_nbor,
                                         __global acctyp4 *restrict ans,
                                         __global acctyp *restrict engv,
@@ -1022,13 +1022,13 @@ __kernel void k_tersoff_three_end_vatom(const __global numtyp4 *restrict x_,
       int nbor_k,numk;
       if (dev_nbor==dev_packed) {
         if (gpu_nbor) nbor_k=j+nbor_pitch;
-        else nbor_k=dev_acc[j]+nbor_pitch;
+        else nbor_k=dev_ilist[j]+nbor_pitch;
         numk=dev_nbor[nbor_k];
         nbor_k+=nbor_pitch+fast_mul(j,t_per_atom-1);
         k_end=nbor_k+fast_mul(numk/t_per_atom,n_stride)+(numk & (t_per_atom-1));
         nbor_k+=offset_k;
       } else {
-        nbor_k=dev_acc[j]+nbor_pitch;
+        nbor_k=dev_ilist[j]+nbor_pitch;
         numk=dev_nbor[nbor_k];
         nbor_k+=nbor_pitch;
         nbor_k=dev_nbor[nbor_k];
diff --git a/lib/gpu/lal_tersoff_mod.cpp b/lib/gpu/lal_tersoff_mod.cpp
index c37c07f1a1234d1945cfefdac45d42f9be446458..3cbb488cab878c497c0f0cf7eede5f9c5ce9663c 100644
--- a/lib/gpu/lal_tersoff_mod.cpp
+++ b/lib/gpu/lal_tersoff_mod.cpp
@@ -272,7 +272,7 @@ void TersoffMT::loop(const bool _eflag, const bool _vflag, const int evatom) {
                    &map, &elem2param, &_nelements, &_nparams, &_zetaij,
                    &this->nbor->dev_nbor, &this->_nbor_data->begin(),
                    &this->dev_short_nbor,
-                   &_eflag, &this->_ainum, &nbor_pitch, &this->_threads_per_atom);
+                   &eflag, &this->_ainum, &nbor_pitch, &this->_threads_per_atom);
 
   ainum=this->ans->inum();
   nbor_pitch=this->nbor->nbor_pitch();
@@ -311,7 +311,7 @@ void TersoffMT::loop(const bool _eflag, const bool _vflag, const int evatom) {
     this->k_three_end_vatom.run(&this->atom->x, &ts1, &ts2, &ts4, &ts5, &cutsq,
                           &map, &elem2param, &_nelements, &_nparams, &_zetaij,
                           &this->nbor->dev_nbor, &this->_nbor_data->begin(),
-                          &this->nbor->dev_acc, &this->dev_short_nbor,
+                          &this->nbor->dev_ilist, &this->dev_short_nbor,
                           &end_ans->force, &end_ans->engv, &eflag, &vflag, &ainum,
                           &nbor_pitch, &this->_threads_per_atom, &this->_gpu_nbor);
 
@@ -320,7 +320,7 @@ void TersoffMT::loop(const bool _eflag, const bool _vflag, const int evatom) {
     this->k_three_end.run(&this->atom->x, &ts1, &ts2, &ts4, &ts5, &cutsq,
                           &map, &elem2param, &_nelements, &_nparams, &_zetaij,
                           &this->nbor->dev_nbor, &this->_nbor_data->begin(),
-                          &this->nbor->dev_acc, &this->dev_short_nbor,
+                          &this->nbor->dev_ilist, &this->dev_short_nbor,
                           &end_ans->force, &end_ans->engv, &eflag, &vflag, &ainum,
                           &nbor_pitch, &this->_threads_per_atom, &this->_gpu_nbor);
   }
diff --git a/lib/gpu/lal_tersoff_mod.cu b/lib/gpu/lal_tersoff_mod.cu
index 576359b5146246d74078b0deff98a700bbdcb533..dfb94c41451c4a553a244e14c2aa05710cf1ebe6 100644
--- a/lib/gpu/lal_tersoff_mod.cu
+++ b/lib/gpu/lal_tersoff_mod.cu
@@ -272,7 +272,7 @@ __kernel void k_tersoff_mod_zeta(const __global numtyp4 *restrict x_,
 
   if (ii<inum) {
     int nbor_j, nbor_end, i, numj;
-    const int* nbor_mem=dev_packed;
+    const __global int* nbor_mem=dev_packed;
     int offset_j=offset/t_per_atom;
     nbor_info(dev_nbor,dev_packed,nbor_pitch,t_per_atom,ii,offset_j,i,numj,
               n_stride,nbor_end,nbor_j);
@@ -432,7 +432,7 @@ __kernel void k_tersoff_mod_repulsive(const __global numtyp4 *restrict x_,
 
   if (ii<inum) {
     int nbor, nbor_end, i, numj;
-    const int* nbor_mem=dev_packed;
+    const __global int* nbor_mem=dev_packed;
     nbor_info(dev_nbor,dev_packed,nbor_pitch,t_per_atom,ii,offset,i,numj,
               n_stride,nbor_end,nbor);
 
@@ -547,7 +547,7 @@ __kernel void k_tersoff_mod_three_center(const __global numtyp4 *restrict x_,
 
   if (ii<inum) {
     int i, numj, nbor_j, nbor_end;
-    const int* nbor_mem=dev_packed;
+    const __global int* nbor_mem=dev_packed;
     int offset_j=offset/t_per_atom;
     nbor_info(dev_nbor,dev_packed,nbor_pitch,t_per_atom,ii,offset_j,i,numj,
               n_stride,nbor_end,nbor_j);
@@ -702,7 +702,7 @@ __kernel void k_tersoff_mod_three_end(const __global numtyp4 *restrict x_,
                                   const __global acctyp4 *restrict zetaij,
                                   const __global int * dev_nbor,
                                   const __global int * dev_packed,
-                                  const __global int * dev_acc,
+                                  const __global int * dev_ilist,
                                   const __global int * dev_short_nbor,
                                   __global acctyp4 *restrict ans,
                                   __global acctyp *restrict engv,
@@ -740,7 +740,7 @@ __kernel void k_tersoff_mod_three_end(const __global numtyp4 *restrict x_,
 
   if (ii<inum) {
     int i, numj, nbor_j, nbor_end, k_end;
-    const int* nbor_mem=dev_packed;
+    const __global int* nbor_mem=dev_packed;
     int offset_j=offset/t_per_atom;
     nbor_info(dev_nbor,dev_packed,nbor_pitch,t_per_atom,ii,offset_j,i,numj,
               n_stride,nbor_end,nbor_j);
@@ -785,13 +785,13 @@ __kernel void k_tersoff_mod_three_end(const __global numtyp4 *restrict x_,
       int nbor_k,numk;
       if (dev_nbor==dev_packed) {
         if (gpu_nbor) nbor_k=j+nbor_pitch;
-        else nbor_k=dev_acc[j]+nbor_pitch;
+        else nbor_k=dev_ilist[j]+nbor_pitch;
         numk=dev_nbor[nbor_k];
         nbor_k+=nbor_pitch+fast_mul(j,t_per_atom-1);
         k_end=nbor_k+fast_mul(numk/t_per_atom,n_stride)+(numk & (t_per_atom-1));
         nbor_k+=offset_k;
       } else {
-        nbor_k=dev_acc[j]+nbor_pitch;
+        nbor_k=dev_ilist[j]+nbor_pitch;
         numk=dev_nbor[nbor_k];
         nbor_k+=nbor_pitch;
         nbor_k=dev_nbor[nbor_k];
@@ -956,7 +956,7 @@ __kernel void k_tersoff_mod_three_end_vatom(const __global numtyp4 *restrict x_,
                                         const __global acctyp4 *restrict zetaij,
                                         const __global int * dev_nbor,
                                         const __global int * dev_packed,
-                                        const __global int * dev_acc,
+                                        const __global int * dev_ilist,
                                         const __global int * dev_short_nbor,
                                         __global acctyp4 *restrict ans,
                                         __global acctyp *restrict engv,
@@ -994,7 +994,7 @@ __kernel void k_tersoff_mod_three_end_vatom(const __global numtyp4 *restrict x_,
 
   if (ii<inum) {
     int i, numj, nbor_j, nbor_end, k_end;
-    const int* nbor_mem = dev_packed;
+    const __global int* nbor_mem = dev_packed;
     int offset_j=offset/t_per_atom;
     nbor_info(dev_nbor,dev_packed,nbor_pitch,t_per_atom,ii,offset_j,i,numj,
               n_stride,nbor_end,nbor_j);
@@ -1039,13 +1039,13 @@ __kernel void k_tersoff_mod_three_end_vatom(const __global numtyp4 *restrict x_,
       int nbor_k,numk;
       if (dev_nbor==dev_packed) {
         if (gpu_nbor) nbor_k=j+nbor_pitch;
-        else nbor_k=dev_acc[j]+nbor_pitch;
+        else nbor_k=dev_ilist[j]+nbor_pitch;
         numk=dev_nbor[nbor_k];
         nbor_k+=nbor_pitch+fast_mul(j,t_per_atom-1);
         k_end=nbor_k+fast_mul(numk/t_per_atom,n_stride)+(numk & (t_per_atom-1));
         nbor_k+=offset_k;
       } else {
-        nbor_k=dev_acc[j]+nbor_pitch;
+        nbor_k=dev_ilist[j]+nbor_pitch;
         numk=dev_nbor[nbor_k];
         nbor_k+=nbor_pitch;
         nbor_k=dev_nbor[nbor_k];
diff --git a/lib/gpu/lal_tersoff_zbl.cpp b/lib/gpu/lal_tersoff_zbl.cpp
index 341f663030f6330ec0ffbfd97526a24e5e59e87a..ebf67285eda47914ed06f3d0ec4abe3d4d4084aa 100644
--- a/lib/gpu/lal_tersoff_zbl.cpp
+++ b/lib/gpu/lal_tersoff_zbl.cpp
@@ -297,7 +297,7 @@ void TersoffZT::loop(const bool _eflag, const bool _vflag, const int evatom) {
                    &map, &elem2param, &_nelements, &_nparams, &_zetaij,
                    &this->nbor->dev_nbor, &this->_nbor_data->begin(),
                    &this->dev_short_nbor,
-                   &_eflag, &this->_ainum, &nbor_pitch, &this->_threads_per_atom);
+                   &eflag, &this->_ainum, &nbor_pitch, &this->_threads_per_atom);
 
   ainum=this->ans->inum();
   nbor_pitch=this->nbor->nbor_pitch();
@@ -337,7 +337,7 @@ void TersoffZT::loop(const bool _eflag, const bool _vflag, const int evatom) {
     this->k_three_end_vatom.run(&this->atom->x, &ts1, &ts2, &ts4, &cutsq,
                           &map, &elem2param, &_nelements, &_nparams, &_zetaij,
                           &this->nbor->dev_nbor, &this->_nbor_data->begin(),
-                          &this->nbor->dev_acc, &this->dev_short_nbor,
+                          &this->nbor->dev_ilist, &this->dev_short_nbor,
                           &end_ans->force, &end_ans->engv, &eflag, &vflag, &ainum,
                           &nbor_pitch, &this->_threads_per_atom, &this->_gpu_nbor);
 
@@ -346,7 +346,7 @@ void TersoffZT::loop(const bool _eflag, const bool _vflag, const int evatom) {
     this->k_three_end.run(&this->atom->x, &ts1, &ts2, &ts4, &cutsq,
                           &map, &elem2param, &_nelements, &_nparams, &_zetaij,
                           &this->nbor->dev_nbor, &this->_nbor_data->begin(),
-                          &this->nbor->dev_acc, &this->dev_short_nbor,
+                          &this->nbor->dev_ilist, &this->dev_short_nbor,
                           &end_ans->force, &end_ans->engv, &eflag, &vflag, &ainum,
                           &nbor_pitch, &this->_threads_per_atom, &this->_gpu_nbor);
   }
diff --git a/lib/gpu/lal_tersoff_zbl.cu b/lib/gpu/lal_tersoff_zbl.cu
index e8bb017f5901a9184b80403d8814aab50794500c..73ff51c70404cfea89fa7c9195e26ac12b6fbbcd 100644
--- a/lib/gpu/lal_tersoff_zbl.cu
+++ b/lib/gpu/lal_tersoff_zbl.cu
@@ -278,7 +278,7 @@ __kernel void k_tersoff_zbl_zeta(const __global numtyp4 *restrict x_,
 
   if (ii<inum) {
     int nbor_j, nbor_end, i, numj;
-    const int* nbor_mem=dev_packed;
+    const __global int* nbor_mem=dev_packed;
     int offset_j=offset/t_per_atom;
     nbor_info(dev_nbor,dev_packed,nbor_pitch,t_per_atom,ii,offset_j,i,numj,
               n_stride,nbor_end,nbor_j);
@@ -445,7 +445,7 @@ __kernel void k_tersoff_zbl_repulsive(const __global numtyp4 *restrict x_,
 
   if (ii<inum) {
     int nbor, nbor_end, i, numj;
-    const int* nbor_mem=dev_packed;
+    const __global int* nbor_mem=dev_packed;
     nbor_info(dev_nbor,dev_packed,nbor_pitch,t_per_atom,ii,offset,i,numj,
               n_stride,nbor_end,nbor);
 
@@ -563,7 +563,7 @@ __kernel void k_tersoff_zbl_three_center(const __global numtyp4 *restrict x_,
 
   if (ii<inum) {
     int i, numj, nbor_j, nbor_end;
-    const int* nbor_mem=dev_packed;
+    const __global int* nbor_mem=dev_packed;
     int offset_j=offset/t_per_atom;
     nbor_info(dev_nbor,dev_packed,nbor_pitch,t_per_atom,ii,offset_j,i,numj,
               n_stride,nbor_end,nbor_j);
@@ -714,7 +714,7 @@ __kernel void k_tersoff_zbl_three_end(const __global numtyp4 *restrict x_,
                                   const __global acctyp4 *restrict zetaij,
                                   const __global int * dev_nbor,
                                   const __global int * dev_packed,
-                                  const __global int * dev_acc,
+                                  const __global int * dev_ilist,
                                   const __global int * dev_short_nbor,
                                   __global acctyp4 *restrict ans,
                                   __global acctyp *restrict engv,
@@ -750,7 +750,7 @@ __kernel void k_tersoff_zbl_three_end(const __global numtyp4 *restrict x_,
 
   if (ii<inum) {
     int i, numj, nbor_j, nbor_end, k_end;
-    const int* nbor_mem=dev_packed;
+    const __global int* nbor_mem=dev_packed;
     int offset_j=offset/t_per_atom;
     nbor_info(dev_nbor,dev_packed,nbor_pitch,t_per_atom,ii,offset_j,i,numj,
               n_stride,nbor_end,nbor_j);
@@ -795,13 +795,13 @@ __kernel void k_tersoff_zbl_three_end(const __global numtyp4 *restrict x_,
       int nbor_k,numk;
       if (dev_nbor==dev_packed) {
         if (gpu_nbor) nbor_k=j+nbor_pitch;
-        else nbor_k=dev_acc[j]+nbor_pitch;
+        else nbor_k=dev_ilist[j]+nbor_pitch;
         numk=dev_nbor[nbor_k];
         nbor_k+=nbor_pitch+fast_mul(j,t_per_atom-1);
         k_end=nbor_k+fast_mul(numk/t_per_atom,n_stride)+(numk & (t_per_atom-1));
         nbor_k+=offset_k;
       } else {
-        nbor_k=dev_acc[j]+nbor_pitch;
+        nbor_k=dev_ilist[j]+nbor_pitch;
         numk=dev_nbor[nbor_k];
         nbor_k+=nbor_pitch;
         nbor_k=dev_nbor[nbor_k];
@@ -959,7 +959,7 @@ __kernel void k_tersoff_zbl_three_end_vatom(const __global numtyp4 *restrict x_,
                                         const __global acctyp4 *restrict zetaij,
                                         const __global int * dev_nbor,
                                         const __global int * dev_packed,
-                                        const __global int * dev_acc,
+                                        const __global int * dev_ilist,
                                         const __global int * dev_short_nbor,
                                         __global acctyp4 *restrict ans,
                                         __global acctyp *restrict engv,
@@ -995,7 +995,7 @@ __kernel void k_tersoff_zbl_three_end_vatom(const __global numtyp4 *restrict x_,
 
   if (ii<inum) {
     int i, numj, nbor_j, nbor_end, k_end;
-    const int* nbor_mem = dev_packed;
+    const __global int* nbor_mem = dev_packed;
     int offset_j=offset/t_per_atom;
     nbor_info(dev_nbor,dev_packed,nbor_pitch,t_per_atom,ii,offset_j,i,numj,
               n_stride,nbor_end,nbor_j);
@@ -1040,13 +1040,13 @@ __kernel void k_tersoff_zbl_three_end_vatom(const __global numtyp4 *restrict x_,
       int nbor_k,numk;
       if (dev_nbor==dev_packed) {
         if (gpu_nbor) nbor_k=j+nbor_pitch;
-        else nbor_k=dev_acc[j]+nbor_pitch;
+        else nbor_k=dev_ilist[j]+nbor_pitch;
         numk=dev_nbor[nbor_k];
         nbor_k+=nbor_pitch+fast_mul(j,t_per_atom-1);
         k_end=nbor_k+fast_mul(numk/t_per_atom,n_stride)+(numk & (t_per_atom-1));
         nbor_k+=offset_k;
       } else {
-        nbor_k=dev_acc[j]+nbor_pitch;
+        nbor_k=dev_ilist[j]+nbor_pitch;
         numk=dev_nbor[nbor_k];
         nbor_k+=nbor_pitch;
         nbor_k=dev_nbor[nbor_k];
diff --git a/lib/gpu/lal_vashishta.cpp b/lib/gpu/lal_vashishta.cpp
index d03ac992bd468ea0677a6b537468016f56b7b3e0..5a01a9bd46f185938710ab65cfd75761b3f5fb1e 100644
--- a/lib/gpu/lal_vashishta.cpp
+++ b/lib/gpu/lal_vashishta.cpp
@@ -278,7 +278,7 @@ void VashishtaT::loop(const bool _eflag, const bool _vflag, const int evatom) {
     this->k_three_end_vatom.run(&this->atom->x, &param1, &param2, &param3, &param4, &param5,
                           &map, &elem2param, &_nelements,
                           &this->nbor->dev_nbor, &this->_nbor_data->begin(),
-                          &this->nbor->dev_acc, &this->dev_short_nbor,
+                          &this->nbor->dev_ilist, &this->dev_short_nbor,
                           &end_ans->force, &end_ans->engv, &eflag, &vflag, &ainum,
                           &nbor_pitch, &this->_threads_per_atom, &this->_gpu_nbor);
   } else {
@@ -286,7 +286,7 @@ void VashishtaT::loop(const bool _eflag, const bool _vflag, const int evatom) {
     this->k_three_end.run(&this->atom->x, &param1, &param2, &param3, &param4, &param5,
                           &map, &elem2param, &_nelements,
                           &this->nbor->dev_nbor, &this->_nbor_data->begin(),
-                          &this->nbor->dev_acc, &this->dev_short_nbor,
+                          &this->nbor->dev_ilist, &this->dev_short_nbor,
                           &end_ans->force, &end_ans->engv, &eflag, &vflag, &ainum,
                           &nbor_pitch, &this->_threads_per_atom, &this->_gpu_nbor);
   }
diff --git a/lib/gpu/lal_vashishta.cu b/lib/gpu/lal_vashishta.cu
index d2e8bb1496abfd7355f88730cbb0d69c1c22339d..0da46c3b534cc29cba600851db0dda05a2cf38da 100644
--- a/lib/gpu/lal_vashishta.cu
+++ b/lib/gpu/lal_vashishta.cu
@@ -554,7 +554,7 @@ __kernel void k_vashishta_three_end(const __global numtyp4 *restrict x_,
                              const int nelements,
                              const __global int * dev_nbor,
                              const __global int * dev_packed,
-                             const __global int * dev_acc,
+                             const __global int * dev_ilist,
                              const __global int * dev_short_nbor,
                              __global acctyp4 *restrict ans,
                              __global acctyp *restrict engv,
@@ -623,13 +623,13 @@ __kernel void k_vashishta_three_end(const __global numtyp4 *restrict x_,
       int nbor_k,numk;
       if (dev_nbor==dev_packed) {
         if (gpu_nbor) nbor_k=j+nbor_pitch;
-        else nbor_k=dev_acc[j]+nbor_pitch;
+        else nbor_k=dev_ilist[j]+nbor_pitch;
         numk=dev_nbor[nbor_k];
         nbor_k+=nbor_pitch+fast_mul(j,t_per_atom-1);
         k_end=nbor_k+fast_mul(numk/t_per_atom,n_stride)+(numk & (t_per_atom-1));
         nbor_k+=offset_k;
       } else {
-        nbor_k=dev_acc[j]+nbor_pitch;
+        nbor_k=dev_ilist[j]+nbor_pitch;
         numk=dev_nbor[nbor_k];
         nbor_k+=nbor_pitch;
         nbor_k=dev_nbor[nbor_k];
@@ -709,7 +709,7 @@ __kernel void k_vashishta_three_end_vatom(const __global numtyp4 *restrict x_,
                              const int nelements,
                              const __global int * dev_nbor,
                              const __global int * dev_packed,
-                             const __global int * dev_acc,
+                             const __global int * dev_ilist,
                              const __global int * dev_short_nbor,
                              __global acctyp4 *restrict ans,
                              __global acctyp *restrict engv,
@@ -778,13 +778,13 @@ __kernel void k_vashishta_three_end_vatom(const __global numtyp4 *restrict x_,
       int nbor_k,numk;
       if (dev_nbor==dev_packed) {
         if (gpu_nbor) nbor_k=j+nbor_pitch;
-        else nbor_k=dev_acc[j]+nbor_pitch;
+        else nbor_k=dev_ilist[j]+nbor_pitch;
         numk=dev_nbor[nbor_k];
         nbor_k+=nbor_pitch+fast_mul(j,t_per_atom-1);
         k_end=nbor_k+fast_mul(numk/t_per_atom,n_stride)+(numk & (t_per_atom-1));
         nbor_k+=offset_k;
       } else {
-        nbor_k=dev_acc[j]+nbor_pitch;
+        nbor_k=dev_ilist[j]+nbor_pitch;
         numk=dev_nbor[nbor_k];
         nbor_k+=nbor_pitch;
         nbor_k=dev_nbor[nbor_k];
diff --git a/lib/latte/Install.py b/lib/latte/Install.py
index e1ed9d4eaaf4c95c2d3f09b91dee4f9db4441702..3b211858dd15b5336c0d962e7bf9bcbe88edcf08 100644
--- a/lib/latte/Install.py
+++ b/lib/latte/Install.py
@@ -40,7 +40,7 @@ version = '1.2.1'
 checksums = { \
         '1.1.0' : '533635721ee222d0ed2925a18fb5b294', \
         '1.2.0' : '68bf0db879da5e068a71281020239ae7', \
-        '1.2.1' : 'bed76e7e76c545c36dd848a8f1fd35eb' \
+        '1.2.1' : '85ac414fdada2d04619c8f936344df14', \
         }
 
 # print error message or help
diff --git a/src/BODY/body_rounded_polygon.cpp b/src/BODY/body_rounded_polygon.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1e232f0f3f59fbbdab6bf470920bcf2a70ff2036
--- /dev/null
+++ b/src/BODY/body_rounded_polygon.cpp
@@ -0,0 +1,452 @@
+/* ----------------------------------------------------------------------
+   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: Trung Dac Nguyen (ndactrung@gmail.com)
+------------------------------------------------------------------------- */
+
+#include <cstdlib>
+#include "body_rounded_polygon.h"
+#include "atom_vec_body.h"
+#include "atom.h"
+#include "force.h"
+#include "domain.h"
+#include "math_extra.h"
+#include "memory.h"
+#include "error.h"
+
+using namespace LAMMPS_NS;
+
+#define EPSILON 1.0e-7
+enum{SPHERE,LINE};           // also in DumpImage
+
+/* ---------------------------------------------------------------------- */
+
+BodyRoundedPolygon::BodyRoundedPolygon(LAMMPS *lmp, int narg, char **arg) :
+  Body(lmp, narg, arg)
+{
+  if (narg != 3) error->all(FLERR,"Invalid body rounded/polygon command");
+
+  if (domain->dimension != 2)
+    error->all(FLERR,"Atom_style body rounded/polygon "
+               "can only be used in 2d simulations");
+
+  // nmin and nmax are minimum and maximum number of vertices
+
+  int nmin = force->inumeric(FLERR,arg[1]);
+  int nmax = force->inumeric(FLERR,arg[2]);
+  if (nmin <= 0 || nmin > nmax)
+    error->all(FLERR,"Invalid body rounded/polygon command");
+
+  size_forward = 0;
+
+  // 1 integer for number of vertices,
+  // 3*nmax doubles for vertex coordinates + 2*nmax doubles for edge ends
+  // 1 double for the enclosing radius
+  // 1 double for the rounded radius
+
+  size_border = 1 + 3*nmax + 2*nmax + 1 + 1;
+
+  // NOTE: need to set appropriate nnbin param for dcp
+
+  icp = new MyPoolChunk<int>(1,1);
+  dcp = new MyPoolChunk<double>(3*nmin+2*nmin+1+1,3*nmax+2*nmax+1+1);
+
+  memory->create(imflag,nmax,"body/rounded/polygon:imflag");
+  memory->create(imdata,nmax,7,"body/nparticle:imdata");
+}
+
+/* ---------------------------------------------------------------------- */
+
+BodyRoundedPolygon::~BodyRoundedPolygon()
+{
+  delete icp;
+  delete dcp;
+  memory->destroy(imflag);
+  memory->destroy(imdata);
+}
+
+/* ---------------------------------------------------------------------- */
+
+int BodyRoundedPolygon::nsub(AtomVecBody::Bonus *bonus)
+{
+  return bonus->ivalue[0];
+}
+
+/* ---------------------------------------------------------------------- */
+
+double *BodyRoundedPolygon::coords(AtomVecBody::Bonus *bonus)
+{
+  return bonus->dvalue;
+}
+
+/* ---------------------------------------------------------------------- */
+
+int BodyRoundedPolygon::nedges(AtomVecBody::Bonus *bonus)
+{
+  int nvertices = bonus->ivalue[0];
+  if (nvertices == 1) return 0;
+  else if (nvertices == 2) return 1;
+  return nvertices;
+}
+
+/* ---------------------------------------------------------------------- */
+
+double *BodyRoundedPolygon::edges(AtomVecBody::Bonus *bonus)
+{
+  return bonus->dvalue+3*nsub(bonus);
+}
+
+/* ---------------------------------------------------------------------- */
+
+double BodyRoundedPolygon::enclosing_radius(struct AtomVecBody::Bonus *bonus)
+{
+  int nvertices = bonus->ivalue[0];
+  if (nvertices == 1 || nvertices == 2)
+	return *(bonus->dvalue+3*nsub(bonus)+2);
+  return *(bonus->dvalue + 3*nsub(bonus) + 2*nsub(bonus));
+}
+
+/* ---------------------------------------------------------------------- */
+
+double BodyRoundedPolygon::rounded_radius(struct AtomVecBody::Bonus *bonus)
+{
+  int nvertices = bonus->ivalue[0];
+  if (nvertices == 1 || nvertices == 2)
+	return *(bonus->dvalue+3*nsub(bonus)+2+1);
+  return *(bonus->dvalue + 3*nsub(bonus) + 2*nsub(bonus)+1);
+}
+
+/* ---------------------------------------------------------------------- */
+
+int BodyRoundedPolygon::pack_border_body(AtomVecBody::Bonus *bonus, double *buf)
+{
+  int nsub = bonus->ivalue[0];
+  buf[0] = nsub;
+  memcpy(&buf[1],bonus->dvalue,(3*nsub+2*nsub+1+1)*sizeof(double));
+  return 1+(3*nsub+2*nsub+1+1);
+}
+
+/* ---------------------------------------------------------------------- */
+
+int BodyRoundedPolygon::unpack_border_body(AtomVecBody::Bonus *bonus,
+                                           double *buf)
+{
+  int nsub = static_cast<int> (buf[0]);
+  bonus->ivalue[0] = nsub;
+  memcpy(bonus->dvalue,&buf[1],(3*nsub+2*nsub+1+1)*sizeof(double));
+  return 1+(3*nsub+2*nsub+1+1);
+}
+
+/* ----------------------------------------------------------------------
+   populate bonus data structure with data file values
+------------------------------------------------------------------------- */
+
+void BodyRoundedPolygon::data_body(int ibonus, int ninteger, int ndouble,
+				   int *ifile, double *dfile)
+{
+  AtomVecBody::Bonus *bonus = &avec->bonus[ibonus];
+
+  // set ninteger, ndouble in bonus and allocate 2 vectors of ints, doubles
+
+  if (ninteger != 1)
+    error->one(FLERR,"Incorrect # of integer values in "
+               "Bodies section of data file");
+  int nsub = ifile[0];
+  if (nsub < 1)
+    error->one(FLERR,"Incorrect integer value in "
+               "Bodies section of data file");
+
+  // nentries = number of double entries to be read from Body section:
+  //   6 for inertia + 3*nsub for vertex coords + 1 for rounded radius
+
+  int nentries = 6 + 3*nsub + 1; 
+  if (ndouble != nentries)
+    error->one(FLERR,"Incorrect # of floating-point values in "
+             "Bodies section of data file");
+
+  bonus->ninteger = 1;
+  bonus->ivalue = icp->get(bonus->iindex);
+  bonus->ivalue[0] = nsub;
+  bonus->ndouble = 3*nsub + 2*nsub + 1 + 1;
+  bonus->dvalue = dcp->get(bonus->ndouble,bonus->dindex);
+
+  // diagonalize inertia tensor
+
+  double tensor[3][3];
+  tensor[0][0] = dfile[0];
+  tensor[1][1] = dfile[1];
+  tensor[2][2] = dfile[2];
+  tensor[0][1] = tensor[1][0] = dfile[3];
+  tensor[0][2] = tensor[2][0] = dfile[4];
+  tensor[1][2] = tensor[2][1] = dfile[5];
+
+  double *inertia = bonus->inertia;
+  double evectors[3][3];
+  int ierror = MathExtra::jacobi(tensor,inertia,evectors);
+  if (ierror) error->one(FLERR,
+                         "Insufficient Jacobi rotations for body nparticle");
+
+  // if any principal moment < scaled EPSILON, set to 0.0
+
+  double max;
+  max = MAX(inertia[0],inertia[1]);
+  max = MAX(max,inertia[2]);
+
+  if (inertia[0] < EPSILON*max) inertia[0] = 0.0;
+  if (inertia[1] < EPSILON*max) inertia[1] = 0.0;
+  if (inertia[2] < EPSILON*max) inertia[2] = 0.0;
+
+  // exyz_space = principal axes in space frame
+
+  double ex_space[3],ey_space[3],ez_space[3];
+
+  ex_space[0] = evectors[0][0];
+  ex_space[1] = evectors[1][0];
+  ex_space[2] = evectors[2][0];
+  ey_space[0] = evectors[0][1];
+  ey_space[1] = evectors[1][1];
+  ey_space[2] = evectors[2][1];
+  ez_space[0] = evectors[0][2];
+  ez_space[1] = evectors[1][2];
+  ez_space[2] = evectors[2][2];
+
+  // enforce 3 evectors as a right-handed coordinate system
+  // flip 3rd vector if needed
+
+  double cross[3];
+  MathExtra::cross3(ex_space,ey_space,cross);
+  if (MathExtra::dot3(cross,ez_space) < 0.0) MathExtra::negate3(ez_space);
+
+  // create initial quaternion
+
+  MathExtra::exyz_to_q(ex_space,ey_space,ez_space,bonus->quat);
+
+  // bonus->dvalue = the first 3*nsub elements are sub-particle displacements
+  // find the enclosing radius of the body from the maximum displacement
+
+  int i,m;
+  double delta[3], rsq, erad, rrad;
+  double erad2 = 0;
+  int j = 6;
+  int k = 0;
+  for (i = 0; i < nsub; i++) {
+    delta[0] = dfile[j];
+    delta[1] = dfile[j+1];
+    delta[2] = dfile[j+2];
+    MathExtra::transpose_matvec(ex_space,ey_space,ez_space,
+                                delta,&bonus->dvalue[k]);
+    rsq = delta[0] * delta[0] + delta[1] * delta[1] +
+      delta[2] * delta[2];
+    if (rsq > erad2) erad2 = rsq;
+    j += 3;
+    k += 3;
+  }
+
+  // .. the next 2*nsub elements are edge ends
+
+  int nedges;
+  if (nsub == 1) { // spheres
+    nedges = 0;
+    bonus->dvalue[k] = 0;
+    *(&bonus->dvalue[k]+1) = 0;
+    k += 2;
+
+    // the last element of bonus->dvalue is the rounded & enclosing radius
+
+    rrad = 0.5 * dfile[j];
+    bonus->dvalue[k] = rrad;
+    erad = rrad;
+
+    k++;
+    bonus->dvalue[k] = rrad;
+
+    atom->radius[bonus->ilocal] = erad;
+
+  } else if (nsub == 2) { // rods
+    nedges = 1;
+    for (i = 0; i < nedges; i++) {
+      bonus->dvalue[k] = 0;
+      *(&bonus->dvalue[k]+1) = 1;
+      k += 2;
+    }    
+
+    erad = sqrt(erad2);
+    bonus->dvalue[k] = erad;
+
+    // the last element of bonus->dvalue is the rounded radius
+
+    rrad = 0.5 * dfile[j];
+    k++;
+    bonus->dvalue[k] = rrad;
+
+    atom->radius[bonus->ilocal] = erad + rrad;
+
+  } else { // polygons
+    nedges = nsub;
+    for (i = 0; i < nedges; i++) {
+      bonus->dvalue[k] = i;
+      m = i+1;
+      if (m == nedges) m = 0;
+      *(&bonus->dvalue[k]+1) = m;
+      k += 2;
+    }
+
+    // the next to last element is the enclosing radius
+
+    erad = sqrt(erad2);
+    bonus->dvalue[k] = erad;
+
+    // the last element of bonus->dvalue is the rounded radius
+
+    rrad = 0.5 * dfile[j];
+    k++;
+    bonus->dvalue[k] = rrad;
+
+    atom->radius[bonus->ilocal] = erad + rrad;
+  }
+}
+
+/* ----------------------------------------------------------------------
+   return radius of body particle defined by ifile/dfile params
+   params are ordered as in data file
+   called by Molecule class which needs single body size
+------------------------------------------------------------------------- */
+
+double BodyRoundedPolygon::radius_body(int ninteger, int ndouble,
+				       int *ifile, double *dfile)
+{
+  int nsub = ifile[0];
+  if (nsub < 1)
+    error->one(FLERR,"Incorrect integer value in "
+               "Bodies section of data file");
+  if (ndouble != 6 + 3*nsub + 1)
+    error->one(FLERR,"Incorrect # of floating-point values in "
+               "Bodies section of data file");
+
+  // sub-particle coords are relative to body center at (0,0,0)
+  // offset = 6 for sub-particle coords
+
+  double onerad;
+  double maxrad = 0.0;
+  double delta[3];
+
+  int offset = 6;          
+  for (int i = 0; i < nsub; i++) {
+    delta[0] = dfile[offset];
+    delta[1] = dfile[offset+1];
+    delta[2] = dfile[offset+2];
+    offset += 3;
+    onerad = MathExtra::len3(delta);
+    maxrad = MAX(maxrad,onerad);
+  }
+  
+  // add in radius of rounded corners
+  
+  return maxrad + 0.5*dfile[offset];
+}
+
+/* ---------------------------------------------------------------------- */
+
+int BodyRoundedPolygon::noutcol()
+{
+  // the number of columns for the vertex coordinates
+
+  return 3;
+}
+
+/* ---------------------------------------------------------------------- */
+
+int BodyRoundedPolygon::noutrow(int ibonus)
+{
+  // only return the first nsub rows for the vertex coordinates
+
+  return avec->bonus[ibonus].ivalue[0];
+}
+
+/* ---------------------------------------------------------------------- */
+
+void BodyRoundedPolygon::output(int ibonus, int m, double *values)
+{
+  AtomVecBody::Bonus *bonus = &avec->bonus[ibonus];
+
+  double p[3][3];
+  MathExtra::quat_to_mat(bonus->quat,p);
+  MathExtra::matvec(p,&bonus->dvalue[3*m],values);
+
+  double *x = atom->x[bonus->ilocal];
+  values[0] += x[0];
+  values[1] += x[1];
+  values[2] += x[2];
+}
+
+/* ---------------------------------------------------------------------- */
+
+int BodyRoundedPolygon::image(int ibonus, double flag1, double flag2,
+                              int *&ivec, double **&darray)
+{
+  int j;
+  double p[3][3];
+  double *x, rrad;
+
+  AtomVecBody::Bonus *bonus = &avec->bonus[ibonus];
+  int n = bonus->ivalue[0];
+  
+  if (n == 1) {
+    for (int i = 0; i < n; i++) {
+      imflag[i] = SPHERE;
+      MathExtra::quat_to_mat(bonus->quat,p);
+      MathExtra::matvec(p,&bonus->dvalue[3*i],imdata[i]);
+
+      rrad = enclosing_radius(bonus);
+      x = atom->x[bonus->ilocal];
+      imdata[i][0] += x[0];
+      imdata[i][1] += x[1];
+      imdata[i][2] += x[2];
+      if (flag1 <= 0) imdata[i][3] = 2*rrad;
+      else imdata[i][3] = flag1;
+    }
+
+  } else {
+  
+    // first end pt of each line
+
+    for (int i = 0; i < n; i++) {
+      imflag[i] = LINE;
+      MathExtra::quat_to_mat(bonus->quat,p);
+      MathExtra::matvec(p,&bonus->dvalue[3*i],imdata[i]);
+
+      rrad = rounded_radius(bonus);
+      x = atom->x[bonus->ilocal];
+      imdata[i][0] += x[0];
+      imdata[i][1] += x[1];
+      imdata[i][2] += x[2];
+      if (flag1 <= 0) imdata[i][6] = 2*rrad;
+      else imdata[i][6] = flag1;
+    }
+
+    // second end pt of each line
+  
+    for (int i = 0; i < n; i++) {
+      j = i+1;
+      if (j == n) j = 0;
+      imdata[i][3] = imdata[j][0];
+      imdata[i][4] = imdata[j][1];
+      imdata[i][5] = imdata[j][2];
+    }
+  }
+
+  ivec = imflag;
+  darray = imdata;
+  return n;
+}
diff --git a/src/BODY/body_rounded_polygon.h b/src/BODY/body_rounded_polygon.h
new file mode 100644
index 0000000000000000000000000000000000000000..b6f45c5cf551cc35fc1ff2d817684f5250cf23f4
--- /dev/null
+++ b/src/BODY/body_rounded_polygon.h
@@ -0,0 +1,86 @@
+/* -*- 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 BODY_CLASS
+
+BodyStyle(rounded/polygon,BodyRoundedPolygon)
+
+#else
+
+#ifndef LMP_BODY_ROUNDED_POLYGON_H
+#define LMP_BODY_ROUNDED_POLYGON_H
+
+#include "body.h"
+#include "atom_vec_body.h"
+
+namespace LAMMPS_NS {
+
+class BodyRoundedPolygon : public Body {
+ public:
+  BodyRoundedPolygon(class LAMMPS *, int, char **);
+  ~BodyRoundedPolygon();
+  int nsub(struct AtomVecBody::Bonus *);
+  double *coords(struct AtomVecBody::Bonus *);
+  int nedges(struct AtomVecBody::Bonus *);
+  double *edges(struct AtomVecBody::Bonus *);
+  double enclosing_radius(struct AtomVecBody::Bonus *);
+  double rounded_radius(struct AtomVecBody::Bonus *);
+
+  int pack_border_body(struct AtomVecBody::Bonus *, double *);
+  int unpack_border_body(struct AtomVecBody::Bonus *, double *);
+  void data_body(int, int, int, int *, double *);
+  double radius_body(int, int, int *, double *);
+
+  int noutrow(int);
+  int noutcol();
+  void output(int, int, double *);
+  int image(int, double, double, int *&, double **&);
+
+ private:
+  int *imflag;
+  double **imdata;
+};
+
+}
+
+#endif
+#endif
+
+/* ERROR/WARNING messages:
+
+E: Invalid body rounded/polygon command
+
+Arguments in atom-style command are not correct.
+
+E: Invalid format in Bodies section of data file
+
+The specified number of integer or floating point values does not
+appear.
+
+E: Incorrect # of integer values in Bodies section of data file
+
+See doc page for body style.
+
+E: Incorrect integer value in Bodies section of data file
+
+See doc page for body style.
+
+E: Incorrect # of floating-point values in Bodies section of data file
+
+See doc page for body style.
+
+E: Insufficient Jacobi rotations for body nparticle
+
+Eigensolve for rigid body was not sufficiently accurate.
+
+*/
diff --git a/src/BODY/body_rounded_polyhedron.cpp b/src/BODY/body_rounded_polyhedron.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6a9b97ae2348ec344b75656afbb3d5261282e5b5
--- /dev/null
+++ b/src/BODY/body_rounded_polyhedron.cpp
@@ -0,0 +1,526 @@
+/* ----------------------------------------------------------------------
+   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: Trung Dac Nguyen (ndactrung@gmail.com)
+------------------------------------------------------------------------- */
+
+#include <cstdlib>
+#include "body_rounded_polyhedron.h"
+#include "atom_vec_body.h"
+#include "atom.h"
+#include "force.h"
+#include "domain.h"
+#include "math_extra.h"
+#include "memory.h"
+#include "error.h"
+
+using namespace LAMMPS_NS;
+
+#define EPSILON 1.0e-7
+#define MAX_FACE_SIZE 4  // maximum number of vertices per face (for now)
+
+enum{SPHERE,LINE};       // also in DumpImage
+
+/* ---------------------------------------------------------------------- */
+
+BodyRoundedPolyhedron::BodyRoundedPolyhedron(LAMMPS *lmp, int narg, char **arg) :
+  Body(lmp, narg, arg)
+{
+  if (narg != 3) error->all(FLERR,"Invalid body rounded/polygon command");
+
+  // nmin and nmax are minimum and maximum number of vertices
+
+  int nmin = force->inumeric(FLERR,arg[1]);
+  int nmax = force->inumeric(FLERR,arg[2]);
+  if (nmin <= 0 || nmin > nmax)
+    error->all(FLERR,"Invalid body rounded/polyhedron command");
+
+  size_forward = 0;
+
+  // 3 integers: 1 for no. of vertices, 1 for no. of edges, 1 for no. of faces
+  // 3*nmax doubles for vertex coordinates + 2*nmax doubles for edge ends +
+  // (MAX_FACE_SIZE+1)*nmax for faces
+  // 1 double for the enclosing radius
+  // 1 double for the rounded radius
+
+  size_border = 3 + 3*nmax + 2*nmax + MAX_FACE_SIZE*nmax + 1 + 1;
+
+  // NOTE: need to set appropriate nnbin param for dcp
+
+  icp = new MyPoolChunk<int>(1,3);
+  dcp = new MyPoolChunk<double>(3*nmin+2+1+1,
+                                3*nmax+2*nmax+MAX_FACE_SIZE*nmax+1+1);
+
+  memory->create(imflag,2*nmax,"body/rounded/polyhedron:imflag");
+  memory->create(imdata,2*nmax,7,"body/polyhedron:imdata");
+}
+
+/* ---------------------------------------------------------------------- */
+
+BodyRoundedPolyhedron::~BodyRoundedPolyhedron()
+{
+  delete icp;
+  delete dcp;
+  memory->destroy(imflag);
+  memory->destroy(imdata);
+}
+
+/* ---------------------------------------------------------------------- */
+
+int BodyRoundedPolyhedron::nsub(AtomVecBody::Bonus *bonus)
+{
+  return bonus->ivalue[0];
+}
+
+/* ---------------------------------------------------------------------- */
+
+double *BodyRoundedPolyhedron::coords(AtomVecBody::Bonus *bonus)
+{
+  return bonus->dvalue;
+}
+
+/* ---------------------------------------------------------------------- */
+
+int BodyRoundedPolyhedron::nedges(AtomVecBody::Bonus *bonus)
+{
+  int nvertices = bonus->ivalue[0];
+  int nedges = bonus->ivalue[1];
+  int nfaces = bonus->ivalue[2];
+  if (nvertices == 1) return 0;
+  else if (nvertices == 2) return 1;
+  return nedges; //(nvertices+nfaces-2); // Euler's polyon formula: V-E+F=2
+}
+
+/* ---------------------------------------------------------------------- */
+
+double *BodyRoundedPolyhedron::edges(AtomVecBody::Bonus *bonus)
+{
+  return bonus->dvalue+3*nsub(bonus);
+}
+
+/* ---------------------------------------------------------------------- */
+
+int BodyRoundedPolyhedron::nfaces(AtomVecBody::Bonus *bonus)
+{
+  return bonus->ivalue[2];
+}
+
+/* ---------------------------------------------------------------------- */
+
+double *BodyRoundedPolyhedron::faces(AtomVecBody::Bonus *bonus)
+{
+  int nvertices = bonus->ivalue[0];
+  if (nvertices == 1 || nvertices == 2) return NULL;
+  return bonus->dvalue+3*nsub(bonus)+2*nedges(bonus);
+}
+
+/* ---------------------------------------------------------------------- */
+
+double BodyRoundedPolyhedron::enclosing_radius(struct AtomVecBody::Bonus *bonus)
+{
+  int nvertices = bonus->ivalue[0];
+  if (nvertices == 1 || nvertices == 2)
+  	return *(bonus->dvalue+3*nsub(bonus)+2);
+  return *(bonus->dvalue+3*nsub(bonus) + 2*nedges(bonus) + 
+           MAX_FACE_SIZE*nfaces(bonus));
+}
+
+/* ---------------------------------------------------------------------- */
+
+double BodyRoundedPolyhedron::rounded_radius(struct AtomVecBody::Bonus *bonus)
+{
+  int nvertices = bonus->ivalue[0];
+  if (nvertices == 1 || nvertices == 2)
+    return *(bonus->dvalue+3*nsub(bonus)+2+1);
+  return *(bonus->dvalue+3*nsub(bonus) + 2*nedges(bonus) + 
+           MAX_FACE_SIZE*nfaces(bonus)+1);
+}
+
+/* ---------------------------------------------------------------------- */
+
+int BodyRoundedPolyhedron::pack_border_body(AtomVecBody::Bonus *bonus, double *buf)
+{
+  int nsub = bonus->ivalue[0];
+  int ned = bonus->ivalue[1];
+  int nfac = bonus->ivalue[2];
+  buf[0] = nsub;
+  buf[1] = ned;
+  buf[2] = nfac;
+  int ndouble;
+  if (nsub == 1 || nsub == 2) ndouble = 3*nsub+2+MAX_FACE_SIZE*nfac+1+1;
+  else ndouble = 3*nsub+2*ned+MAX_FACE_SIZE*nfac+1+1;
+  memcpy(&buf[3],bonus->dvalue,ndouble*sizeof(double));
+  return 3+ndouble;
+}
+
+/* ---------------------------------------------------------------------- */
+
+int BodyRoundedPolyhedron::unpack_border_body(AtomVecBody::Bonus *bonus,
+                                           double *buf)
+{
+  int nsub = static_cast<int> (buf[0]);
+  int ned = static_cast<int> (buf[1]);
+  int nfac = static_cast<int> (buf[2]);
+  bonus->ivalue[0] = nsub;
+  bonus->ivalue[1] = ned;
+  bonus->ivalue[2] = nfac;
+  int ndouble;
+  if (nsub == 1 || nsub == 2) ndouble = 3*nsub+2+MAX_FACE_SIZE*nfac+1+1;
+  else ndouble = 3*nsub+2*ned+MAX_FACE_SIZE*nfac+1+1;
+  memcpy(bonus->dvalue,&buf[3],ndouble*sizeof(double));
+  return 3+ndouble;
+}
+
+/* ----------------------------------------------------------------------
+   populate bonus data structure with data file values
+------------------------------------------------------------------------- */
+
+void BodyRoundedPolyhedron::data_body(int ibonus, int ninteger, int ndouble,
+                             int *ifile, double *dfile)
+{
+  AtomVecBody::Bonus *bonus = &avec->bonus[ibonus];
+
+  // set ninteger, ndouble in bonus and allocate 2 vectors of ints, doubles
+
+  if (ninteger != 3)
+    error->one(FLERR,"Incorrect # of integer values in "
+               "Bodies section of data file");
+  int nsub = ifile[0];
+  int ned = ifile[1];
+  int nfac = ifile[2];
+  if (nsub < 1)
+    error->one(FLERR,"Incorrect integer value in "
+               "Bodies section of data file");
+
+  // nentries = number of double entries to be read from Body section:
+  // nsub == 1 || nsub == 2 || nsub == 3:
+  //   6 for inertia + 3*nsub for vertex coords + 1 for rounded radius
+  // nsub > 3:
+  //   6 for inertia + 3*nsub for vertex coords + 2*nsub for edges + 
+  //   3*nfaces + 1 for rounded radius
+
+  int nedges,nentries;
+  if (nsub == 1 || nsub == 2) {
+    nentries = 6 + 3*nsub + 1;
+  } else {
+    nedges = ned; //nsub + nfac - 2;
+    nentries = 6 + 3*nsub + 2*nedges + MAX_FACE_SIZE*nfac + 1;
+  }
+  if (ndouble != nentries)
+    error->one(FLERR,"Incorrect # of floating-point values in "
+             "Bodies section of data file");
+
+  bonus->ninteger = 3;
+  bonus->ivalue = icp->get(bonus->iindex);
+  bonus->ivalue[0] = nsub;
+  bonus->ivalue[1] = ned;
+  bonus->ivalue[2] = nfac;
+  if (nsub == 1 || nsub == 2) bonus->ndouble = 3*nsub + 2*nsub + 1 + 1;
+  else bonus->ndouble = 3*nsub + 2*nedges + MAX_FACE_SIZE*nfac + 1 + 1;
+  bonus->dvalue = dcp->get(bonus->ndouble,bonus->dindex);
+
+  // diagonalize inertia tensor
+
+  double tensor[3][3];
+  tensor[0][0] = dfile[0];
+  tensor[1][1] = dfile[1];
+  tensor[2][2] = dfile[2];
+  tensor[0][1] = tensor[1][0] = dfile[3];
+  tensor[0][2] = tensor[2][0] = dfile[4];
+  tensor[1][2] = tensor[2][1] = dfile[5];
+
+  double *inertia = bonus->inertia;
+  double evectors[3][3];
+  int ierror = MathExtra::jacobi(tensor,inertia,evectors);
+  if (ierror) error->one(FLERR,
+                         "Insufficient Jacobi rotations for body nparticle");
+
+  // if any principal moment < scaled EPSILON, set to 0.0
+
+  double max;
+  max = MAX(inertia[0],inertia[1]);
+  max = MAX(max,inertia[2]);
+
+  if (inertia[0] < EPSILON*max) inertia[0] = 0.0;
+  if (inertia[1] < EPSILON*max) inertia[1] = 0.0;
+  if (inertia[2] < EPSILON*max) inertia[2] = 0.0;
+
+  // exyz_space = principal axes in space frame
+
+  double ex_space[3],ey_space[3],ez_space[3];
+
+  ex_space[0] = evectors[0][0];
+  ex_space[1] = evectors[1][0];
+  ex_space[2] = evectors[2][0];
+  ey_space[0] = evectors[0][1];
+  ey_space[1] = evectors[1][1];
+  ey_space[2] = evectors[2][1];
+  ez_space[0] = evectors[0][2];
+  ez_space[1] = evectors[1][2];
+  ez_space[2] = evectors[2][2];
+
+  // enforce 3 evectors as a right-handed coordinate system
+  // flip 3rd vector if needed
+
+  double cross[3];
+  MathExtra::cross3(ex_space,ey_space,cross);
+  if (MathExtra::dot3(cross,ez_space) < 0.0) MathExtra::negate3(ez_space);
+
+  // create initial quaternion
+
+  MathExtra::exyz_to_q(ex_space,ey_space,ez_space,bonus->quat);
+
+  // bonus->dvalue = the first 3*nsub elements are sub-particle displacements
+  // find the enclosing radius of the body from the maximum displacement
+
+  int i,m;
+  double delta[3], rsq, erad, rrad;
+  double erad2 = 0;
+  int j = 6;
+  int k = 0;
+  for (i = 0; i < nsub; i++) {
+    delta[0] = dfile[j];
+    delta[1] = dfile[j+1];
+    delta[2] = dfile[j+2];
+    MathExtra::transpose_matvec(ex_space,ey_space,ez_space,
+                                delta,&bonus->dvalue[k]);
+    rsq = delta[0] * delta[0] + delta[1] * delta[1] +
+      delta[2] * delta[2];
+    if (rsq > erad2) erad2 = rsq;
+    j += 3;
+    k += 3;
+  }
+
+  // .. the next 2*nsub elements are edge ends
+
+  if (nsub == 1) { // spheres
+    nedges = 0;
+    bonus->dvalue[k] = 0;
+    *(&bonus->dvalue[k]+1) = 0;
+    k += 2;
+
+    rrad = 0.5 * dfile[j];
+    bonus->dvalue[k] = rrad;
+    erad = rrad; // enclosing radius = rounded_radius
+
+    // the last element of bonus->dvalue is the rounded radius
+
+    k++;
+    bonus->dvalue[k] = rrad;
+
+    atom->radius[bonus->ilocal] = erad;
+
+  } else if (nsub == 2) { // rods
+    nedges = 1;
+    for (i = 0; i < nedges; i++) {
+      bonus->dvalue[k] = 0;
+      *(&bonus->dvalue[k]+1) = 1;
+      k += 2;
+    }    
+
+    erad = sqrt(erad2);
+    bonus->dvalue[k] = erad;
+
+    // the last element of bonus->dvalue is the rounded radius
+
+    rrad = 0.5 * dfile[j];
+    k++;
+    bonus->dvalue[k] = rrad;
+
+    atom->radius[bonus->ilocal] = erad + rrad;
+
+  } else { // polyhedra
+
+    // edges
+
+    for (i = 0; i < nedges; i++) {
+      bonus->dvalue[k] = dfile[j];
+      *(&bonus->dvalue[k]+1) = dfile[j+1];
+      k += 2;
+      j += 2;
+    }
+
+    // faces
+
+    for (i = 0; i < nfac; i++) {
+      for (m = 0; m < MAX_FACE_SIZE; m++)
+        *(&bonus->dvalue[k]+m) = dfile[j+m];
+      k += MAX_FACE_SIZE;
+      j += MAX_FACE_SIZE;
+    }
+
+    // the next to last element is the enclosing radius
+
+    erad = sqrt(erad2);
+    bonus->dvalue[k] = erad;
+
+    // the last element bonus-> dvalue is the rounded radius
+
+    rrad = 0.5 * dfile[j];
+    k++;
+    bonus->dvalue[k] = rrad;
+
+    atom->radius[bonus->ilocal] = erad + rrad;
+  }
+}
+
+/* ----------------------------------------------------------------------
+   return radius of body particle defined by ifile/dfile params
+   params are ordered as in data file
+   called by Molecule class which needs single body size
+------------------------------------------------------------------------- */
+
+double BodyRoundedPolyhedron::radius_body(int ninteger, int ndouble,
+				       int *ifile, double *dfile)
+{
+  int nsub = ifile[0];
+  int ned = ifile[1];
+  int nfac = ifile[2];
+  int nedges = ned; //nsub + nfac - 2;
+
+  int nentries;
+  if (nsub == 1 || nsub == 2) nentries = 6 + 3*nsub + 1;
+  else nentries = 6 + 3*nsub + 2*nedges + MAX_FACE_SIZE*nfac + 1;
+
+  if (nsub < 1)
+    error->one(FLERR,"Incorrect integer value in "
+               "Bodies section of data file");
+  if (ndouble != nentries)
+    error->one(FLERR,"Incorrect # of floating-point values in "
+               "Bodies section of data file");
+
+  // sub-particle coords are relative to body center at (0,0,0)
+  // offset = 6 for sub-particle coords
+
+  double onerad;
+  double maxrad = 0.0;
+  double delta[3];
+
+  int offset = 6;          
+  for (int i = 0; i < nsub; i++) {
+    delta[0] = dfile[offset];
+    delta[1] = dfile[offset+1];
+    delta[2] = dfile[offset+2];
+    offset += 3;
+    onerad = MathExtra::len3(delta);
+    maxrad = MAX(maxrad,onerad);
+  }
+
+  if (nsub > 2) offset += (2*nedges+MAX_FACE_SIZE*nfac);
+
+  // add in radius of rounded corners
+  
+  return maxrad + 0.5*dfile[offset];
+}
+
+/* ---------------------------------------------------------------------- */
+
+int BodyRoundedPolyhedron::noutcol()
+{
+  // the number of columns for the vertex coordinates
+
+  return 3;
+}
+
+/* ---------------------------------------------------------------------- */
+
+int BodyRoundedPolyhedron::noutrow(int ibonus)
+{
+  // only return the first nsub rows for the vertex coordinates
+
+  return avec->bonus[ibonus].ivalue[0];
+}
+
+/* ---------------------------------------------------------------------- */
+
+void BodyRoundedPolyhedron::output(int ibonus, int m, double *values)
+{
+  AtomVecBody::Bonus *bonus = &avec->bonus[ibonus];
+
+  double p[3][3];
+  MathExtra::quat_to_mat(bonus->quat,p);
+  MathExtra::matvec(p,&bonus->dvalue[3*m],values);
+
+  double *x = atom->x[bonus->ilocal];
+  values[0] += x[0];
+  values[1] += x[1];
+  values[2] += x[2];
+}
+
+/* ---------------------------------------------------------------------- */
+
+int BodyRoundedPolyhedron::image(int ibonus, double flag1, double flag2,
+                              int *&ivec, double **&darray)
+{
+  int j, nelements;
+  double p[3][3];
+  double *x, rrad;
+
+  AtomVecBody::Bonus *bonus = &avec->bonus[ibonus];
+  int nvertices = bonus->ivalue[0];
+
+  if (nvertices == 1) { // spheres
+
+    for (int i = 0; i < nvertices; i++) {
+      imflag[i] = SPHERE;
+      MathExtra::quat_to_mat(bonus->quat,p);
+      MathExtra::matvec(p,&bonus->dvalue[3*i],imdata[i]);
+
+      rrad = enclosing_radius(bonus);
+      x = atom->x[bonus->ilocal];
+      imdata[i][0] += x[0];
+      imdata[i][1] += x[1];
+      imdata[i][2] += x[2];
+      if (flag1 <= 0) imdata[i][3] = 2*rrad;
+      else imdata[i][3] = flag1;
+    }
+
+    nelements = nvertices;
+  } else {
+    int nfaces = bonus->ivalue[2];
+    int nedges = bonus->ivalue[1]; //nvertices + nfaces - 2;
+    if (nvertices == 2) nedges = 1; // special case: rods
+    double* edge_ends = &bonus->dvalue[3*nvertices];
+    int pt1, pt2;
+
+    for (int i = 0; i < nedges; i++) {
+      imflag[i] = LINE;
+
+      pt1 = static_cast<int>(edge_ends[2*i]);
+      pt2 = static_cast<int>(edge_ends[2*i+1]);
+
+      MathExtra::quat_to_mat(bonus->quat,p);
+      MathExtra::matvec(p,&bonus->dvalue[3*pt1],imdata[i]);
+      MathExtra::matvec(p,&bonus->dvalue[3*pt2],&imdata[i][3]);
+
+      rrad = rounded_radius(bonus);
+      x = atom->x[bonus->ilocal];
+      imdata[i][0] += x[0];
+      imdata[i][1] += x[1];
+      imdata[i][2] += x[2];
+      imdata[i][3] += x[0];
+      imdata[i][4] += x[1];
+      imdata[i][5] += x[2];
+
+      if (flag1 <= 0) imdata[i][6] = 2*rrad;
+      else imdata[i][6] = flag1;
+    }
+
+    nelements = nedges;
+  }
+
+  ivec = imflag;
+  darray = imdata;
+  return nelements;
+}
diff --git a/src/BODY/body_rounded_polyhedron.h b/src/BODY/body_rounded_polyhedron.h
new file mode 100644
index 0000000000000000000000000000000000000000..e5b15fd8f93f6c0a65d896262a52dd85d7569c41
--- /dev/null
+++ b/src/BODY/body_rounded_polyhedron.h
@@ -0,0 +1,88 @@
+/* -*- 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 BODY_CLASS
+
+BodyStyle(rounded/polyhedron,BodyRoundedPolyhedron)
+
+#else
+
+#ifndef LMP_BODY_ROUNDED_POLYHEDRON_H
+#define LMP_BODY_ROUNDED_POLYHEDRON_H
+
+#include "body.h"
+#include "atom_vec_body.h"
+
+namespace LAMMPS_NS {
+
+class BodyRoundedPolyhedron : public Body {
+ public:
+  BodyRoundedPolyhedron(class LAMMPS *, int, char **);
+  ~BodyRoundedPolyhedron();
+  int nsub(struct AtomVecBody::Bonus *);
+  double *coords(struct AtomVecBody::Bonus *);
+  int nedges(struct AtomVecBody::Bonus *);
+  double *edges(struct AtomVecBody::Bonus *);
+  int nfaces(struct AtomVecBody::Bonus *);
+  double *faces(struct AtomVecBody::Bonus *);
+  double enclosing_radius(struct AtomVecBody::Bonus *);
+  double rounded_radius(struct AtomVecBody::Bonus *);
+
+  int pack_border_body(struct AtomVecBody::Bonus *, double *);
+  int unpack_border_body(struct AtomVecBody::Bonus *, double *);
+  void data_body(int, int, int, int *, double *);
+  double radius_body(int, int, int *, double *);
+
+  int noutrow(int);
+  int noutcol();
+  void output(int, int, double *);
+  int image(int, double, double, int *&, double **&);
+
+ private:
+  int *imflag;
+  double **imdata;
+};
+
+}
+
+#endif
+#endif
+
+/* ERROR/WARNING messages:
+
+E: Invalid body rounded/polyhedron command
+
+Arguments in atom-style command are not correct.
+
+E: Invalid format in Bodies section of data file
+
+The specified number of integer or floating point values does not
+appear.
+
+E: Incorrect # of integer values in Bodies section of data file
+
+See doc page for body style.
+
+E: Incorrect integer value in Bodies section of data file
+
+See doc page for body style.
+
+E: Incorrect # of floating-point values in Bodies section of data file
+
+See doc page for body style.
+
+E: Insufficient Jacobi rotations for body rounded/polyhedron
+
+Eigensolve for rigid body was not sufficiently accurate.
+
+*/
diff --git a/src/BODY/fix_wall_body_polygon.cpp b/src/BODY/fix_wall_body_polygon.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5ec5a7cca8eb30309294a14b13f8e2d10e56bd26
--- /dev/null
+++ b/src/BODY/fix_wall_body_polygon.cpp
@@ -0,0 +1,832 @@
+/* ----------------------------------------------------------------------
+   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: Trung Dac Nguyen (ndactrung@gmail.com)
+------------------------------------------------------------------------- */
+
+#include <cmath>
+#include <cstdlib>
+#include <cstring>
+#include "fix_wall_body_polygon.h"
+#include "atom.h"
+#include "atom_vec_body.h"
+#include "body_rounded_polygon.h"
+#include "domain.h"
+#include "update.h"
+#include "force.h"
+#include "pair.h"
+#include "modify.h"
+#include "respa.h"
+#include "math_const.h"
+#include "math_extra.h"
+#include "memory.h"
+#include "error.h"
+
+using namespace LAMMPS_NS;
+using namespace FixConst;
+using namespace MathConst;
+
+enum{XPLANE=0,YPLANE=1,ZCYLINDER};    // XYZ PLANE need to be 0,1,2
+enum{HOOKE,HOOKE_HISTORY};
+
+enum {INVALID=0,NONE=1,VERTEX=2};
+enum {FAR=0,XLO,XHI,YLO,YHI};
+
+//#define _POLYGON_DEBUG
+#define DELTA 10000
+#define EPSILON 1e-2
+#define BIG 1.0e20
+#define MAX_CONTACTS 4  // maximum number of contacts for 2D models
+#define EFF_CONTACTS 2  // effective contacts for 2D models
+
+/* ---------------------------------------------------------------------- */
+
+FixWallBodyPolygon::FixWallBodyPolygon(LAMMPS *lmp, int narg, char **arg) :
+  Fix(lmp, narg, arg)
+{
+  if (narg < 7) error->all(FLERR,"Illegal fix wall/body/polygon command");
+
+  if (!atom->body_flag)
+    error->all(FLERR,"Fix wall/body/polygon requires "
+               "atom style body/rounded/polygon");
+
+  restart_peratom = 1;
+  create_attribute = 1;
+
+  // wall/particle coefficients
+
+  kn = force->numeric(FLERR,arg[3]);
+
+  c_n = force->numeric(FLERR,arg[4]);
+  if (strcmp(arg[5],"NULL") == 0) c_t = 0.5 * c_n;
+  else c_t = force->numeric(FLERR,arg[5]);
+
+  if (kn < 0.0 || c_n < 0.0 || c_t < 0.0)
+    error->all(FLERR,"Illegal fix wall/body/polygon command");
+
+  // wallstyle args
+
+  int iarg = 6;
+  if (strcmp(arg[iarg],"xplane") == 0) {
+    if (narg < iarg+3) error->all(FLERR,"Illegal fix wall/body/polygon command");
+    wallstyle = XPLANE;
+    if (strcmp(arg[iarg+1],"NULL") == 0) lo = -BIG;
+    else lo = force->numeric(FLERR,arg[iarg+1]);
+    if (strcmp(arg[iarg+2],"NULL") == 0) hi = BIG;
+    else hi = force->numeric(FLERR,arg[iarg+2]);
+    iarg += 3;
+  } else if (strcmp(arg[iarg],"yplane") == 0) {
+    if (narg < iarg+3) error->all(FLERR,"Illegal fix wall/body/polygon command");
+    wallstyle = YPLANE;
+    if (strcmp(arg[iarg+1],"NULL") == 0) lo = -BIG;
+    else lo = force->numeric(FLERR,arg[iarg+1]);
+    if (strcmp(arg[iarg+2],"NULL") == 0) hi = BIG;
+    else hi = force->numeric(FLERR,arg[iarg+2]);
+    iarg += 3;
+  } else if (strcmp(arg[iarg],"zcylinder") == 0) {
+    if (narg < iarg+2) error->all(FLERR,"Illegal fix wall/body/polygon command");
+    wallstyle = ZCYLINDER;
+    lo = hi = 0.0;
+    cylradius = force->numeric(FLERR,arg[iarg+1]);
+    iarg += 2;
+  }
+
+  // check for trailing keyword/values
+
+  wiggle = 0;
+
+  while (iarg < narg) {
+    if (strcmp(arg[iarg],"wiggle") == 0) {
+      if (iarg+4 > narg) error->all(FLERR,"Illegal fix wall/body/polygon command");
+      if (strcmp(arg[iarg+1],"x") == 0) axis = 0;
+      else if (strcmp(arg[iarg+1],"y") == 0) axis = 1;
+      else if (strcmp(arg[iarg+1],"z") == 0) axis = 2;
+      else error->all(FLERR,"Illegal fix wall/body/polygon command");
+      amplitude = force->numeric(FLERR,arg[iarg+2]);
+      period = force->numeric(FLERR,arg[iarg+3]);
+      wiggle = 1;
+      iarg += 4;
+    } else error->all(FLERR,"Illegal fix wall/body/polygon command");
+  }
+
+  if (wallstyle == XPLANE && domain->xperiodic)
+    error->all(FLERR,"Cannot use wall in periodic dimension");
+  if (wallstyle == YPLANE && domain->yperiodic)
+    error->all(FLERR,"Cannot use wall in periodic dimension");
+  if (wallstyle == ZCYLINDER && (domain->xperiodic || domain->yperiodic))
+    error->all(FLERR,"Cannot use wall in periodic dimension");
+
+  if (wiggle && wallstyle == ZCYLINDER && axis != 2)
+    error->all(FLERR,"Invalid wiggle direction for fix wall/body/polygon");
+
+  // setup oscillations
+
+  if (wiggle) omega = 2.0*MY_PI / period;
+
+  time_origin = update->ntimestep;
+
+  dmax = nmax = 0;
+  discrete = NULL;
+  dnum = dfirst = NULL;
+
+  edmax = ednummax = 0;
+  edge = NULL;
+  ednum = edfirst = NULL;
+
+  enclosing_radius = NULL;
+  rounded_radius = NULL;
+}
+
+/* ---------------------------------------------------------------------- */
+
+FixWallBodyPolygon::~FixWallBodyPolygon()
+{
+  memory->destroy(discrete);
+  memory->destroy(dnum);
+  memory->destroy(dfirst);
+
+  memory->destroy(edge);
+  memory->destroy(ednum);
+  memory->destroy(edfirst);
+
+  memory->destroy(enclosing_radius);
+  memory->destroy(rounded_radius);
+}
+
+/* ---------------------------------------------------------------------- */
+
+int FixWallBodyPolygon::setmask()
+{
+  int mask = 0;
+  mask |= POST_FORCE;
+  return mask;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixWallBodyPolygon::init()
+{
+  dt = update->dt;
+
+  avec = (AtomVecBody *) atom->style_match("body");
+  if (!avec)
+    error->all(FLERR,"Pair body/rounded/polygon requires atom style body");
+  if (strcmp(avec->bptr->style,"rounded/polygon") != 0)
+    error->all(FLERR,"Pair body/rounded/polygon requires "
+               "body style rounded/polygon");
+  bptr = (BodyRoundedPolygon *) avec->bptr;
+
+  // set pairstyle from body/polygonular pair style
+
+  if (force->pair_match("body/rounded/polygon",1))
+    pairstyle = HOOKE;
+  else error->all(FLERR,"Fix wall/body/polygon is incompatible with Pair style");
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixWallBodyPolygon::setup(int vflag)
+{
+  if (strstr(update->integrate_style,"verlet"))
+    post_force(vflag);
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixWallBodyPolygon::post_force(int vflag)
+{
+  double vwall[3],dx,dy,dz,del1,del2,delxy,delr,rsq,eradi,rradi,wall_pos;
+  int i,ni,npi,ifirst,nei,iefirst,side;
+  double facc[3];
+
+  // set position of wall to initial settings and velocity to 0.0
+  // if wiggle, set wall position and velocity accordingly
+
+  double wlo = lo;
+  double whi = hi;
+  vwall[0] = vwall[1] = vwall[2] = 0.0;
+  if (wiggle) {
+    double arg = omega * (update->ntimestep - time_origin) * dt;
+    if (wallstyle == axis) {
+      wlo = lo + amplitude - amplitude*cos(arg);
+      whi = hi + amplitude - amplitude*cos(arg);
+    }
+    vwall[axis] = amplitude*omega*sin(arg);
+  }
+
+  // loop over all my atoms
+  // rsq = distance from wall
+  // dx,dy,dz = signed distance from wall
+  // for rotating cylinder, reset vwall based on particle position
+  // skip atom if not close enough to wall
+  //   if wall was set to NULL, it's skipped since lo/hi are infinity
+  // compute force and torque on atom if close enough to wall
+  //   via wall potential matched to pair potential
+
+  double **x = atom->x;
+  double **v = atom->v;
+  double **f = atom->f;
+  int *body = atom->body;
+  double *radius = atom->radius;
+  double **torque = atom->torque;
+  double **angmom = atom->angmom;
+  int *mask = atom->mask;
+  int nlocal = atom->nlocal;
+
+  // grow the per-atom lists if necessary and initialize
+
+  if (atom->nmax > nmax) {
+    memory->destroy(dnum);
+    memory->destroy(dfirst);
+    memory->destroy(ednum);
+    memory->destroy(edfirst);
+    memory->destroy(enclosing_radius);
+    memory->destroy(rounded_radius);
+    nmax = atom->nmax;
+    memory->create(dnum,nmax,"fix:dnum");
+    memory->create(dfirst,nmax,"fix:dfirst");
+    memory->create(ednum,nmax,"fix:ednum");
+    memory->create(edfirst,nmax,"fix:edfirst");
+    memory->create(enclosing_radius,nmax,"fix:enclosing_radius");
+    memory->create(rounded_radius,nmax,"fix:rounded_radius");
+  }
+
+  ndiscrete = nedge = 0;
+  for (i = 0; i < nlocal; i++) 
+    dnum[i] = ednum[i] = 0;
+
+  for (i = 0; i < nlocal; i++) {
+    if (mask[i] & groupbit) {
+
+      if (body[i] < 0) continue;
+
+      dx = dy = dz = 0.0;
+      side = FAR;
+      if (wallstyle == XPLANE) {
+        del1 = x[i][0] - wlo;
+        del2 = whi - x[i][0];
+        if (del1 < del2) {
+          dx = del1;
+          wall_pos = wlo;
+          side = XLO;
+        } else {
+          dx = -del2;
+          wall_pos = whi;
+          side = XHI;
+        }
+      } else if (wallstyle == YPLANE) {
+        del1 = x[i][1] - wlo;
+        del2 = whi - x[i][1];
+        if (del1 < del2) {
+          dy = del1;
+          wall_pos = wlo;
+          side = YLO;
+        } else {
+          dy = -del2;
+          wall_pos = whi;
+          side = YHI;
+        }
+      } else if (wallstyle == ZCYLINDER) {
+        delxy = sqrt(x[i][0]*x[i][0] + x[i][1]*x[i][1]);
+        delr = cylradius - delxy;
+        if (delr > eradi) dz = cylradius;
+        else {
+          dx = -delr/delxy * x[i][0];
+          dy = -delr/delxy * x[i][1];
+        }
+      }
+
+      rsq = dx*dx + dy*dy + dz*dz;
+      if (rsq > radius[i]*radius[i]) continue;
+
+      double r = sqrt(rsq);
+      double rsqinv = 1.0 / rsq;
+
+      if (dnum[i] == 0) body2space(i);
+      npi = dnum[i];
+      ifirst = dfirst[i];
+      nei = ednum[i];
+      iefirst = edfirst[i];
+      eradi = enclosing_radius[i];
+      rradi = rounded_radius[i];
+
+      // reset vertex and edge forces
+
+      for (ni = 0; ni < npi; ni++) {
+        discrete[ifirst+ni][3] = 0;
+        discrete[ifirst+ni][4] = 0;
+        discrete[ifirst+ni][5] = 0;
+      }
+
+      for (ni = 0; ni < nei; ni++) {
+        edge[iefirst+ni][2] = 0;
+        edge[iefirst+ni][3] = 0;
+        edge[iefirst+ni][4] = 0;
+      }
+
+      int interact, num_contacts, done;
+      double delta_a, delta_ua, j_a;
+      Contact contact_list[MAX_CONTACTS];
+
+      num_contacts = 0;
+      facc[0] = facc[1] = facc[2] = 0;
+      interact = vertex_against_wall(i, wall_pos, x, f, torque, side,
+                                     contact_list, num_contacts, facc);
+
+      if (num_contacts >= 2) {
+
+        // find the first two distinct contacts
+
+        done = 0;
+        for (int m = 0; m < num_contacts-1; m++) {
+          for (int n = m+1; n < num_contacts; n++) {
+            delta_a = contact_separation(contact_list[m], contact_list[n]);
+            if (delta_a > 0) {
+              delta_ua = 1.0;
+              j_a = delta_a / (EFF_CONTACTS * delta_ua);
+              if (j_a < 1.0) j_a = 1.0;
+
+              // scale the force at both contacts
+
+              contact_forces(contact_list[m], j_a, x, v, angmom, f, torque,
+                             vwall, facc);
+              contact_forces(contact_list[n], j_a, x, v, angmom, f, torque,
+                             vwall, facc);
+              done = 1;
+              break;
+            }
+          }
+          if (done == 1) break;
+        }
+
+      } else if (num_contacts == 1) {
+
+        // if there's only one contact, it should be handled here
+        // since forces/torques have not been accumulated from vertex2wall()
+
+        contact_forces(contact_list[0], 1.0, x, v, angmom, f, torque,
+                       vwall, facc);
+      }
+    } // group bit
+  }
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixWallBodyPolygon::reset_dt()
+{
+  dt = update->dt;
+}
+
+/* ----------------------------------------------------------------------
+   convert N sub-particles in body I to space frame using current quaternion
+   store sub-particle space-frame displacements from COM in discrete list
+------------------------------------------------------------------------- */
+
+void FixWallBodyPolygon::body2space(int i)
+{
+  int ibonus = atom->body[i];
+  AtomVecBody::Bonus *bonus = &avec->bonus[ibonus];
+  int nsub = bptr->nsub(bonus);
+  double *coords = bptr->coords(bonus);
+  int body_num_edges = bptr->nedges(bonus);
+  double* vertices = bptr->edges(bonus);
+  double eradius = bptr->enclosing_radius(bonus);
+  double rradius = bptr->rounded_radius(bonus);
+
+  // get the number of sub-particles (vertices)
+  // and the index of the first vertex of my body in the list
+
+  dnum[i] = nsub;
+  dfirst[i] = ndiscrete;
+
+  // grow the vertex list if necessary
+  // the first 3 columns are for coords, the last 3 for forces
+
+  if (ndiscrete + nsub > dmax) {
+    dmax += DELTA;
+    memory->grow(discrete,dmax,6,"fix:discrete");
+  }
+
+  double p[3][3];
+  MathExtra::quat_to_mat(bonus->quat,p);
+
+  for (int m = 0; m < nsub; m++) {
+    MathExtra::matvec(p,&coords[3*m],discrete[ndiscrete]);
+    discrete[ndiscrete][3] = 0;
+    discrete[ndiscrete][4] = 0;
+    discrete[ndiscrete][5] = 0;
+    ndiscrete++;
+  }
+
+  // get the number of edges (vertices)
+  // and the index of the first edge of my body in the list
+
+  ednum[i] = body_num_edges;
+  edfirst[i] = nedge;
+
+  // grow the edge list if necessary
+  // the first 2 columns are for vertex indices within body,
+  // the last 3 for forces
+
+  if (nedge + body_num_edges > edmax) {
+    edmax += DELTA;
+    memory->grow(edge,edmax,5,"fix:edge");
+  }
+
+  for (int m = 0; m < body_num_edges; m++) {
+    edge[nedge][0] = static_cast<int>(vertices[2*m+0]);
+    edge[nedge][1] = static_cast<int>(vertices[2*m+1]);
+    edge[nedge][2] = 0;
+    edge[nedge][3] = 0;
+    edge[nedge][4] = 0;
+    nedge++;
+  }
+
+  enclosing_radius[i] = eradius;
+  rounded_radius[i] = rradius;
+}
+
+/* ----------------------------------------------------------------------
+   Determine the interaction mode between i's vertices against the wall
+
+   i = atom i (body i)
+   x      = atoms' coordinates
+   f      = atoms' forces
+   torque = atoms' torques
+   Return:
+     contact_list = list of contacts between i and the wall
+     num_contacts = number of contacts between i's vertices and the wall
+     interact = 0 no interaction with the wall
+                1 there's at least one vertex of i interacts
+                  with the wall
+---------------------------------------------------------------------- */
+
+int FixWallBodyPolygon::vertex_against_wall(int i, double wall_pos,
+                double** x, double** f, double** torque, int side,
+                Contact* contact_list, int &num_contacts, double* facc)
+{
+  int ni, npi, ifirst, interact;
+  double xpi[3], xpj[3], dist, eradi, rradi;
+  double fx, fy, fz, rx, ry, rz;
+  int nlocal = atom->nlocal;
+
+  npi = dnum[i];
+  ifirst = dfirst[i];
+  eradi = enclosing_radius[i];
+  rradi = rounded_radius[i];
+
+  interact = 0;
+
+  // loop through body i's vertices
+
+  for (ni = 0; ni < npi; ni++) {
+
+    // convert body-fixed coordinates to space-fixed, xi
+
+    xpi[0] = x[i][0] + discrete[ifirst+ni][0];
+    xpi[1] = x[i][1] + discrete[ifirst+ni][1];
+    xpi[2] = x[i][2] + discrete[ifirst+ni][2];
+
+    int mode, contact, p2vertex;
+    double d, R, hi[3], t, delx, dely, delz, fpair, shift;
+    double xj[3], rij;
+
+    // compute the distance from the vertex xpi to the wall
+
+    mode = compute_distance_to_wall(xpi, rradi, wall_pos, side,
+                                    d, hi, contact);
+
+    if (mode == INVALID || mode == NONE) continue;
+
+    if (mode == VERTEX) {
+
+      interact = 1;
+
+      // vertex i interacts with the wall
+
+      delx = xpi[0] - hi[0];
+      dely = xpi[1] - hi[1];
+      delz = xpi[2] - hi[2];
+
+      // R = surface separation = d shifted by the rounded radius
+      // R = d - p1.rounded_radius;
+      // note: the force is defined for R, not for d
+      // R >  0: no interaction
+      // R <= 0: deformation between vertex i and the wall
+
+      rij = sqrt(delx*delx + dely*dely + delz*delz);
+      R = rij - rradi;
+
+      // the normal frictional term -c_n * vn will be added later
+
+      if (R <= 0) {           // deformation occurs
+        fpair = -kn * R;
+      } else fpair = 0.0;
+
+      fx = delx*fpair/rij;
+      fy = dely*fpair/rij;
+      fz = delz*fpair/rij;
+
+      #ifdef _POLYGON_DEBUG
+      printf("  Interaction between vertex %d of %d and wall:", ni);
+      printf("    mode = %d; contact = %d; d = %f; rij = %f\n",
+             mode, contact, d, rij);
+      printf("    R = %f\n", R);
+      printf("    fpair = %f\n", fpair);
+      #endif
+
+      if (contact == 1) {
+
+        // vertex ni of body i contacts with edge nj of body j
+
+        contact_list[num_contacts].ibody = i;
+        contact_list[num_contacts].jbody = -1;
+        contact_list[num_contacts].vertex = ni;
+        contact_list[num_contacts].edge = -1;
+        contact_list[num_contacts].xv[0] = xpi[0];
+        contact_list[num_contacts].xv[1] = xpi[1];
+        contact_list[num_contacts].xv[2] = xpi[2];
+        contact_list[num_contacts].xe[0] = hi[0];
+        contact_list[num_contacts].xe[1] = hi[1];
+        contact_list[num_contacts].xe[2] = hi[2];
+        contact_list[num_contacts].separation = R;
+        num_contacts++;
+
+        // store forces to vertex ni to be rescaled later,
+        // if there are 2 contacts
+
+        discrete[ifirst+ni][3] = fx;
+        discrete[ifirst+ni][4] = fy;
+        discrete[ifirst+ni][5] = fz;
+
+        #ifdef _POLYGON_DEBUG
+        printf("  Stored forces at vertex and edge for accumulating later.\n");
+        #endif
+
+      } else { // no contact
+
+        // accumulate force and torque to the body directly
+
+        f[i][0] += fx;
+        f[i][1] += fy;
+        f[i][2] += fz;
+        sum_torque(x[i], xpi, fx, fy, fz, torque[i]);
+
+      } // end if contact
+
+    } // end if mode
+
+  } // end for looping through the vertices of body i
+
+  return interact;
+}
+
+/* -------------------------------------------------------------------------
+  Compute the distance between a vertex to the wall
+  another body
+  Input:
+    x0         = coordinate of the tested vertex
+    rradi      = rounded radius of the vertex
+    wall_pos   = position of the wall
+  Output:
+    d          = Distance from a point x0 to an wall
+    hi         = coordinates of the projection of x0 on the wall
+  contact      = 0 no contact between the queried vertex and the wall
+                 1 contact detected
+  return NONE    if there is no interaction
+         EDGE    if the tested vertex interacts with the wall
+------------------------------------------------------------------------- */
+
+int FixWallBodyPolygon::compute_distance_to_wall(double* x0, double rradi,
+          double wall_pos, int side, double &d, double hi[3], int &contact)
+{
+  int mode;
+  double delxy;
+
+  // h0 = position of the projection of x0 on the wall
+  if (wallstyle == XPLANE) {
+    hi[0] = wall_pos;
+    hi[1] = x0[1];
+    hi[2] = x0[2];
+  } else if (wallstyle == YPLANE) {
+    hi[0] = x0[0];
+    hi[1] = wall_pos;
+    hi[2] = x0[2];
+  } else if (wallstyle == ZCYLINDER) {
+    delxy = sqrt(x0[0]*x0[0] + x0[1]*x0[1]);
+    hi[0] = x0[0]*cylradius/delxy;
+    hi[1] = x0[1]*cylradius/delxy;
+    hi[2] = x0[2];
+  }
+
+  // distance from x0 to the wall = distance from x0 to hi
+
+  distance(hi, x0, d);
+
+  // determine the interaction mode
+
+  if (d < rradi) {
+    mode = VERTEX;
+    contact = 1;
+  } else {
+    if (side == XLO) {
+      if (x0[0] < wall_pos) mode = VERTEX;
+      else mode = NONE;
+    } else if (side == XHI) {
+      if (x0[0] > wall_pos) mode = VERTEX;
+      else mode = NONE;
+    } else if (side == YLO) {
+      if (x0[1] < wall_pos) mode = VERTEX;
+      else mode = NONE;
+    } else if (side == YHI) {
+      if (x0[1] > wall_pos) mode = VERTEX;
+      else mode = NONE;
+    }
+  }
+
+  if (mode == NONE) contact = 0;
+  else contact = 1;
+
+  return mode;
+}
+
+/* ----------------------------------------------------------------------
+  Compute the contact forces between two bodies
+  modify the force stored at the vertex and edge in contact by j_a
+  sum forces and torque to the corresponding bodies
+    fn = normal friction component
+    ft = tangential friction component (-c_t * vrt)
+------------------------------------------------------------------------- */
+
+void FixWallBodyPolygon::contact_forces(Contact& contact, double j_a,
+                      double** x, double** v, double** angmom, double** f,
+                      double** torque, double* vwall, double* facc)
+{
+  int ibody,ibonus,ifirst, jefirst, ni;
+  double fx,fy,fz,delx,dely,delz,rsq,rsqinv;
+  double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3;
+  double fn[3],ft[3],vi[3];
+  double *quat, *inertia;
+  AtomVecBody::Bonus *bonus;
+
+  ibody = contact.ibody;
+  
+  // compute the velocity of the vertex in the space-fixed frame
+
+  ibonus = atom->body[ibody];
+  bonus = &avec->bonus[ibonus];
+  quat = bonus->quat;
+  inertia = bonus->inertia;
+  total_velocity(contact.xv, x[ibody], v[ibody], angmom[ibody],
+                 inertia, quat, vi);
+
+  // vector pointing from the vertex to the point on the wall
+
+  delx = contact.xv[0] - contact.xe[0];
+  dely = contact.xv[1] - contact.xe[1];
+  delz = contact.xv[2] - contact.xe[2];
+  rsq = delx*delx + dely*dely + delz*delz;
+  rsqinv = 1.0/rsq;
+
+  // relative translational velocity
+
+  vr1 = vi[0] - vwall[0];
+  vr2 = vi[1] - vwall[1];
+  vr3 = vi[2] - vwall[2];
+
+  // normal component
+
+  vnnr = vr1*delx + vr2*dely + vr3*delz;
+  vn1 = delx*vnnr * rsqinv;
+  vn2 = dely*vnnr * rsqinv;
+  vn3 = delz*vnnr * rsqinv;
+
+  // tangential component
+
+  vt1 = vr1 - vn1;
+  vt2 = vr2 - vn2;
+  vt3 = vr3 - vn3;
+
+  // normal friction term at contact
+
+  fn[0] = -c_n * vn1;
+  fn[1] = -c_n * vn2;
+  fn[2] = -c_n * vn3;
+
+  // tangential friction term at contact
+  // excluding the tangential deformation term for now
+
+  ft[0] = -c_t * vt1;
+  ft[1] = -c_t * vt2;
+  ft[2] = -c_t * vt3;
+
+  // only the cohesive force is scaled by j_a
+
+  ifirst = dfirst[ibody];
+  ni = contact.vertex;
+
+  fx = discrete[ifirst+ni][3] * j_a + fn[0] + ft[0];
+  fy = discrete[ifirst+ni][4] * j_a + fn[1] + ft[1];
+  fz = discrete[ifirst+ni][5] * j_a + fn[2] + ft[2];
+  f[ibody][0] += fx;
+  f[ibody][1] += fy;
+  f[ibody][2] += fz;
+  sum_torque(x[ibody], contact.xv, fx, fy, fz, torque[ibody]);
+
+  // accumulate forces to the vertex only
+
+  facc[0] += fx; facc[1] += fy; facc[2] += fz;
+
+  #ifdef _POLYGON_DEBUG
+  printf("From contact forces: vertex fx %f fy %f fz %f\n"
+         "      torque body %d: %f %f %f\n",
+         discrete[ifirst+ni][3], discrete[ifirst+ni][4], discrete[ifirst+ni][5],
+         atom->tag[ibody],torque[ibody][0],torque[ibody][1],torque[ibody][2]);
+  #endif
+}
+
+/* ----------------------------------------------------------------------
+  Determine the length of the contact segment, i.e. the separation between
+  2 contacts
+------------------------------------------------------------------------- */
+
+double FixWallBodyPolygon::contact_separation(const Contact& c1,
+                                              const Contact& c2)
+{
+  double x1 = c1.xv[0];
+  double y1 = c1.xv[1];
+  double x2 = c1.xe[0];
+  double y2 = c1.xe[1];
+  double x3 = c2.xv[0];
+  double y3 = c2.xv[1];
+
+  double delta_a = 0.0;
+  if (fabs(x2 - x1) > EPSILON) {
+    double A = (y2 - y1) / (x2 - x1);
+    delta_a = fabs(y1 - A * x1 - y3 + A * x3) / sqrt(1 + A * A);
+  } else {
+    delta_a = fabs(x1 - x3);
+  }
+
+  return delta_a;
+}
+
+/* ----------------------------------------------------------------------
+  Accumulate torque to body from the force f=(fx,fy,fz) acting at point x
+------------------------------------------------------------------------- */
+
+void FixWallBodyPolygon::sum_torque(double* xm, double *x, double fx,
+                                    double fy, double fz, double* torque)
+{
+  double rx = x[0] - xm[0];
+  double ry = x[1] - xm[1];
+  double rz = x[2] - xm[2];
+  double tx = ry * fz - rz * fy;
+  double ty = rz * fx - rx * fz;
+  double tz = rx * fy - ry * fx;
+  torque[0] += tx;
+  torque[1] += ty;
+  torque[2] += tz;
+}
+
+/* ----------------------------------------------------------------------
+  Calculate the total velocity of a point (vertex, a point on an edge):
+    vi = vcm + omega ^ (p - xcm)
+------------------------------------------------------------------------- */
+
+void FixWallBodyPolygon::total_velocity(double* p, double *xcm,
+                              double* vcm, double *angmom, double *inertia,
+                              double *quat, double* vi)
+{
+  double r[3],omega[3],ex_space[3],ey_space[3],ez_space[3];
+  r[0] = p[0] - xcm[0];
+  r[1] = p[1] - xcm[1];
+  r[2] = p[2] - xcm[2];
+  MathExtra::q_to_exyz(quat,ex_space,ey_space,ez_space);
+  MathExtra::angmom_to_omega(angmom,ex_space,ey_space,ez_space,
+                             inertia,omega);
+  vi[0] = omega[1]*r[2] - omega[2]*r[1] + vcm[0];
+  vi[1] = omega[2]*r[0] - omega[0]*r[2] + vcm[1];
+  vi[2] = omega[0]*r[1] - omega[1]*r[0] + vcm[2];
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixWallBodyPolygon::distance(const double* x2, const double* x1,
+                                  double& r) {
+  r = sqrt((x2[0] - x1[0]) * (x2[0] - x1[0])
+    + (x2[1] - x1[1]) * (x2[1] - x1[1])
+    + (x2[2] - x1[2]) * (x2[2] - x1[2]));
+}
diff --git a/src/BODY/fix_wall_body_polygon.h b/src/BODY/fix_wall_body_polygon.h
new file mode 100644
index 0000000000000000000000000000000000000000..b71dcb06832ba312fb6a3853d185d1c37d23d314
--- /dev/null
+++ b/src/BODY/fix_wall_body_polygon.h
@@ -0,0 +1,131 @@
+/* -*- 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 FIX_CLASS
+
+FixStyle(wall/body/polygon,FixWallBodyPolygon)
+
+#else
+
+#ifndef LMP_FIX_WALL_BODY_POLYGON_H
+#define LMP_FIX_WALL_BODY_POLYGON_H
+
+#include "fix.h"
+
+namespace LAMMPS_NS {
+
+class FixWallBodyPolygon : public Fix {
+ public:
+  FixWallBodyPolygon(class LAMMPS *, int, char **);
+  virtual ~FixWallBodyPolygon();
+  int setmask();
+  void init();
+  void setup(int);
+  virtual void post_force(int);
+  void reset_dt();
+
+  struct Contact {
+    int ibody, jbody; // body (i.e. atom) indices (not tags)
+    int vertex;       // vertex of the first polygon
+    int edge;         // edge of the second polygon
+    double xv[3];     // coordinates of the vertex
+    double xe[3];     // coordinates of the projection of the vertex on the edge
+    double separation;// separation at contact
+  };
+
+ protected:
+  int wallstyle,pairstyle,wiggle,axis;
+  double kn;          // normal repulsion strength
+  double c_n;         // normal damping coefficient
+  double c_t;         // tangential damping coefficient
+  double lo,hi,cylradius;
+  double amplitude,period,omega;
+  double dt;
+  int time_origin;
+
+  class AtomVecBody *avec;
+  class BodyRoundedPolygon *bptr;
+
+  double **discrete;  // list of all sub-particles for all bodies
+  int ndiscrete;      // number of discretes in list
+  int dmax;           // allocated size of discrete list
+  int *dnum;          // number of discretes per line, 0 if uninit
+  int *dfirst;        // index of first discrete per each line
+  int nmax;           // allocated size of dnum,dfirst vectors
+
+  double **edge;      // list of all edge for all bodies
+  int nedge;          // number of edge in list
+  int edmax;          // allocated size of edge list
+  int *ednum;         // number of edges per line, 0 if uninit
+  int *edfirst;       // index of first edge per each line
+  int ednummax;       // allocated size of ednum,edfirst vectors
+
+  double *enclosing_radius; // enclosing radii for all bodies
+  double *rounded_radius;   // rounded radii for all bodies
+
+  void body2space(int);
+
+  int vertex_against_wall(int ibody, double wall_pos, double** x,
+                          double** f, double** torque, int side,
+                          Contact* contact_list, int &num_contacts,
+                          double* facc);
+
+  int compute_distance_to_wall(double* x0, double rradi, double wall_pos,
+                               int side, double &d, double hi[3], int &contact);
+  double contact_separation(const Contact& c1, const Contact& c2);
+  void contact_forces(Contact& contact, double j_a, double** x,
+                      double** v, double** angmom, double** f, double** torque,
+                      double* vwall, double* facc);
+  void sum_torque(double* xm, double *x, double fx,
+                  double fy, double fz, double* torque);
+  void total_velocity(double* p, double *xcm, double* vcm, double *angmom,
+                      double *inertia, double *quat, double* vi);
+  void distance(const double* x2, const double* x1, double& r);
+
+};
+
+}
+
+#endif
+#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: Fix wall/body/polygon requires atom style body rounded/polygon
+
+Self-explanatory.
+
+E: Cannot use wall in periodic dimension
+
+Self-explanatory.
+
+E: Cannot wiggle and shear fix wall/body/polygon
+
+Cannot specify both options at the same time.
+
+E: Invalid wiggle direction for fix wall/body/polygon
+
+Self-explanatory.
+
+E: Fix wall/body/polygon is incompatible with Pair style
+
+Must use a body pair style to define the parameters needed for
+this fix.
+
+*/
diff --git a/src/BODY/fix_wall_body_polyhedron.cpp b/src/BODY/fix_wall_body_polyhedron.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..17e9f0b8b5e05441dff0c93f333dde24793fd3e8
--- /dev/null
+++ b/src/BODY/fix_wall_body_polyhedron.cpp
@@ -0,0 +1,945 @@
+/* ----------------------------------------------------------------------
+   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: Trung Dac Nguyen (ndactrung@gmail.com)
+------------------------------------------------------------------------- */
+
+#include <cmath>
+#include <cstdlib>
+#include <cstring>
+#include "fix_wall_body_polyhedron.h"
+#include "atom.h"
+#include "atom_vec_body.h"
+#include "body_rounded_polyhedron.h"
+#include "domain.h"
+#include "update.h"
+#include "force.h"
+#include "pair.h"
+#include "modify.h"
+#include "respa.h"
+#include "math_const.h"
+#include "math_extra.h"
+#include "memory.h"
+#include "error.h"
+
+using namespace LAMMPS_NS;
+using namespace FixConst;
+using namespace MathConst;
+
+enum{XPLANE=0,YPLANE=1,ZPLANE};    // XYZ PLANE need to be 0,1,2
+enum{HOOKE,HOOKE_HISTORY};
+
+enum {INVALID=0,NONE=1,VERTEX=2};
+enum {FAR=0,XLO,XHI,YLO,YHI,ZLO,ZHI};
+
+//#define _POLYHEDRON_DEBUG
+#define DELTA 10000
+#define EPSILON 1e-2
+#define BIG 1.0e20
+#define MAX_CONTACTS 4  // maximum number of contacts for 2D models
+#define EFF_CONTACTS 2  // effective contacts for 2D models
+
+/* ---------------------------------------------------------------------- */
+
+FixWallBodyPolyhedron::FixWallBodyPolyhedron(LAMMPS *lmp, int narg, char **arg) :
+  Fix(lmp, narg, arg)
+{
+  if (narg < 7) error->all(FLERR,"Illegal fix wall/body/polyhedron command");
+
+  if (!atom->body_flag)
+    error->all(FLERR,"Fix wall/body/polyhedron requires "
+               "atom style body/rounded/polyhedron");
+
+  restart_peratom = 1;
+  create_attribute = 1;
+
+  // wall/particle coefficients
+
+  kn = force->numeric(FLERR,arg[3]);
+
+  c_n = force->numeric(FLERR,arg[4]);
+  if (strcmp(arg[5],"NULL") == 0) c_t = 0.5 * c_n;
+  else c_t = force->numeric(FLERR,arg[5]);
+
+  if (kn < 0.0 || c_n < 0.0 || c_t < 0.0)
+    error->all(FLERR,"Illegal fix wall/body/polyhedron command");
+
+  // wallstyle args
+
+  int iarg = 6;
+  if (strcmp(arg[iarg],"xplane") == 0) {
+    if (narg < iarg+3) error->all(FLERR,"Illegal fix wall/body/polyhedron command");
+    wallstyle = XPLANE;
+    if (strcmp(arg[iarg+1],"NULL") == 0) lo = -BIG;
+    else lo = force->numeric(FLERR,arg[iarg+1]);
+    if (strcmp(arg[iarg+2],"NULL") == 0) hi = BIG;
+    else hi = force->numeric(FLERR,arg[iarg+2]);
+    iarg += 3;
+  } else if (strcmp(arg[iarg],"yplane") == 0) {
+    if (narg < iarg+3) error->all(FLERR,"Illegal fix wall/body/polyhedron command");
+    wallstyle = YPLANE;
+    if (strcmp(arg[iarg+1],"NULL") == 0) lo = -BIG;
+    else lo = force->numeric(FLERR,arg[iarg+1]);
+    if (strcmp(arg[iarg+2],"NULL") == 0) hi = BIG;
+    else hi = force->numeric(FLERR,arg[iarg+2]);
+    iarg += 3;
+  } else if (strcmp(arg[iarg],"zplane") == 0) {
+    if (narg < iarg+3) error->all(FLERR,"Illegal fix wall/body/polyhedron command");
+    wallstyle = ZPLANE;
+    if (strcmp(arg[iarg+1],"NULL") == 0) lo = -BIG;
+    else lo = force->numeric(FLERR,arg[iarg+1]);
+    if (strcmp(arg[iarg+2],"NULL") == 0) hi = BIG;
+    else hi = force->numeric(FLERR,arg[iarg+2]);
+    iarg += 3;
+  } 
+
+  // check for trailing keyword/values
+
+  wiggle = 0;
+
+  while (iarg < narg) {
+    if (strcmp(arg[iarg],"wiggle") == 0) {
+      if (iarg+4 > narg) error->all(FLERR,"Illegal fix wall/body/polyhedron command");
+      if (strcmp(arg[iarg+1],"x") == 0) axis = 0;
+      else if (strcmp(arg[iarg+1],"y") == 0) axis = 1;
+      else if (strcmp(arg[iarg+1],"z") == 0) axis = 2;
+      else error->all(FLERR,"Illegal fix wall/body/polyhedron command");
+      amplitude = force->numeric(FLERR,arg[iarg+2]);
+      period = force->numeric(FLERR,arg[iarg+3]);
+      wiggle = 1;
+      iarg += 4;
+    } else error->all(FLERR,"Illegal fix wall/body/polyhedron command");
+  }
+
+  if (wallstyle == XPLANE && domain->xperiodic)
+    error->all(FLERR,"Cannot use wall in periodic dimension");
+  if (wallstyle == YPLANE && domain->yperiodic)
+    error->all(FLERR,"Cannot use wall in periodic dimension");
+  if (wallstyle == ZPLANE && domain->zperiodic)
+    error->all(FLERR,"Cannot use wall in periodic dimension");
+
+  // setup oscillations
+
+  if (wiggle) omega = 2.0*MY_PI / period;
+
+  time_origin = update->ntimestep;
+
+  dmax = nmax = 0;
+  discrete = NULL;
+  dnum = dfirst = NULL;
+
+  edmax = ednummax = 0;
+  edge = NULL;
+  ednum = edfirst = NULL;
+
+  facmax = facnummax = 0;
+  face = NULL;
+  facnum = facfirst = NULL;
+
+  enclosing_radius = NULL;
+  rounded_radius = NULL;
+}
+
+/* ---------------------------------------------------------------------- */
+
+FixWallBodyPolyhedron::~FixWallBodyPolyhedron()
+{
+  memory->destroy(discrete);
+  memory->destroy(dnum);
+  memory->destroy(dfirst);
+
+  memory->destroy(edge);
+  memory->destroy(ednum);
+  memory->destroy(edfirst);
+
+  memory->destroy(face);
+  memory->destroy(facnum);
+  memory->destroy(facfirst);
+
+  memory->destroy(enclosing_radius);
+  memory->destroy(rounded_radius);
+}
+
+/* ---------------------------------------------------------------------- */
+
+int FixWallBodyPolyhedron::setmask()
+{
+  int mask = 0;
+  mask |= POST_FORCE;
+  return mask;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixWallBodyPolyhedron::init()
+{
+  dt = update->dt;
+
+  avec = (AtomVecBody *) atom->style_match("body");
+  if (!avec)
+    error->all(FLERR,"Pair body/rounded/polyhedron requires atom style body");
+  if (strcmp(avec->bptr->style,"rounded/polyhedron") != 0)
+    error->all(FLERR,"Pair body/rounded/polyhedron requires "
+               "body style rounded/polyhedron");
+  bptr = (BodyRoundedPolyhedron *) avec->bptr;
+
+  // set pairstyle from body/polyhedronular pair style
+
+  if (force->pair_match("body/rounded/polyhedron",1))
+    pairstyle = HOOKE;
+  else error->all(FLERR,"Fix wall/body/polyhedron is incompatible with Pair style");
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixWallBodyPolyhedron::setup(int vflag)
+{
+  if (strstr(update->integrate_style,"verlet"))
+    post_force(vflag);
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixWallBodyPolyhedron::post_force(int vflag)
+{
+  double vwall[3],dx,dy,dz,del1,del2,delxy,delr,rsq,eradi,rradi,wall_pos;
+  int i,ni,npi,ifirst,nei,iefirst,nfi,iffirst,side;
+  double facc[3];
+
+  // set position of wall to initial settings and velocity to 0.0
+  // if wiggle, set wall position and velocity accordingly
+
+  double wlo = lo;
+  double whi = hi;
+  vwall[0] = vwall[1] = vwall[2] = 0.0;
+  if (wiggle) {
+    double arg = omega * (update->ntimestep - time_origin) * dt;
+    if (wallstyle == axis) {
+      wlo = lo + amplitude - amplitude*cos(arg);
+      whi = hi + amplitude - amplitude*cos(arg);
+    }
+    vwall[axis] = amplitude*omega*sin(arg);
+  }
+
+  // loop over all my atoms
+  // rsq = distance from wall
+  // dx,dy,dz = signed distance from wall
+  // for rotating cylinder, reset vwall based on particle position
+  // skip atom if not close enough to wall
+  //   if wall was set to NULL, it's skipped since lo/hi are infinity
+  // compute force and torque on atom if close enough to wall
+  //   via wall potential matched to pair potential
+
+  double **x = atom->x;
+  double **v = atom->v;
+  double **f = atom->f;
+  int *body = atom->body;
+  double *radius = atom->radius;
+  double **torque = atom->torque;
+  double **angmom = atom->angmom;
+  int *mask = atom->mask;
+  int nlocal = atom->nlocal;
+
+  // grow the per-atom lists if necessary and initialize
+
+  if (atom->nmax > nmax) {
+    memory->destroy(dnum);
+    memory->destroy(dfirst);
+    memory->destroy(ednum);
+    memory->destroy(edfirst);
+    memory->destroy(facnum);
+    memory->destroy(facfirst);
+    memory->destroy(enclosing_radius);
+    memory->destroy(rounded_radius);
+    nmax = atom->nmax;
+    memory->create(dnum,nmax,"fix:dnum");
+    memory->create(dfirst,nmax,"fix:dfirst");
+    memory->create(ednum,nmax,"fix:ednum");
+    memory->create(edfirst,nmax,"fix:edfirst");
+    memory->create(facnum,nmax,"fix:facnum");
+    memory->create(facfirst,nmax,"fix:facfirst");
+    memory->create(enclosing_radius,nmax,"fix:enclosing_radius");
+    memory->create(rounded_radius,nmax,"fix:rounded_radius");
+  }
+
+  ndiscrete = nedge = nface = 0;
+  for (i = 0; i < nlocal; i++) 
+    dnum[i] = ednum[i] = facnum[i] = 0;
+
+  for (i = 0; i < nlocal; i++) {
+    if (mask[i] & groupbit) {
+
+      if (body[i] < 0) continue;
+
+      dx = dy = dz = 0.0;
+      side = FAR;
+      if (wallstyle == XPLANE) {
+        del1 = x[i][0] - wlo;
+        del2 = whi - x[i][0];
+        if (del1 < del2) {
+          dx = del1;
+          wall_pos = wlo;
+          side = XLO;
+        } else {
+          dx = -del2;
+          wall_pos = whi;
+          side = XHI;
+        }
+      } else if (wallstyle == YPLANE) {
+        del1 = x[i][1] - wlo;
+        del2 = whi - x[i][1];
+        if (del1 < del2) {
+          dy = del1;
+          wall_pos = wlo;
+          side = YLO;
+        } else {
+          dy = -del2;
+          wall_pos = whi;
+          side = YHI;
+        }
+      } else if (wallstyle == ZPLANE) {
+        del1 = x[i][2] - wlo;
+        del2 = whi - x[i][2];
+        if (del1 < del2) {
+          dy = del1;
+          wall_pos = wlo;
+          side = ZLO;
+        } else {
+          dy = -del2;
+          wall_pos = whi;
+          side = ZHI;
+        }
+      } 
+
+      rsq = dx*dx + dy*dy + dz*dz;
+      if (rsq > radius[i]*radius[i]) continue;
+
+      double r = sqrt(rsq);
+      double rsqinv = 1.0 / rsq;
+
+      if (dnum[i] == 0) body2space(i);
+      npi = dnum[i];
+      ifirst = dfirst[i];
+      nei = ednum[i];
+      iefirst = edfirst[i];
+      nfi = facnum[i];
+      iffirst = facfirst[i];
+      eradi = enclosing_radius[i];
+      rradi = rounded_radius[i];
+
+      if (npi == 1) {
+        sphere_against_wall(i, wall_pos, side, vwall, x, v, f, angmom, torque);
+        continue;
+      }
+
+      // reset vertex and edge forces
+
+      for (ni = 0; ni < npi; ni++) {
+        discrete[ifirst+ni][3] = 0;
+        discrete[ifirst+ni][4] = 0;
+        discrete[ifirst+ni][5] = 0;
+        discrete[ifirst+ni][6] = 0;
+      }
+
+      for (ni = 0; ni < nei; ni++) {
+        edge[iefirst+ni][2] = 0;
+        edge[iefirst+ni][3] = 0;
+        edge[iefirst+ni][4] = 0;
+        edge[iefirst+ni][5] = 0;
+      }
+
+      int interact, num_contacts, done;
+      double delta_a, delta_ua, j_a;
+      Contact contact_list[MAX_CONTACTS];
+
+      num_contacts = 0;
+      facc[0] = facc[1] = facc[2] = 0;
+      interact = edge_against_wall(i, wall_pos, side, vwall, x, f, torque,
+                                   contact_list, num_contacts, facc);
+
+    } // group bit
+  }
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixWallBodyPolyhedron::reset_dt()
+{
+  dt = update->dt;
+}
+
+/* ----------------------------------------------------------------------
+   convert N sub-particles in body I to space frame using current quaternion
+   store sub-particle space-frame displacements from COM in discrete list
+------------------------------------------------------------------------- */
+
+void FixWallBodyPolyhedron::body2space(int i)
+{
+  int ibonus = atom->body[i];
+  AtomVecBody::Bonus *bonus = &avec->bonus[ibonus];
+  int nsub = bptr->nsub(bonus);
+  double *coords = bptr->coords(bonus);
+  int body_num_edges = bptr->nedges(bonus);
+  double* edge_ends = bptr->edges(bonus);
+  int body_num_faces = bptr->nfaces(bonus);
+  double* face_pts = bptr->faces(bonus);
+  double eradius = bptr->enclosing_radius(bonus);
+  double rradius = bptr->rounded_radius(bonus);
+
+  // get the number of sub-particles (vertices)
+  // and the index of the first vertex of my body in the list
+
+  dnum[i] = nsub;
+  dfirst[i] = ndiscrete;
+
+  // grow the vertex list if necessary
+  // the first 3 columns are for coords, the last 3 for forces
+
+  if (ndiscrete + nsub > dmax) {
+    dmax += DELTA;
+    memory->grow(discrete,dmax,7,"fix:discrete");
+  }
+
+  double p[3][3];
+  MathExtra::quat_to_mat(bonus->quat,p);
+
+  for (int m = 0; m < nsub; m++) {
+    MathExtra::matvec(p,&coords[3*m],discrete[ndiscrete]);
+    discrete[ndiscrete][3] = 0;
+    discrete[ndiscrete][4] = 0;
+    discrete[ndiscrete][5] = 0;
+    discrete[ndiscrete][6] = 0;
+    ndiscrete++;
+  }
+
+  // get the number of edges (vertices)
+  // and the index of the first edge of my body in the list
+
+  ednum[i] = body_num_edges;
+  edfirst[i] = nedge;
+
+  // grow the edge list if necessary
+  // the first 2 columns are for vertex indices within body,
+  // the last 3 for forces
+
+  if (nedge + body_num_edges > edmax) {
+    edmax += DELTA;
+    memory->grow(edge,edmax,6,"fix:edge");
+  }
+
+  for (int m = 0; m < body_num_edges; m++) {
+    edge[nedge][0] = static_cast<int>(edge_ends[2*m+0]);
+    edge[nedge][1] = static_cast<int>(edge_ends[2*m+1]);
+    edge[nedge][2] = 0;
+    edge[nedge][3] = 0;
+    edge[nedge][4] = 0;
+    edge[nedge][5] = 0;
+    nedge++;
+  }
+
+  // get the number of faces and the index of the first face
+
+  facnum[i] = body_num_faces;
+  facfirst[i] = nface;
+
+  // grow the face list if necessary
+  // the first 3 columns are for vertex indices within body, the last 3 for forces
+
+  if (nface + body_num_faces > facmax) {
+    facmax += DELTA;
+    memory->grow(face,facmax,6,"pair:face");
+  }
+
+  for (int m = 0; m < body_num_faces; m++) {
+    face[nface][0] = static_cast<int>(face_pts[3*m+0]);
+    face[nface][1] = static_cast<int>(face_pts[3*m+1]);
+    face[nface][2] = static_cast<int>(face_pts[3*m+2]);
+    face[nface][3] = 0;
+    face[nface][4] = 0;
+    face[nface][5] = 0;
+    nface++;
+  }
+
+  enclosing_radius[i] = eradius;
+  rounded_radius[i] = rradius;
+}
+
+/* ----------------------------------------------------------------------
+   Determine the interaction mode between a sphere against the wall
+
+   i = atom i (body i)
+   x      = atoms' coordinates
+   f      = atoms' forces
+   torque = atoms' torques
+---------------------------------------------------------------------- */
+
+int FixWallBodyPolyhedron::sphere_against_wall(int i, double wall_pos,
+     int side, double* vwall, double** x, double** v, double** f,
+     double** angmom, double** torque)
+{
+  int mode;
+  double rradi,hi[3],d,delx,dely,delz,R,fpair,fx,fy,fz;
+
+  rradi = rounded_radius[i];
+  mode = NONE;
+
+  if (wallstyle == XPLANE) {
+    hi[0] = wall_pos;
+    hi[1] = x[i][1];
+    hi[2] = x[i][2];
+  } else if (wallstyle == YPLANE) {
+    hi[0] = x[i][0];
+    hi[1] = wall_pos;
+    hi[2] = x[i][2];
+  } else if (wallstyle == ZPLANE) {
+    hi[0] = x[i][0];
+    hi[1] = x[i][1];
+    hi[2] = wall_pos;
+  } 
+
+  distance(hi, x[i], d);
+
+  if (d <= rradi) {
+    delx = x[i][0] - hi[0];
+    dely = x[i][1] - hi[1];
+    delz = x[i][2] - hi[2];
+    R = d - rradi;
+
+    fpair = -kn * R;
+
+    fx = delx*fpair/d;
+    fy = dely*fpair/d;
+    fz = delz*fpair/d;
+
+    contact_forces(i, 1.0, x[i], hi, delx, dely, delz,
+                   fx, fy, fz, x, v, angmom, f, torque, vwall);
+    mode = VERTEX;
+  }
+
+  return mode;
+}
+
+/* ----------------------------------------------------------------------
+   Determine the interaction mode between i's vertices against the wall
+
+   i = atom i (body i)
+   x      = atoms' coordinates
+   f      = atoms' forces
+   torque = atoms' torques
+   Output:
+     contact_list = list of contacts between i and the wall
+     num_contacts = number of contacts between i's vertices and the wall
+   Return: 
+     number of contacts of the edge to the wall (0, 1 or 2)
+---------------------------------------------------------------------- */
+
+int FixWallBodyPolyhedron::edge_against_wall(int i, double wall_pos,
+     int side, double* vwall, double** x, double** f, double** torque,
+     Contact* contact_list, int &num_contacts, double* facc)
+{
+  int ni, nei, mode, contact;
+  double rradi;
+  int nlocal = atom->nlocal;
+
+  nei = ednum[i];
+  rradi = rounded_radius[i];
+
+  contact = 0;
+
+  // loop through body i's edges
+
+  for (ni = 0; ni < nei; ni++)
+    mode = compute_distance_to_wall(i, ni, x[i], rradi, wall_pos, side, vwall,
+                                    contact);
+
+  return contact;
+}
+
+/* -------------------------------------------------------------------------
+  Compute the distance between a vertex to the wall
+  another body
+  Input:
+    x0         = coordinate of the tested vertex
+    rradi      = rounded radius of the vertex
+    wall_pos   = position of the wall
+  Output:
+    d          = Distance from a point x0 to an wall
+    hi         = coordinates of the projection of x0 on the wall
+  contact      = 0 no contact between the queried vertex and the wall
+                 1 contact detected
+  return NONE    if there is no interaction
+         VERTEX  if the tested vertex interacts with the wall
+------------------------------------------------------------------------- */
+
+int FixWallBodyPolyhedron::compute_distance_to_wall(int ibody, int edge_index,
+                        double *xmi, double rounded_radius_i, double wall_pos, 
+                        int side, double* vwall, int &contact)
+{
+  int mode,ifirst,iefirst,npi1,npi2;
+  double d1,d2,xpi1[3],xpi2[3],hi[3];
+  double fx,fy,fz,fpair,delx,dely,delz,R;
+
+  double** x = atom->x;
+  double** v = atom->v;
+  double** f = atom->f;
+  double** torque = atom->torque;
+  double** angmom = atom->angmom;
+
+  // two ends of the edge from body i
+
+  ifirst = dfirst[ibody];
+  iefirst = edfirst[ibody];
+  npi1 = static_cast<int>(edge[iefirst+edge_index][0]);
+  npi2 = static_cast<int>(edge[iefirst+edge_index][1]);
+
+  xpi1[0] = xmi[0] + discrete[ifirst+npi1][0];
+  xpi1[1] = xmi[1] + discrete[ifirst+npi1][1];
+  xpi1[2] = xmi[2] + discrete[ifirst+npi1][2];
+
+  xpi2[0] = xmi[0] + discrete[ifirst+npi2][0];
+  xpi2[1] = xmi[1] + discrete[ifirst+npi2][1];
+  xpi2[2] = xmi[2] + discrete[ifirst+npi2][2];
+
+  // determine the intersection of the edge to the wall
+
+  mode = NONE;
+  double j_a = 1.0;
+
+  if (wallstyle == XPLANE) {
+    hi[0] = wall_pos;
+    hi[1] = xpi1[1];
+    hi[2] = xpi1[2];
+  } else if (wallstyle == YPLANE) {
+    hi[0] = xpi1[0];
+    hi[1] = wall_pos;
+    hi[2] = xpi1[2];
+  } else if (wallstyle == ZPLANE) {
+    hi[0] = xpi1[0];
+    hi[1] = xpi1[1];
+    hi[2] = wall_pos;
+  } 
+
+  distance(hi, xpi1, d1);
+
+  if (d1 <= rounded_radius_i && static_cast<int>(discrete[ifirst+npi1][6]) == 0) {
+    delx = xpi1[0] - hi[0];
+    dely = xpi1[1] - hi[1];
+    delz = xpi1[2] - hi[2];
+    R = d1 - rounded_radius_i;
+
+    fpair = -kn * R;
+
+    fx = delx*fpair/d1;
+    fy = dely*fpair/d1;
+    fz = delz*fpair/d1;
+
+    contact_forces(ibody, j_a, xpi1, hi, delx, dely, delz,
+                   fx, fy, fz, x, v, angmom, f, torque, vwall);
+    discrete[ifirst+npi1][6] = 1;
+    contact++;
+    mode = VERTEX;
+  }
+
+  if (wallstyle == XPLANE) {
+    hi[0] = wall_pos;
+    hi[1] = xpi2[1];
+    hi[2] = xpi2[2];
+  } else if (wallstyle == YPLANE) {
+    hi[0] = xpi2[0];
+    hi[1] = wall_pos;
+    hi[2] = xpi2[2];
+  } else if (wallstyle == ZPLANE) {
+    hi[0] = xpi2[0];
+    hi[1] = xpi2[1];
+    hi[2] = wall_pos;
+  } 
+
+  distance(hi, xpi2, d2);
+
+  if (d2 <= rounded_radius_i && static_cast<int>(discrete[ifirst+npi2][6]) == 0) {
+    delx = xpi2[0] - hi[0];
+    dely = xpi2[1] - hi[1];
+    delz = xpi2[2] - hi[2];
+    R = d2 - rounded_radius_i;
+
+    fpair = -kn * R;
+
+    fx = delx*fpair/d2;
+    fy = dely*fpair/d2;
+    fz = delz*fpair/d2;
+
+    contact_forces(ibody, j_a, xpi2, hi, delx, dely, delz,
+                   fx, fy, fz, x, v, angmom, f, torque, vwall);
+    discrete[ifirst+npi2][6] = 1;
+    contact++;
+    mode = VERTEX;
+  }
+
+  return mode;
+}
+
+/* ----------------------------------------------------------------------
+  Compute contact forces between two bodies
+  modify the force stored at the vertex and edge in contact by j_a
+  sum forces and torque to the corresponding bodies
+  fn = normal friction component
+  ft = tangential friction component (-c_t * v_t)
+------------------------------------------------------------------------- */
+
+void FixWallBodyPolyhedron::contact_forces(int ibody,
+  double j_a, double *xi, double *xj, double delx, double dely, double delz,
+  double fx, double fy, double fz, double** x, double** v, double** angmom,
+  double** f, double** torque, double* vwall)
+{
+  int ibonus,jbonus;
+  double fxt,fyt,fzt,rsq,rsqinv;
+  double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3;
+  double fn[3],ft[3],vi[3],vj[3];
+  double *quat, *inertia;
+  AtomVecBody::Bonus *bonus;
+
+  // compute the velocity of the vertex in the space-fixed frame
+
+  ibonus = atom->body[ibody];
+  bonus = &avec->bonus[ibonus];
+  quat = bonus->quat;
+  inertia = bonus->inertia;
+  total_velocity(xi, x[ibody], v[ibody], angmom[ibody],
+                 inertia, quat, vi);
+
+  // vector pointing from the contact point on ibody to the wall
+
+  rsq = delx*delx + dely*dely + delz*delz;
+  rsqinv = 1.0/rsq;
+
+  // relative translational velocity
+
+  vr1 = vi[0] - vwall[0];
+  vr2 = vi[1] - vwall[1];
+  vr3 = vi[2] - vwall[2];
+
+  // normal component
+
+  vnnr = vr1*delx + vr2*dely + vr3*delz;
+  vn1 = delx*vnnr * rsqinv;
+  vn2 = dely*vnnr * rsqinv;
+  vn3 = delz*vnnr * rsqinv;
+
+  // tangential component
+
+  vt1 = vr1 - vn1;
+  vt2 = vr2 - vn2;
+  vt3 = vr3 - vn3;
+
+  // normal friction term at contact
+
+  fn[0] = -c_n * vn1;
+  fn[1] = -c_n * vn2;
+  fn[2] = -c_n * vn3;
+
+  // tangential friction term at contact
+  // excluding the tangential deformation term for now
+
+  ft[0] = -c_t * vt1;
+  ft[1] = -c_t * vt2;
+  ft[2] = -c_t * vt3;
+
+  fxt = fx; fyt = fy; fzt = fz;
+  fx = fxt * j_a + fn[0] + ft[0];
+  fy = fyt * j_a + fn[1] + ft[1];
+  fz = fzt * j_a + fn[2] + ft[2];
+
+  f[ibody][0] += fx;
+  f[ibody][1] += fy;
+  f[ibody][2] += fz;
+  sum_torque(x[ibody], xi, fx, fy, fz, torque[ibody]);
+
+  #ifdef _POLYHEDRON_DEBUG
+  printf("From contact forces: vertex fx %f fy %f fz %f\n"
+         "      torque body %d: %f %f %f\n"
+         "      torque body %d: %f %f %f\n",
+         fxt, fyt, fzt,
+         atom->tag[ibody],torque[ibody][0],torque[ibody][1],torque[ibody][2],
+         atom->tag[jbody],torque[jbody][0],torque[jbody][1],torque[jbody][2]);
+  #endif
+}
+
+/* ----------------------------------------------------------------------
+  Compute the contact forces between two bodies
+  modify the force stored at the vertex and edge in contact by j_a
+  sum forces and torque to the corresponding bodies
+    fn = normal friction component
+    ft = tangential friction component (-c_t * vrt)
+------------------------------------------------------------------------- */
+
+void FixWallBodyPolyhedron::contact_forces(Contact& contact, double j_a,
+                      double** x, double** v, double** angmom, double** f,
+                      double** torque, double* vwall, double* facc)
+{
+  int ibody,ibonus,ifirst, jefirst, ni;
+  double fx,fy,fz,delx,dely,delz,rsq,rsqinv;
+  double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3;
+  double fn[3],ft[3],vi[3];
+  double *quat, *inertia;
+  AtomVecBody::Bonus *bonus;
+
+  ibody = contact.ibody;
+  
+  // compute the velocity of the vertex in the space-fixed frame
+
+  ibonus = atom->body[ibody];
+  bonus = &avec->bonus[ibonus];
+  quat = bonus->quat;
+  inertia = bonus->inertia;
+  total_velocity(contact.xv, x[ibody], v[ibody], angmom[ibody],
+                 inertia, quat, vi);
+
+  // vector pointing from the vertex to the point on the wall
+
+  delx = contact.xv[0] - contact.xe[0];
+  dely = contact.xv[1] - contact.xe[1];
+  delz = contact.xv[2] - contact.xe[2];
+  rsq = delx*delx + dely*dely + delz*delz;
+  rsqinv = 1.0/rsq;
+
+  // relative translational velocity
+
+  vr1 = vi[0] - vwall[0];
+  vr2 = vi[1] - vwall[1];
+  vr3 = vi[2] - vwall[2];
+
+  // normal component
+
+  vnnr = vr1*delx + vr2*dely + vr3*delz;
+  vn1 = delx*vnnr * rsqinv;
+  vn2 = dely*vnnr * rsqinv;
+  vn3 = delz*vnnr * rsqinv;
+
+  // tangential component
+
+  vt1 = vr1 - vn1;
+  vt2 = vr2 - vn2;
+  vt3 = vr3 - vn3;
+
+  // normal friction term at contact
+
+  fn[0] = -c_n * vn1;
+  fn[1] = -c_n * vn2;
+  fn[2] = -c_n * vn3;
+
+  // tangential friction term at contact
+  // excluding the tangential deformation term for now
+
+  ft[0] = -c_t * vt1;
+  ft[1] = -c_t * vt2;
+  ft[2] = -c_t * vt3;
+
+  // only the cohesive force is scaled by j_a
+
+  ifirst = dfirst[ibody];
+  ni = contact.vertex;
+
+  fx = discrete[ifirst+ni][3] * j_a + fn[0] + ft[0];
+  fy = discrete[ifirst+ni][4] * j_a + fn[1] + ft[1];
+  fz = discrete[ifirst+ni][5] * j_a + fn[2] + ft[2];
+  f[ibody][0] += fx;
+  f[ibody][1] += fy;
+  f[ibody][2] += fz;
+  sum_torque(x[ibody], contact.xv, fx, fy, fz, torque[ibody]);
+
+  // accumulate forces to the vertex only
+
+  facc[0] += fx; facc[1] += fy; facc[2] += fz;
+
+  #ifdef _POLYHEDRON_DEBUG
+  printf("From contact forces: vertex fx %f fy %f fz %f\n"
+         "      torque body %d: %f %f %f\n",
+         discrete[ifirst+ni][3], discrete[ifirst+ni][4], discrete[ifirst+ni][5],
+         atom->tag[ibody],torque[ibody][0],torque[ibody][1],torque[ibody][2]);
+  #endif
+}
+
+/* ----------------------------------------------------------------------
+  Determine the length of the contact segment, i.e. the separation between
+  2 contacts
+------------------------------------------------------------------------- */
+
+double FixWallBodyPolyhedron::contact_separation(const Contact& c1,
+                                              const Contact& c2)
+{
+  double x1 = c1.xv[0];
+  double y1 = c1.xv[1];
+  double x2 = c1.xe[0];
+  double y2 = c1.xe[1];
+  double x3 = c2.xv[0];
+  double y3 = c2.xv[1];
+
+  double delta_a = 0.0;
+  if (fabs(x2 - x1) > EPSILON) {
+    double A = (y2 - y1) / (x2 - x1);
+    delta_a = fabs(y1 - A * x1 - y3 + A * x3) / sqrt(1 + A * A);
+  } else {
+    delta_a = fabs(x1 - x3);
+  }
+
+  return delta_a;
+}
+
+/* ----------------------------------------------------------------------
+  Accumulate torque to body from the force f=(fx,fy,fz) acting at point x
+------------------------------------------------------------------------- */
+
+void FixWallBodyPolyhedron::sum_torque(double* xm, double *x, double fx,
+                                    double fy, double fz, double* torque)
+{
+  double rx = x[0] - xm[0];
+  double ry = x[1] - xm[1];
+  double rz = x[2] - xm[2];
+  double tx = ry * fz - rz * fy;
+  double ty = rz * fx - rx * fz;
+  double tz = rx * fy - ry * fx;
+  torque[0] += tx;
+  torque[1] += ty;
+  torque[2] += tz;
+}
+
+/* ----------------------------------------------------------------------
+  Calculate the total velocity of a point (vertex, a point on an edge):
+    vi = vcm + omega ^ (p - xcm)
+------------------------------------------------------------------------- */
+
+void FixWallBodyPolyhedron::total_velocity(double* p, double *xcm,
+                              double* vcm, double *angmom, double *inertia,
+                              double *quat, double* vi)
+{
+  double r[3],omega[3],ex_space[3],ey_space[3],ez_space[3];
+  r[0] = p[0] - xcm[0];
+  r[1] = p[1] - xcm[1];
+  r[2] = p[2] - xcm[2];
+  MathExtra::q_to_exyz(quat,ex_space,ey_space,ez_space);
+  MathExtra::angmom_to_omega(angmom,ex_space,ey_space,ez_space,
+                             inertia,omega);
+  vi[0] = omega[1]*r[2] - omega[2]*r[1] + vcm[0];
+  vi[1] = omega[2]*r[0] - omega[0]*r[2] + vcm[1];
+  vi[2] = omega[0]*r[1] - omega[1]*r[0] + vcm[2];
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixWallBodyPolyhedron::distance(const double* x2, const double* x1,
+                                  double& r) {
+  r = sqrt((x2[0] - x1[0]) * (x2[0] - x1[0])
+    + (x2[1] - x1[1]) * (x2[1] - x1[1])
+    + (x2[2] - x1[2]) * (x2[2] - x1[2]));
+}
diff --git a/src/BODY/fix_wall_body_polyhedron.h b/src/BODY/fix_wall_body_polyhedron.h
new file mode 100644
index 0000000000000000000000000000000000000000..ff7b7ca7cfd0806de2d5f4fcd16c79b48c980954
--- /dev/null
+++ b/src/BODY/fix_wall_body_polyhedron.h
@@ -0,0 +1,143 @@
+/* -*- 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 FIX_CLASS
+
+FixStyle(wall/body/polyhedron,FixWallBodyPolyhedron)
+
+#else
+
+#ifndef LMP_FIX_WALL_BODY_POLYHERON_H
+#define LMP_FIX_WALL_BODY_POLYHERON_H
+
+#include "fix.h"
+
+namespace LAMMPS_NS {
+
+class FixWallBodyPolyhedron : public Fix {
+ public:
+  FixWallBodyPolyhedron(class LAMMPS *, int, char **);
+  virtual ~FixWallBodyPolyhedron();
+  int setmask();
+  void init();
+  void setup(int);
+  virtual void post_force(int);
+  void reset_dt();
+
+  struct Contact {
+    int ibody, jbody; // body (i.e. atom) indices (not tags)
+    int vertex;       // vertex of the first polygon
+    int edge;         // edge of the second polygon
+    double xv[3];     // coordinates of the vertex
+    double xe[3];     // coordinates of the projection of the vertex on the edge
+    double separation;// separation at contact
+  };
+
+ protected:
+  int wallstyle,pairstyle,wiggle,axis;
+  double kn,c_n,c_t;
+  double lo,hi,cylradius;
+  double amplitude,period,omega;
+  double dt;
+  int time_origin;
+
+  class AtomVecBody *avec;
+  class BodyRoundedPolyhedron *bptr;
+
+  double **discrete;  // list of all sub-particles for all bodies
+  int ndiscrete;      // number of discretes in list
+  int dmax;           // allocated size of discrete list
+  int *dnum;          // number of discretes per line, 0 if uninit
+  int *dfirst;        // index of first discrete per each line
+  int nmax;           // allocated size of dnum,dfirst vectors
+
+  double **edge;      // list of all edge for all bodies
+  int nedge;          // number of edge in list
+  int edmax;          // allocated size of edge list
+  int *ednum;         // number of edges per line, 0 if uninit
+  int *edfirst;       // index of first edge per each line
+  int ednummax;       // allocated size of ednum,edfirst vectors
+
+  double **face;      // list of all edge for all bodies
+  int nface;          // number of faces in list
+  int facmax;         // allocated size of face list
+  int *facnum;        // number of faces per line, 0 if uninit
+  int *facfirst;      // index of first face per each line
+  int facnummax;      // allocated size of facnum,facfirst vectors
+
+  double *enclosing_radius; // enclosing radii for all bodies
+  double *rounded_radius;   // rounded radii for all bodies
+
+  void body2space(int);
+
+  int edge_against_wall(int ibody, double wall_pos, int side, double* vwall,
+     double** x, double** f, double** torque, Contact* contact_list,
+     int &num_contacts, double* facc);
+  int sphere_against_wall(int i, double wall_pos, int side, double* vwall,
+     double** x, double** v, double** f, double** angmom, double** torque);
+
+  int compute_distance_to_wall(int ibody, int edge_index, double *xmi,
+                               double rounded_radius_i, double wall_pos, int side,
+                               double* vwall, int &contact);
+  double contact_separation(const Contact& c1, const Contact& c2);
+  void contact_forces(int ibody, double j_a, double *xi, double *xj, 
+                      double delx, double dely, double delz,
+                      double fx, double fy, double fz, double** x, double** v,
+                      double** angmom, double** f, double** torque, double* vwall);
+
+  void contact_forces(Contact& contact, double j_a, double** x,
+                      double** v, double** angmom, double** f, double** torque,
+                      double* vwall, double* facc);
+  void sum_torque(double* xm, double *x, double fx,
+                  double fy, double fz, double* torque);
+  void total_velocity(double* p, double *xcm, double* vcm, double *angmom,
+                      double *inertia, double *quat, double* vi);
+  void distance(const double* x2, const double* x1, double& r);
+
+};
+
+}
+
+#endif
+#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: Fix wall/body/polyhedron requires atom style body rounded/polyhedron
+
+Self-explanatory.
+
+E: Cannot use wall in periodic dimension
+
+Self-explanatory.
+
+E: Cannot wiggle and shear fix wall/body/polygon
+
+Cannot specify both options at the same time.
+
+E: Invalid wiggle direction for fix wall/body/polygon
+
+Self-explanatory.
+
+E: Fix wall/body/polygon is incompatible with Pair style
+
+Must use a body pair style to define the parameters needed for
+this fix.
+
+*/
diff --git a/src/BODY/pair_body.cpp b/src/BODY/pair_body_nparticle.cpp
similarity index 95%
rename from src/BODY/pair_body.cpp
rename to src/BODY/pair_body_nparticle.cpp
index 8c12c0cf36aa0384c50e3745b45c969c8aa29cc2..80b45beb4e9ecf174503ea7f46c19c0e8a7f46a1 100644
--- a/src/BODY/pair_body.cpp
+++ b/src/BODY/pair_body_nparticle.cpp
@@ -15,7 +15,7 @@
 #include <cstdio>
 #include <cstdlib>
 #include <cstring>
-#include "pair_body.h"
+#include "pair_body_nparticle.h"
 #include "math_extra.h"
 #include "atom.h"
 #include "atom_vec_body.h"
@@ -32,7 +32,7 @@ using namespace LAMMPS_NS;
 
 /* ---------------------------------------------------------------------- */
 
-PairBody::PairBody(LAMMPS *lmp) : Pair(lmp)
+PairBodyNparticle::PairBodyNparticle(LAMMPS *lmp) : Pair(lmp)
 {
   dmax = nmax = 0;
   discrete = NULL;
@@ -44,7 +44,7 @@ PairBody::PairBody(LAMMPS *lmp) : Pair(lmp)
 
 /* ---------------------------------------------------------------------- */
 
-PairBody::~PairBody()
+PairBodyNparticle::~PairBodyNparticle()
 {
   memory->destroy(discrete);
   memory->destroy(dnum);
@@ -66,7 +66,7 @@ PairBody::~PairBody()
 
 /* ---------------------------------------------------------------------- */
 
-void PairBody::compute(int eflag, int vflag)
+void PairBodyNparticle::compute(int eflag, int vflag)
 {
   int i,j,ii,jj,inum,jnum,itype,jtype;
   int ni,nj,npi,npj,ifirst,jfirst;
@@ -336,7 +336,7 @@ void PairBody::compute(int eflag, int vflag)
    allocate all arrays
 ------------------------------------------------------------------------- */
 
-void PairBody::allocate()
+void PairBodyNparticle::allocate()
 {
   allocated = 1;
   int n = atom->ntypes;
@@ -361,7 +361,7 @@ void PairBody::allocate()
    global settings
 ------------------------------------------------------------------------- */
 
-void PairBody::settings(int narg, char **arg)
+void PairBodyNparticle::settings(int narg, char **arg)
 {
   if (narg != 1) error->all(FLERR,"Illegal pair_style command");
 
@@ -381,7 +381,7 @@ void PairBody::settings(int narg, char **arg)
    set coeffs for one or more type pairs
 ------------------------------------------------------------------------- */
 
-void PairBody::coeff(int narg, char **arg)
+void PairBodyNparticle::coeff(int narg, char **arg)
 {
   if (narg < 4 || narg > 5)
     error->all(FLERR,"Incorrect args for pair coefficients");
@@ -415,12 +415,12 @@ void PairBody::coeff(int narg, char **arg)
    init specific to this pair style
 ------------------------------------------------------------------------- */
 
-void PairBody::init_style()
+void PairBodyNparticle::init_style()
 {
   avec = (AtomVecBody *) atom->style_match("body");
-  if (!avec) error->all(FLERR,"Pair body requires atom style body");
+  if (!avec) error->all(FLERR,"Pair body/nparticle requires atom style body");
   if (strcmp(avec->bptr->style,"nparticle") != 0)
-    error->all(FLERR,"Pair body requires body style nparticle");
+    error->all(FLERR,"Pair body/nparticle requires body style nparticle");
   bptr = (BodyNparticle *) avec->bptr;
 
   neighbor->request(this,instance_me);
@@ -430,7 +430,7 @@ void PairBody::init_style()
    init for one type pair i,j and corresponding j,i
 ------------------------------------------------------------------------- */
 
-double PairBody::init_one(int i, int j)
+double PairBodyNparticle::init_one(int i, int j)
 {
   if (setflag[i][j] == 0) {
     epsilon[i][j] = mix_energy(epsilon[i][i],epsilon[j][j],
@@ -459,7 +459,7 @@ double PairBody::init_one(int i, int j)
    store sub-particle space-frame displacements from COM in discrete list
 ------------------------------------------------------------------------- */
 
-void PairBody::body2space(int i)
+void PairBodyNparticle::body2space(int i)
 {
   int ibonus = atom->body[i];
   AtomVecBody::Bonus *bonus = &avec->bonus[ibonus];
diff --git a/src/BODY/pair_body.h b/src/BODY/pair_body_nparticle.h
similarity index 90%
rename from src/BODY/pair_body.h
rename to src/BODY/pair_body_nparticle.h
index 94fbdf34dffd12000165d4f0e936bc64dcc5ae00..9c7d832b64bcacf7fa61baaa0b3ca917f9cbd4ce 100644
--- a/src/BODY/pair_body.h
+++ b/src/BODY/pair_body_nparticle.h
@@ -13,21 +13,21 @@
 
 #ifdef PAIR_CLASS
 
-PairStyle(body,PairBody)
+PairStyle(body/nparticle,PairBodyNparticle)
 
 #else
 
-#ifndef LMP_PAIR_BODY_H
-#define LMP_PAIR_BODY_H
+#ifndef LMP_PAIR_BODY_NPARTICLE_H
+#define LMP_PAIR_BODY_NPARTICLE_H
 
 #include "pair.h"
 
 namespace LAMMPS_NS {
 
-class PairBody : public Pair {
+class PairBodyNparticle : public Pair {
  public:
-  PairBody(class LAMMPS *);
-  ~PairBody();
+  PairBodyNparticle(class LAMMPS *);
+  ~PairBodyNparticle();
   void compute(int, int);
   void settings(int, char **);
   void coeff(int, char **);
diff --git a/src/BODY/pair_body_rounded_polygon.cpp b/src/BODY/pair_body_rounded_polygon.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..14ef70f476061f1240dad92b7e694e6aa1f5957c
--- /dev/null
+++ b/src/BODY/pair_body_rounded_polygon.cpp
@@ -0,0 +1,1380 @@
+/* ----------------------------------------------------------------------
+   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: Trung Dac Nguyen (ndactrung@gmail.com)
+   Ref: Fraige, Langston, Matchett and Dodds, Particuology 2008, 6:455-466
+   Note: The current implementation has not taken into account
+         the contact history for friction forces.
+------------------------------------------------------------------------- */
+
+#include <cmath>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include "pair_body_rounded_polygon.h"
+#include "math_extra.h"
+#include "atom.h"
+#include "atom_vec_body.h"
+#include "body_rounded_polygon.h"
+#include "comm.h"
+#include "force.h"
+#include "fix.h"
+#include "modify.h"
+#include "neighbor.h"
+#include "neigh_list.h"
+#include "memory.h"
+#include "error.h"
+
+using namespace LAMMPS_NS;
+
+#define DELTA 10000
+#define EPSILON 1e-3
+#define MAX_CONTACTS 4  // maximum number of contacts for 2D models
+#define EFF_CONTACTS 2  // effective contacts for 2D models
+
+//#define _CONVEX_POLYGON
+//#define _POLYGON_DEBUG
+
+enum {INVALID=0,NONE=1,VERTEXI=2,VERTEXJ=3,EDGE=4};
+
+/* ---------------------------------------------------------------------- */
+
+PairBodyRoundedPolygon::PairBodyRoundedPolygon(LAMMPS *lmp) : Pair(lmp)
+{
+  dmax = nmax = 0;
+  discrete = NULL;
+  dnum = dfirst = NULL;
+
+  edmax = ednummax = 0;
+  edge = NULL;
+  ednum = edfirst = NULL;
+
+  enclosing_radius = NULL;
+  rounded_radius = NULL;
+  maxerad = NULL;
+
+  single_enable = 0;
+  restartinfo = 0;
+
+  c_n = 0.1;
+  c_t = 0.2;
+  mu = 0.0;
+  delta_ua = 1.0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+PairBodyRoundedPolygon::~PairBodyRoundedPolygon()
+{
+  memory->destroy(discrete);
+  memory->destroy(dnum);
+  memory->destroy(dfirst);
+
+  memory->destroy(edge);
+  memory->destroy(ednum);
+  memory->destroy(edfirst);
+
+  memory->destroy(enclosing_radius);
+  memory->destroy(rounded_radius);
+
+  if (allocated) {
+    memory->destroy(setflag);
+    memory->destroy(cutsq);
+
+    memory->destroy(k_n);
+    memory->destroy(k_na);
+    memory->destroy(maxerad);
+  }
+}
+
+/* ---------------------------------------------------------------------- */
+
+void PairBodyRoundedPolygon::compute(int eflag, int vflag)
+{
+  int i,j,ii,jj,inum,jnum,itype,jtype;
+  int ni,nj,npi,npj,ifirst,jfirst;
+  int nei,nej,iefirst,jefirst;
+  double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fx,fy,fz;
+  double rsq,rsqinv,r,radi,radj,eradi,eradj,rradi,rradj,k_nij,k_naij;
+  double xi[3],xj[3],fi[3],fj[3],ti[3],tj[3],facc[3];
+  double *dxi,*dxj;
+  int *ilist,*jlist,*numneigh,**firstneigh;
+
+  evdwl = 0.0;
+  if (eflag || vflag) ev_setup(eflag,vflag);
+  else evflag = vflag_fdotr = 0;
+
+  double **x = atom->x;
+  double **v = atom->v;
+  double **f = atom->f;
+  double **torque = atom->torque;
+  double **angmom = atom->angmom;
+  double *radius = atom->radius;
+  tagint* tag = atom->tag;
+  int *body = atom->body;
+  int *type = atom->type;
+  int nlocal = atom->nlocal;
+  int nall = nlocal + atom->nghost;
+  int newton_pair = force->newton_pair;
+
+  inum = list->inum;
+  ilist = list->ilist;
+  numneigh = list->numneigh;
+  firstneigh = list->firstneigh;
+
+  // grow the per-atom lists if necessary and initialize
+
+  if (atom->nmax > nmax) {
+    memory->destroy(dnum);
+    memory->destroy(dfirst);
+    memory->destroy(ednum);
+    memory->destroy(edfirst);
+    memory->destroy(enclosing_radius);
+    memory->destroy(rounded_radius);
+    nmax = atom->nmax;
+    memory->create(dnum,nmax,"pair:dnum");
+    memory->create(dfirst,nmax,"pair:dfirst");
+    memory->create(ednum,nmax,"pair:ednum");
+    memory->create(edfirst,nmax,"pair:edfirst");
+    memory->create(enclosing_radius,nmax,"pair:enclosing_radius");
+    memory->create(rounded_radius,nmax,"pair:rounded_radius");
+  }
+
+  ndiscrete = nedge = 0;
+  for (i = 0; i < nall; i++)
+    dnum[i] = ednum[i] = 0;
+
+  // loop over neighbors of my atoms
+
+  for (ii = 0; ii < inum; ii++) {
+    i = ilist[ii];
+    xtmp = x[i][0];
+    ytmp = x[i][1];
+    ztmp = x[i][2];
+    itype = type[i];
+    radi = radius[i];
+    jlist = firstneigh[i];
+    jnum = numneigh[i];
+
+    if (body[i] >= 0) {
+      if (dnum[i] == 0) body2space(i);
+      npi = dnum[i];
+      ifirst = dfirst[i];
+      nei = ednum[i];
+      iefirst = edfirst[i];
+      eradi = enclosing_radius[i];
+      rradi = rounded_radius[i];
+    }
+
+    for (jj = 0; jj < jnum; jj++) {
+      j = jlist[jj];
+      j &= NEIGHMASK;
+
+      delx = xtmp - x[j][0];
+      dely = ytmp - x[j][1];
+      delz = ztmp - x[j][2];
+      rsq = delx*delx + dely*dely + delz*delz;
+      jtype = type[j];
+      radj = radius[j];
+
+      // body/body interactions
+
+      evdwl = 0.0;
+      facc[0] = facc[1] = facc[2] = 0;
+
+      if (body[i] < 0 || body[j] < 0) continue;
+
+      if (dnum[j] == 0) body2space(j);
+      npj = dnum[j];
+      jfirst = dfirst[j];
+      nej = ednum[j];
+      jefirst = edfirst[j];
+      eradj = enclosing_radius[j];
+      rradj = rounded_radius[j];
+
+      k_nij = k_n[itype][jtype];
+      k_naij = k_na[itype][jtype];
+
+      // no interaction
+
+      r = sqrt(rsq);
+      if (r > radi + radj + cut_inner) continue;
+      rsqinv = 1.0 / rsq;
+
+      if (npi == 1 && npj == 1) {
+        sphere_against_sphere(i, j, delx, dely, delz, rsq,
+                            k_nij, k_naij, x, v, f, evflag);
+        continue;
+      }
+
+      // reset vertex and edge forces
+
+      for (ni = 0; ni < npi; ni++) {
+        discrete[ifirst+ni][3] = 0;
+        discrete[ifirst+ni][4] = 0;
+        discrete[ifirst+ni][5] = 0;
+      }
+
+      for (nj = 0; nj < npj; nj++) {
+        discrete[jfirst+nj][3] = 0;
+        discrete[jfirst+nj][4] = 0;
+        discrete[jfirst+nj][5] = 0;
+      }
+
+      for (ni = 0; ni < nei; ni++) {
+        edge[iefirst+ni][2] = 0;
+        edge[iefirst+ni][3] = 0;
+        edge[iefirst+ni][4] = 0;
+      }
+
+      for (nj = 0; nj < nej; nj++) {
+        edge[jefirst+nj][2] = 0;
+        edge[jefirst+nj][3] = 0;
+        edge[jefirst+nj][4] = 0;
+      }
+
+      int interact, num_contacts, done;
+      double delta_a, j_a;
+      Contact contact_list[MAX_CONTACTS];
+
+      num_contacts = 0;
+
+      // check interaction between i's vertices and j' edges
+
+      interact = vertex_against_edge(i, j, k_nij, k_naij,
+                                     x, f, torque, tag, contact_list,
+                                     num_contacts, evdwl, facc);
+
+      // check interaction between j's vertices and i' edges
+
+      interact = vertex_against_edge(j, i, k_nij, k_naij,
+                                     x, f, torque, tag, contact_list,
+                                     num_contacts, evdwl, facc);
+
+      if (num_contacts >= 2) {
+
+        // find the first two distinct contacts
+
+        done = 0;
+        for (int m = 0; m < num_contacts-1; m++) {
+          for (int n = m+1; n < num_contacts; n++) {
+            delta_a = contact_separation(contact_list[m], contact_list[n]);
+            if (delta_a > 0) {
+              j_a = delta_a / (EFF_CONTACTS * delta_ua);
+              if (j_a < 1.0) j_a = 1.0;
+
+              // scale the force at both contacts
+
+              contact_forces(contact_list[m], j_a, x, v, angmom, f, torque, 
+                             evdwl, facc);
+              contact_forces(contact_list[n], j_a, x, v, angmom, f, torque, 
+                             evdwl, facc);
+              done = 1;
+
+              #ifdef _POLYGON_DEBUG
+              printf("  Two separate contacts %d and %d: delta_a = %f; j_a = %f\n",
+                m, n, delta_a, j_a);
+              printf("    %d: vertex %d of body %d and edge %d of body %d; "
+                     "xv = %f %f %f; xe = %f %f %f\n",
+                     m, contact_list[m].vertex, contact_list[m].ibody,
+                     contact_list[m].edge, contact_list[m].jbody,
+                     contact_list[m].xv[0], contact_list[m].xv[1], 
+                     contact_list[m].xv[2], contact_list[m].xe[0], 
+                     contact_list[m].xe[1], contact_list[m].xe[2]);
+              printf("    %d: vertex %d of body %d and edge %d of body %d; "
+                     "xv = %f %f %f; xe = %f %f %f\n",
+                     n, contact_list[n].vertex, contact_list[n].ibody,
+                     contact_list[n].edge, contact_list[n].jbody,
+                     contact_list[n].xv[0], contact_list[n].xv[1], 
+                     contact_list[n].xv[2], contact_list[n].xe[0], 
+                     contact_list[n].xe[1], contact_list[n].xe[2]);
+              #endif
+
+              break;
+            }
+          }
+          if (done == 1) break;
+        }
+
+
+      } else if (num_contacts == 1) {
+
+        // if there's only one contact, it should be handled here
+        // since forces/torques have not been accumulated from vertex2edge()
+
+        contact_forces(contact_list[0], 1.0, x, v, angmom, f, torque, evdwl, facc);
+
+        #ifdef _POLYGON_DEBUG
+        printf("One contact between vertex %d of body %d and edge %d of body %d:\n",
+                contact_list[0].vertex, tag[contact_list[0].ibody],
+                contact_list[0].edge, tag[contact_list[0].jbody]);
+        printf("xv = %f %f %f; xe = %f %f %f\n",
+               contact_list[0].xv[0], contact_list[0].xv[1], contact_list[0].xv[2],
+               contact_list[0].xe[0], contact_list[0].xe[1], contact_list[0].xe[2]);
+        #endif
+      }
+
+      #ifdef _POLYGON_DEBUG
+      int num_overlapping_contacts = 0;
+      for (int m = 0; m < num_contacts-1; m++) {
+        for (int n = m+1; n < num_contacts; n++) {
+          double l = contact_separation(contact_list[m], contact_list[n]);
+          if (l < EPSILON) num_overlapping_contacts++;
+        }
+      }
+      printf("There are %d contacts detected, %d of which overlap.\n",
+             num_contacts, num_overlapping_contacts);
+      #endif
+
+      if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair,evdwl,0.0,
+                               facc[0],facc[1],facc[2],delx,dely,delz);
+
+    } // end for jj
+  }
+
+  if (vflag_fdotr) virial_fdotr_compute();
+}
+
+/* ----------------------------------------------------------------------
+   allocate all arrays
+------------------------------------------------------------------------- */
+
+void PairBodyRoundedPolygon::allocate()
+{
+  allocated = 1;
+  int n = atom->ntypes;
+
+  memory->create(setflag,n+1,n+1,"pair:setflag");
+  for (int i = 1; i <= n; i++)
+    for (int j = i; j <= n; j++)
+      setflag[i][j] = 0;
+
+  memory->create(cutsq,n+1,n+1,"pair:cutsq");
+
+  memory->create(k_n,n+1,n+1,"pair:k_n");
+  memory->create(k_na,n+1,n+1,"pair:k_na");
+  memory->create(maxerad,n+1,"pair:maxerad");
+}
+
+/* ----------------------------------------------------------------------
+   global settings
+------------------------------------------------------------------------- */
+
+void PairBodyRoundedPolygon::settings(int narg, char **arg)
+{
+  if (narg < 5) error->all(FLERR,"Illegal pair_style command");
+
+  c_n = force->numeric(FLERR,arg[0]);
+  c_t = force->numeric(FLERR,arg[1]);
+  mu = force->numeric(FLERR,arg[2]);
+  delta_ua = force->numeric(FLERR,arg[3]);
+  cut_inner = force->numeric(FLERR,arg[4]);
+
+  if (delta_ua < 0) delta_ua = 1;
+}
+
+/* ----------------------------------------------------------------------
+   set coeffs for one or more type pairs
+------------------------------------------------------------------------- */
+
+void PairBodyRoundedPolygon::coeff(int narg, char **arg)
+{
+  if (narg < 4 || narg > 5)
+    error->all(FLERR,"Incorrect args for pair coefficients");
+  if (!allocated) allocate();
+
+  int ilo,ihi,jlo,jhi;
+  force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
+  force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
+
+  double k_n_one = force->numeric(FLERR,arg[2]);
+  double k_na_one = force->numeric(FLERR,arg[3]);
+
+  int count = 0;
+  for (int i = ilo; i <= ihi; i++) {
+    for (int j = MAX(jlo,i); j <= jhi; j++) {
+      k_n[i][j] = k_n_one;
+      k_na[i][j] = k_na_one;
+      setflag[i][j] = 1;
+      count++;
+    }
+  }
+
+  if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
+}
+
+/* ----------------------------------------------------------------------
+   init specific to this pair style
+------------------------------------------------------------------------- */
+
+void PairBodyRoundedPolygon::init_style()
+{
+  avec = (AtomVecBody *) atom->style_match("body");
+  if (!avec) 
+    error->all(FLERR,"Pair body/rounded/polygon requires atom style body");
+  if (strcmp(avec->bptr->style,"rounded/polygon") != 0)
+    error->all(FLERR,"Pair body/rounded/polygon requires "
+               "body style rounded/polygon");
+  bptr = (BodyRoundedPolygon *) avec->bptr;
+
+  if (force->newton_pair == 0)
+    error->all(FLERR,"Pair style body/rounded/polygon requires "
+               "newton pair on");
+
+  if (comm->ghost_velocity == 0)
+    error->all(FLERR,"Pair body/rounded/polygon requires "
+               "ghost atoms store velocity");
+
+  neighbor->request(this);
+
+  // find the maximum enclosing radius for each atom type
+
+  int i, itype;
+  double eradi;
+  int* body = atom->body;
+  int* type = atom->type;
+  int ntypes = atom->ntypes;
+  int nlocal = atom->nlocal;
+
+  if (atom->nmax > nmax) {
+    memory->destroy(dnum);
+    memory->destroy(dfirst);
+    memory->destroy(ednum);
+    memory->destroy(edfirst);
+    memory->destroy(enclosing_radius);
+    memory->destroy(rounded_radius);
+    nmax = atom->nmax;
+    memory->create(dnum,nmax,"pair:dnum");
+    memory->create(dfirst,nmax,"pair:dfirst");
+    memory->create(ednum,nmax,"pair:ednum");
+    memory->create(edfirst,nmax,"pair:edfirst");
+    memory->create(enclosing_radius,nmax,"pair:enclosing_radius");
+    memory->create(rounded_radius,nmax,"pair:rounded_radius");
+  }
+
+  ndiscrete = nedge = 0;
+  for (i = 0; i < nlocal; i++)
+    dnum[i] = ednum[i] = 0;
+
+  double *merad = NULL;
+  memory->create(merad,ntypes+1,"pair:merad");
+  for (i = 1; i <= ntypes; i++)
+    maxerad[i] = merad[i] = 0;
+
+  int ipour;
+  for (ipour = 0; ipour < modify->nfix; ipour++)
+    if (strcmp(modify->fix[ipour]->style,"pour") == 0) break;
+  if (ipour == modify->nfix) ipour = -1;
+
+  int idep;
+  for (idep = 0; idep < modify->nfix; idep++)
+    if (strcmp(modify->fix[idep]->style,"deposit") == 0) break;
+  if (idep == modify->nfix) idep = -1;
+
+  for (i = 1; i <= ntypes; i++) {
+    merad[i] = 0.0;
+    if (ipour >= 0) {
+      itype = i;
+      merad[i] =
+        *((double *) modify->fix[ipour]->extract("radius",itype));
+    }
+    if (idep >= 0) {
+      itype = i;
+      merad[i] =
+        *((double *) modify->fix[idep]->extract("radius",itype));
+    }
+  }
+
+  for (i = 0; i < nlocal; i++) {
+    itype = type[i];
+    if (body[i] >= 0) {
+      if (dnum[i] == 0) body2space(i);
+      eradi = enclosing_radius[i];
+      if (eradi > merad[itype]) merad[itype] = eradi;
+    } else 
+      merad[itype] = 0;
+  }
+
+  MPI_Allreduce(&merad[1],&maxerad[1],ntypes,MPI_DOUBLE,MPI_MAX,world);
+
+  memory->destroy(merad);
+}
+
+/* ----------------------------------------------------------------------
+   init for one type pair i,j and corresponding j,i
+------------------------------------------------------------------------- */
+
+double PairBodyRoundedPolygon::init_one(int i, int j)
+{
+  k_n[j][i] = k_n[i][j];
+  k_na[j][i] = k_na[i][j];
+
+  return (maxerad[i]+maxerad[j]);
+}
+
+/* ----------------------------------------------------------------------
+   convert N sub-particles in body I to space frame using current quaternion
+   store sub-particle space-frame displacements from COM in discrete list
+------------------------------------------------------------------------- */
+
+void PairBodyRoundedPolygon::body2space(int i)
+{
+  int ibonus = atom->body[i];
+  AtomVecBody::Bonus *bonus = &avec->bonus[ibonus];
+  int nsub = bptr->nsub(bonus);
+  double *coords = bptr->coords(bonus);
+  int body_num_edges = bptr->nedges(bonus);
+  double* edge_ends = bptr->edges(bonus);
+  double eradius = bptr->enclosing_radius(bonus);
+  double rradius = bptr->rounded_radius(bonus);
+
+  // get the number of sub-particles (vertices)
+  // and the index of the first vertex of my body in the list
+
+  dnum[i] = nsub;
+  dfirst[i] = ndiscrete;
+
+  // grow the vertex list if necessary
+  // the first 3 columns are for coords, the last 3 for forces
+
+  if (ndiscrete + nsub > dmax) {
+    dmax += DELTA;
+    memory->grow(discrete,dmax,6,"pair:discrete");
+  }
+
+  double p[3][3];
+  MathExtra::quat_to_mat(bonus->quat,p);
+
+  for (int m = 0; m < nsub; m++) {
+    MathExtra::matvec(p,&coords[3*m],discrete[ndiscrete]);
+    discrete[ndiscrete][3] = 0;
+    discrete[ndiscrete][4] = 0;
+    discrete[ndiscrete][5] = 0;
+    ndiscrete++;
+  }
+
+  // get the number of edges (vertices)
+  // and the index of the first edge of my body in the list
+
+  ednum[i] = body_num_edges;
+  edfirst[i] = nedge;
+
+  // grow the edge list if necessary
+  // the first 2 columns are for vertex indices within body, the last 3 for forces
+
+  if (nedge + body_num_edges > edmax) {
+    edmax += DELTA;
+    memory->grow(edge,edmax,5,"pair:edge");
+  }
+
+  for (int m = 0; m < body_num_edges; m++) {
+    edge[nedge][0] = static_cast<int>(edge_ends[2*m+0]);
+    edge[nedge][1] = static_cast<int>(edge_ends[2*m+1]);
+    edge[nedge][2] = 0;
+    edge[nedge][3] = 0;
+    edge[nedge][4] = 0;
+    nedge++;
+  }
+
+  enclosing_radius[i] = eradius;
+  rounded_radius[i] = rradius;
+}
+
+/* ----------------------------------------------------------------------
+   Interaction between two spheres with different radii
+   according to the 2D model from Fraige et al.
+---------------------------------------------------------------------- */
+
+void PairBodyRoundedPolygon::sphere_against_sphere(int i, int j,
+                       double delx, double dely, double delz, double rsq,
+                       double k_n, double k_na, double** x, double** v,
+                       double** f, int evflag)
+{
+  double eradi,eradj,rradi,rradj;
+  double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3;
+  double rij,rsqinv,R,fx,fy,fz,fn[3],ft[3],fpair,shift,energy;
+  int nlocal = atom->nlocal;
+  int newton_pair = force->newton_pair;
+
+  eradi = enclosing_radius[i];
+  rradi = rounded_radius[i];
+
+  eradj = enclosing_radius[j];
+  rradj = rounded_radius[j];
+
+  rsqinv = 1.0/rsq;
+  rij = sqrt(rsq);
+  R = rij - (rradi + rradj);
+  shift = k_na * cut_inner;
+
+  energy = 0;
+
+  if (R <= 0) {           // deformation occurs
+    fpair = -k_n * R - shift;
+    energy = (0.5 * k_n * R + shift) * R;
+  } else if (R <= cut_inner) {   // not deforming but cohesive ranges overlap
+    fpair = k_na * R - shift;
+    energy = (-0.5 * k_na * R + shift) * R;
+  } else fpair = 0.0;
+
+  fx = delx*fpair/rij;
+  fy = dely*fpair/rij;
+  fz = delz*fpair/rij;
+
+  if (R <= EPSILON) { // in contact
+
+    // relative translational velocity
+
+    vr1 = v[i][0] - v[j][0];
+    vr2 = v[i][1] - v[j][1];
+    vr3 = v[i][2] - v[j][2];
+
+    // normal component
+
+    vnnr = vr1*delx + vr2*dely + vr3*delz;
+    vn1 = delx*vnnr * rsqinv;
+    vn2 = dely*vnnr * rsqinv;
+    vn3 = delz*vnnr * rsqinv;
+
+    // tangential component
+
+    vt1 = vr1 - vn1;
+    vt2 = vr2 - vn2;
+    vt3 = vr3 - vn3;
+
+    // normal friction term at contact
+
+    fn[0] = -c_n * vn1;
+    fn[1] = -c_n * vn2;
+    fn[2] = -c_n * vn3;
+
+    // tangential friction term at contact
+    // excluding the tangential deformation term
+
+    ft[0] = -c_t * vt1;
+    ft[1] = -c_t * vt2;
+    ft[2] = -c_t * vt3;
+  }
+
+  f[i][0] += fx;
+  f[i][1] += fy;
+  f[i][2] += fz;
+  
+  if (newton_pair || j < nlocal) {
+    f[j][0] -= fx;
+    f[j][1] -= fy;
+    f[j][2] -= fz;
+  }
+
+  if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair,
+                           energy,0.0,fx,fy,fz,delx,dely,delz);
+}
+
+/* ----------------------------------------------------------------------
+   Determine the interaction mode between i's vertices against j's edges
+
+   i = atom i (body i)
+   j = atom j (body j)
+   x      = atoms' coordinates
+   f      = atoms' forces
+   torque = atoms' torques
+   tag    = atoms' tags
+   contact_list = list of contacts
+   num_contacts = number of contacts between i's vertices and j's edges
+   Return:
+     interact = 0 no interaction at all
+                1 there's at least one case where i's vertices interacts
+                  with j's edges
+---------------------------------------------------------------------- */
+
+int PairBodyRoundedPolygon::vertex_against_edge(int i, int j,
+                                                double k_n, double k_na,
+                                                double** x, double** f,
+                                                double** torque, tagint* tag,
+                                                Contact* contact_list,
+                                                int &num_contacts,
+                                                double &evdwl, double* facc)
+{
+  int ni, npi, ifirst, nei, iefirst;
+  int nj, npj, jfirst, nej, jefirst;
+  double xpi[3], xpj[3], dist, eradi, eradj, rradi, rradj;
+  double fx, fy, fz, rx, ry, rz, energy;
+  int interact;
+  int nlocal = atom->nlocal;
+
+  npi = dnum[i];
+  ifirst = dfirst[i];
+  nei = ednum[i];
+  iefirst = edfirst[i];
+  eradi = enclosing_radius[i];
+  rradi = rounded_radius[i];
+
+  npj = dnum[j];
+  jfirst = dfirst[j];
+  nej = ednum[j];
+  jefirst = edfirst[j];
+  eradj = enclosing_radius[j];
+  rradj = rounded_radius[j];
+
+  energy = 0;
+  interact = 0;
+
+  // loop through body i's vertices
+
+  for (ni = 0; ni < npi; ni++) {
+
+    // convert body-fixed coordinates to space-fixed, xi
+
+    xpi[0] = x[i][0] + discrete[ifirst+ni][0];
+    xpi[1] = x[i][1] + discrete[ifirst+ni][1];
+    xpi[2] = x[i][2] + discrete[ifirst+ni][2];
+
+    // compute the distance from the vertex to the COM of body j
+
+    distance(xpi, x[j], dist);
+
+    #ifdef _POLYGON_DEBUG
+    printf("Distance between vertex %d of body %d (%0.1f %0.1f %0.1f) "
+           "to body %d's COM: %f (cut = %0.1f)\n",
+           ni, xpi[0], xpi[1], xpi[2], atom->tag[i], atom->tag[j], dist,
+           eradj + rradi + rradj + cut_inner);
+    #endif
+
+    // the vertex is within the enclosing circle (sphere) of body j,
+    // possibly interacting
+
+    if (dist > eradj + rradj + rradi + cut_inner) continue;
+
+    int mode, contact, p2vertex;
+    double d, R, hi[3], t, delx, dely, delz, fpair, shift;
+    double xj[3], rij;
+
+    // loop through body j's edges
+
+    for (nj = 0; nj < nej; nj++) {
+
+      // compute the distance between the edge nj to the vertex xpi
+
+      mode = compute_distance_to_vertex(j, nj, x[j], rradj,
+                                        xpi, rradi, cut_inner,
+                                        d, hi, t, contact);
+
+      if (mode == INVALID || mode == NONE) continue;
+
+      if (mode == VERTEXI || mode == VERTEXJ) {
+
+        interact = 1;
+
+        // vertex i interacts with a vertex of the edge, but does not contact
+
+        if (mode == VERTEXI) p2vertex = edge[jefirst+nj][0];
+        else if (mode == VERTEXJ) p2vertex = edge[jefirst+nj][1];
+
+        // p2.body2space(p2vertex, xj);
+        xpj[0] = x[j][0] + discrete[jfirst+p2vertex][0];
+        xpj[1] = x[j][1] + discrete[jfirst+p2vertex][1];
+        xpj[2] = x[j][2] + discrete[jfirst+p2vertex][2];
+
+        delx = xpi[0] - xpj[0];
+        dely = xpi[1] - xpj[1];
+        delz = xpi[2] - xpj[2];
+
+        // R = surface separation = rij shifted by the rounded radii
+        // R = rij - (p1.rounded_radius + p2.rounded_radius);
+        // note: the force is defined for R, not for rij
+        // R > rc:     no interaction between vertex ni and p2vertex
+        // 0 < R < rc: cohesion between vertex ni and p2vertex
+        // R < 0:      deformation between vertex ni and p2vertex
+
+        rij = sqrt(delx*delx + dely*dely + delz*delz);
+        R = rij - (rradi + rradj);
+        shift = k_na * cut_inner;
+
+        // the normal frictional term -c_n * vn will be added later
+
+        if (R <= 0) {           // deformation occurs
+          fpair = -k_n * R - shift;
+          energy += (0.5 * k_n * R + shift) * R;
+        } else if (R <= cut_inner) {   // not deforming but cohesive ranges overlap
+          fpair = k_na * R - shift;
+          energy += (-0.5 * k_na * R + shift) * R;
+        } else fpair = 0.0;
+
+        fx = delx*fpair/rij;
+        fy = dely*fpair/rij;
+        fz = delz*fpair/rij;
+
+        #ifdef _POLYGON_DEBUG
+        printf("  Interaction between vertex %d of %d and vertex %d of %d:",
+               ni, tag[i], p2vertex, tag[j]);
+        printf("    mode = %d; contact = %d; d = %f; rij = %f, t = %f\n",
+               mode, contact, d, rij, t);
+        printf("    R = %f; cut_inner = %f\n", R, cut_inner);
+        printf("    fpair = %f\n", fpair);
+        #endif
+
+        // add forces to body i and body j directly
+        // avoid double counts this pair of vertices
+        // i and j can be either local or ghost atoms (bodies)
+        // probably need more work here when the vertices' interaction
+        // are not symmetric, e.g. j interacts with the edge
+        // consisting of i but in mode = EDGE instead of VERTEX*.
+        // OR, for the time being assume that the edge length is
+        // sufficiently greater than the rounded radius to distinguish
+        // vertex-vertex from vertex-edge contact modes.
+        // Special case: when i is a sphere, also accumulate
+
+        if (tag[i] < tag[j] || npi == 1) {
+
+          f[i][0] += fx;
+          f[i][1] += fy;
+          f[i][2] += fz;
+          sum_torque(x[i], xpi, fx, fy, fz, torque[i]);
+
+          f[j][0] -= fx;
+          f[j][1] -= fy;
+          f[j][2] -= fz;
+          sum_torque(x[j], xpj, -fx, -fy, -fz, torque[j]);
+
+          facc[0] += fx; facc[1] += fy; facc[2] += fz;
+
+          #ifdef _POLYGON_DEBUG
+          printf("    from vertex-vertex: "
+                 "force on vertex %d of body %d: fx %f fy %f fz %f\n"
+                 "      torque body %d: %f %f %f\n"
+                 "      torque body %d: %f %f %f\n", ni, tag[i], fx, fy, fz,
+            tag[i],torque[i][0],torque[i][1],torque[i][2],
+            tag[j],torque[j][0],torque[j][1],torque[j][2]);
+        #endif
+        }
+
+        #ifdef _CONVEX_POLYGON
+        // done with the edges from body j,
+        // given that vertex ni interacts with only one vertex 
+        //   from one edge of body j
+        break;
+        #endif
+
+      } else if (mode == EDGE) {
+
+        interact = 1;
+
+        // vertex i interacts with the edge
+
+        delx = xpi[0] - hi[0];
+        dely = xpi[1] - hi[1];
+        delz = xpi[2] - hi[2];
+
+        // R = surface separation = d shifted by the rounded radii
+        // R = d - (p1.rounded_radius + p2.rounded_radius);
+        // Note: the force is defined for R, not for d
+        // R > rc:     no interaction between vertex i and edge j
+        // 0 < R < rc: cohesion between vertex i and edge j
+        // R < 0:      deformation between vertex i and edge j
+        // rij = sqrt(delx*delx + dely*dely + delz*delz);
+
+        R = d - (rradi + rradj);
+        shift = k_na * cut_inner;
+
+        // the normal frictional term -c_n * vn will be added later
+
+        if (R <= 0) {           // deformation occurs
+          fpair = -k_n * R - shift;
+          energy += (0.5 * k_n * R + shift) * R;
+        } else if (R <= cut_inner) {   // not deforming but cohesive ranges overlap
+          fpair = k_na * R - shift;
+          energy += (-0.5 * k_na * R + shift) * R;
+        } else fpair = 0.0;
+
+        fx = delx*fpair/d;
+        fy = dely*fpair/d;
+        fz = delz*fpair/d;
+
+        #ifdef _POLYGON_DEBUG
+        printf("  Interaction between vertex %d of %d and edge %d of %d:",
+               ni, tag[i], nj, tag[j]);
+        printf("    mode = %d; contact = %d; d = %f; t = %f\n",
+               mode, contact, d, t);
+        printf("    R = %f; cut_inner = %f\n", R, cut_inner);
+        printf("    fpair = %f\n", fpair);
+        #endif
+
+        if (contact == 1) {
+
+          // vertex ni of body i contacts with edge nj of body j
+
+          contact_list[num_contacts].ibody = i;
+          contact_list[num_contacts].jbody = j;
+          contact_list[num_contacts].vertex = ni;
+          contact_list[num_contacts].edge = nj;
+          contact_list[num_contacts].xv[0] = xpi[0];
+          contact_list[num_contacts].xv[1] = xpi[1];
+          contact_list[num_contacts].xv[2] = xpi[2];
+          contact_list[num_contacts].xe[0] = hi[0];
+          contact_list[num_contacts].xe[1] = hi[1];
+          contact_list[num_contacts].xe[2] = hi[2];
+          contact_list[num_contacts].separation = R;
+          num_contacts++;
+
+          // store forces to vertex ni and the edge nj
+          // to be rescaled later
+
+          discrete[ifirst+ni][3] = fx;
+          discrete[ifirst+ni][4] = fy;
+          discrete[ifirst+ni][5] = fz;
+
+          edge[jefirst+nj][2] = -fx;
+          edge[jefirst+nj][3] = -fy;
+          edge[jefirst+nj][4] = -fz;
+
+          #ifdef _POLYGON_DEBUG
+          printf("  Stored forces at vertex and edge for accumulating later.\n");
+          #endif
+
+        } else { // no contact
+
+          // accumulate force and torque to both bodies directly
+
+          f[i][0] += fx;
+          f[i][1] += fy;
+          f[i][2] += fz;
+          sum_torque(x[i], xpi, fx, fy, fz, torque[i]);
+
+          f[j][0] -= fx;
+          f[j][1] -= fy;
+          f[j][2] -= fz;
+          sum_torque(x[j], hi, -fx, -fy, -fz, torque[j]);
+
+          facc[0] += fx; facc[1] += fy; facc[2] += fz;
+
+          #ifdef _POLYGON_DEBUG
+          printf("    from vertex-edge, no contact: "
+                 "force on vertex %d of body %d: fx %f fy %f fz %f\n"
+                 "      torque body %d: %f %f %f\n"
+                 "      torque body %d: %f %f %f\n", ni, tag[i], fx, fy, fz,
+                 tag[i],torque[i][0],torque[i][1],torque[i][2],
+                 tag[j],torque[j][0],torque[j][1],torque[j][2]);
+          #endif
+        } // end if contact
+
+        #ifdef _CONVEX_POLYGON
+        // done with the edges from body j,
+        // given that vertex ni interacts with only one edge from body j
+        break;
+        #endif
+      } // end if mode
+
+    } // end for looping through the edges of body j
+
+  } // end for looping through the vertices of body i
+
+  evdwl += energy;
+
+  return interact;
+}
+
+/* -------------------------------------------------------------------------
+  Compute the distance between an edge of body i and a vertex from
+  another body
+  Input:
+    ibody      = body i (i.e. atom i)
+    edge_index = edge index of body i
+    xmi        = atom i's coordinates (body i's center of mass)
+    x0         = coordinate of the tested vertex from another body
+    x0_rounded_radius = rounded radius of the tested vertex
+    cut_inner  = cutoff for vertex-vertex and vertex-edge interaction
+  Output:
+    d          = Distance from a point x0 to an edge
+    hi         = coordinates of the projection of x0 on the edge
+    t          = ratio to determine the relative position of hi
+                 wrt xi and xj on the segment
+  contact      = 0 no contact between the queried vertex and the edge
+                 1 contact detected
+  return
+    INVALID if the edge index is invalid
+    NONE    if there is no interaction
+    VERTEXI if the tested vertex interacts with the first vertex of the edge
+    VERTEXJ if the tested vertex interacts with the second vertex of the edge
+    EDGE    if the tested vertex interacts with the edge
+------------------------------------------------------------------------- */
+
+int PairBodyRoundedPolygon::compute_distance_to_vertex(int ibody,
+                                                int edge_index,
+                                                double *xmi,
+                                                double rounded_radius,
+                                                double* x0,
+                                                double x0_rounded_radius,
+                                                double cut_inner,
+                                                double &d,
+                                                double hi[3],
+                                                double &t,
+                                                int &contact)
+{
+  if (edge_index >= ednum[ibody]) return INVALID;
+
+  int mode,ifirst,iefirst,npi1,npi2;
+  double xi1[3],xi2[3],u[3],v[3],uij[3];
+  double udotv, magv, magucostheta;
+  double delx,dely,delz;
+
+  ifirst = dfirst[ibody];
+  iefirst = edfirst[ibody];
+  npi1 = static_cast<int>(edge[iefirst+edge_index][0]);
+  npi2 = static_cast<int>(edge[iefirst+edge_index][1]);
+
+  // compute the space-fixed coordinates for the vertices of the edge
+
+  xi1[0] = xmi[0] + discrete[ifirst+npi1][0];
+  xi1[1] = xmi[1] + discrete[ifirst+npi1][1];
+  xi1[2] = xmi[2] + discrete[ifirst+npi1][2];
+
+  xi2[0] = xmi[0] + discrete[ifirst+npi2][0];
+  xi2[1] = xmi[1] + discrete[ifirst+npi2][1];
+  xi2[2] = xmi[2] + discrete[ifirst+npi2][2];
+
+  // u = x0 - xi1
+
+  u[0] = x0[0] - xi1[0];
+  u[1] = x0[1] - xi1[1];
+  u[2] = x0[2] - xi1[2];
+
+  // v = xi2 - xi1
+
+  v[0] = xi2[0] - xi1[0];
+  v[1] = xi2[1] - xi1[1];
+  v[2] = xi2[2] - xi1[2];
+
+  // dot product between u and v = magu * magv * costheta
+
+  udotv = u[0] * v[0] + u[1] * v[1] + u[2] * v[2];
+  magv = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
+  magucostheta = udotv / magv;
+
+  // uij is the unit vector pointing from xi to xj
+
+  uij[0] = v[0] / magv;
+  uij[1] = v[1] / magv;
+  uij[2] = v[2] / magv;
+
+  // position of the projection of x0 on the line (xi, xj)
+
+  hi[0] = xi1[0] + magucostheta * uij[0];
+  hi[1] = xi1[1] + magucostheta * uij[1];
+  hi[2] = xi1[2] + magucostheta * uij[2];
+
+  // distance from x0 to the line (xi, xj) = distance from x0 to hi
+
+  distance(hi, x0, d);
+
+  // determine the interaction mode
+  // for 2D: a vertex can interact with one edge at most
+  // for 3D: a vertex can interact with one face at most
+
+  mode = NONE;
+  contact = 0;
+
+  if (d > rounded_radius + x0_rounded_radius + cut_inner) {
+
+    // if the vertex is far away from the edge
+
+    mode = NONE;
+
+  } else {
+
+    // check if x0 (the queried vertex) and xmi (the body's center of mass)
+    // are on the different sides of the edge
+
+    #ifdef _CONVEX_POLYGON
+    int m = opposite_sides(xi1, xi2, x0, xmi);
+    #else
+    int m = 1;
+    #endif
+
+    if (m == 0) {
+
+      // x0 and xmi are on not the opposite sides of the edge
+      // leave xpi for another edge to detect
+
+      mode = NONE;
+
+    } else {
+
+      // x0 and xmi are on the different sides
+      // t is the ratio to detect if x0 is closer to the vertices xi or xj
+
+      if (fabs(xi2[0] - xi1[0]) > EPSILON)
+        t = (hi[0] - xi1[0]) / (xi2[0] - xi1[0]);
+      else if (fabs(xi2[1] - xi1[1]) > EPSILON)
+        t = (hi[1] - xi1[1]) / (xi2[1] - xi1[1]);
+      else if (fabs(xi2[2] - xi1[2]) > EPSILON)
+        t = (hi[2] - xi1[2]) / (xi2[2] - xi1[2]);
+
+      double contact_dist = rounded_radius + x0_rounded_radius;
+      if (t >= 0 && t <= 1) {
+        mode = EDGE;
+        if (d < contact_dist + EPSILON)
+          contact = 1;
+        
+      } else { // t < 0 || t > 1: closer to either vertices of the edge
+
+        if (t < 0) {
+          // measure the distance from x0 to xi1
+          delx = x0[0] - xi1[0];
+          dely = x0[1] - xi1[1];
+          delz = x0[2] - xi1[2];
+          double dx0xi1 = sqrt(delx*delx + dely*dely + delz*delz);
+          if (dx0xi1 > contact_dist + cut_inner)
+            mode = NONE;
+          else
+            mode = VERTEXI;
+        } else {
+          // measure the distance from x0 to xi2
+          delx = x0[0] - xi2[0];
+          dely = x0[1] - xi2[1];
+          delz = x0[2] - xi2[2];
+          double dx0xi2 = sqrt(delx*delx + dely*dely + delz*delz);
+          if (dx0xi2 > contact_dist + cut_inner)
+            mode = NONE;
+          else
+            mode = VERTEXJ;
+        }
+      } // end if t >= 0 && t <= 1
+    } // end if x0 and xmi are on the same side of the edge
+  }
+
+  return mode;
+}
+
+/* ----------------------------------------------------------------------
+  Compute contact forces between two bodies
+  modify the force stored at the vertex and edge in contact by j_a
+  sum forces and torque to the corresponding bodies
+  fn = normal friction component
+  ft = tangential friction component (-c_t * v_t)
+------------------------------------------------------------------------- */
+
+void PairBodyRoundedPolygon::contact_forces(Contact& contact, double j_a,
+                       double** x, double** v, double** angmom, double** f,
+                       double** torque, double &evdwl, double* facc)
+{
+  int ibody,jbody,ibonus,jbonus,ifirst,jefirst,ni,nj;
+  double fx,fy,fz,delx,dely,delz,rsq,rsqinv;
+  double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3;
+  double fn[3],ft[3],vi[3],vj[3];
+  double *quat, *inertia;
+  AtomVecBody::Bonus *bonus;
+
+  ibody = contact.ibody;
+  jbody = contact.jbody;
+
+  // compute the velocity of the vertex in the space-fixed frame
+
+  ibonus = atom->body[ibody];
+  bonus = &avec->bonus[ibonus];
+  quat = bonus->quat;
+  inertia = bonus->inertia;
+  total_velocity(contact.xv, x[ibody], v[ibody], angmom[ibody],
+                 inertia, quat, vi);
+
+  // compute the velocity of the point on the edge in the space-fixed frame
+
+  jbonus = atom->body[jbody];
+  bonus = &avec->bonus[jbonus];
+  quat = bonus->quat;
+  inertia = bonus->inertia;
+  total_velocity(contact.xe, x[jbody], v[jbody], angmom[jbody],
+                 inertia, quat, vj);
+
+  // vector pointing from the vertex to the point on the edge
+
+  delx = contact.xv[0] - contact.xe[0];
+  dely = contact.xv[1] - contact.xe[1];
+  delz = contact.xv[2] - contact.xe[2];
+  rsq = delx*delx + dely*dely + delz*delz;
+  rsqinv = 1.0/rsq;
+
+  // relative translational velocity
+
+  vr1 = vi[0] - vj[0];
+  vr2 = vi[1] - vj[1];
+  vr3 = vi[2] - vj[2];
+
+  // normal component
+
+  vnnr = vr1*delx + vr2*dely + vr3*delz;
+  vn1 = delx*vnnr * rsqinv;
+  vn2 = dely*vnnr * rsqinv;
+  vn3 = delz*vnnr * rsqinv;
+
+  // tangential component
+
+  vt1 = vr1 - vn1;
+  vt2 = vr2 - vn2;
+  vt3 = vr3 - vn3;
+
+  // normal friction term at contact
+
+  fn[0] = -c_n * vn1;
+  fn[1] = -c_n * vn2;
+  fn[2] = -c_n * vn3;
+
+  // tangential friction term at contact
+  // excluding the tangential deformation term for now
+
+  ft[0] = -c_t * vt1;
+  ft[1] = -c_t * vt2;
+  ft[2] = -c_t * vt3;
+
+  // only the cohesive force is scaled by j_a
+  // mu * fne = tangential friction deformation during gross sliding
+  // see Eq. 4, Fraige et al.
+
+  ifirst = dfirst[ibody];
+  ni = contact.vertex;
+
+  fx = discrete[ifirst+ni][3] * j_a + fn[0] + ft[0] +
+    mu * discrete[ifirst+ni][3];
+  fy = discrete[ifirst+ni][4] * j_a + fn[1] + ft[1] +
+    mu * discrete[ifirst+ni][4];
+  fz = discrete[ifirst+ni][5] * j_a + fn[2] + ft[2] +
+    mu * discrete[ifirst+ni][5];
+  f[ibody][0] += fx;
+  f[ibody][1] += fy;
+  f[ibody][2] += fz;
+  sum_torque(x[ibody], contact.xv, fx, fy, fz, torque[ibody]);
+
+  // accumulate forces to the vertex only
+
+  facc[0] += fx; facc[1] += fy; facc[2] += fz;
+
+  // only the cohesive force is scaled by j_a
+  // mu * fne = tangential friction deformation during gross sliding
+  // Eq. 4, Fraige et al.
+
+  jefirst = edfirst[jbody];
+  nj = contact.edge;
+
+  fx = edge[jefirst+nj][2] * j_a - fn[0] - ft[0] +
+    mu * edge[jefirst+nj][2];
+  fy = edge[jefirst+nj][3] * j_a - fn[1] - ft[1] +
+    mu * edge[jefirst+nj][3];
+  fz = edge[jefirst+nj][4] * j_a - fn[2] - ft[2] +
+    mu * edge[jefirst+nj][4];
+  f[jbody][0] += fx;
+  f[jbody][1] += fy;
+  f[jbody][2] += fz;
+  sum_torque(x[jbody], contact.xe, fx, fy, fz, torque[jbody]);
+
+  #ifdef _POLYGON_DEBUG
+  printf("From contact forces: vertex fx %f fy %f fz %f\n"
+         "      torque body %d: %f %f %f\n"
+         "      torque body %d: %f %f %f\n",
+         discrete[ifirst+ni][3], discrete[ifirst+ni][4], discrete[ifirst+ni][5],
+         atom->tag[ibody],torque[ibody][0],torque[ibody][1],torque[ibody][2],
+         atom->tag[jbody],torque[jbody][0],torque[jbody][1],torque[jbody][2]);
+  #endif
+}
+
+/* ----------------------------------------------------------------------
+  Determine the length of the contact segment, i.e. the separation between
+  2 contacts, should be extended for 3D models.
+------------------------------------------------------------------------- */
+
+double PairBodyRoundedPolygon::contact_separation(const Contact& c1,
+                                                  const Contact& c2)
+{
+  double x1 = c1.xv[0];
+  double y1 = c1.xv[1];
+  double x2 = c1.xe[0];
+  double y2 = c1.xe[1];
+  double x3 = c2.xv[0];
+  double y3 = c2.xv[1];
+
+  double delta_a = 0.0;
+  if (fabs(x2 - x1) > EPSILON) {
+    double A = (y2 - y1) / (x2 - x1);
+    delta_a = fabs(y1 - A * x1 - y3 + A * x3) / sqrt(1 + A * A);
+  } else {
+    delta_a = fabs(x1 - x3);
+  }
+
+  return delta_a;
+}
+
+/* ----------------------------------------------------------------------
+  Accumulate torque to body from the force f=(fx,fy,fz) acting at point x
+------------------------------------------------------------------------- */
+
+void PairBodyRoundedPolygon::sum_torque(double* xm, double *x, double fx,
+                                        double fy, double fz, double* torque)
+{
+  double rx = x[0] - xm[0];
+  double ry = x[1] - xm[1];
+  double rz = x[2] - xm[2];
+  double tx = ry * fz - rz * fy;
+  double ty = rz * fx - rx * fz;
+  double tz = rx * fy - ry * fx;
+  torque[0] += tx;
+  torque[1] += ty;
+  torque[2] += tz;
+}
+
+/* ----------------------------------------------------------------------
+  Test if two points a and b are in opposite sides of the line that
+  connects two points x1 and x2
+------------------------------------------------------------------------- */
+
+int PairBodyRoundedPolygon::opposite_sides(double* x1, double* x2,
+                                           double* a, double* b)
+{
+  double m_a = (x1[1] - x2[1])*(a[0] - x1[0]) + (x2[0] - x1[0])*(a[1] - x1[1]);
+  double m_b = (x1[1] - x2[1])*(b[0] - x1[0]) + (x2[0] - x1[0])*(b[1] - x1[1]);
+  // equal to zero when either a or b is inline with the line x1-x2
+  if (m_a * m_b <= 0)
+    return 1;
+  else
+    return 0;
+}
+
+/* ----------------------------------------------------------------------
+  Calculate the total velocity of a point (vertex, a point on an edge):
+    vi = vcm + omega ^ (p - xcm)
+------------------------------------------------------------------------- */
+
+void PairBodyRoundedPolygon::total_velocity(double* p, double *xcm,
+                              double* vcm, double *angmom, double *inertia,
+                              double *quat, double* vi)
+{
+  double r[3],omega[3],ex_space[3],ey_space[3],ez_space[3];
+  r[0] = p[0] - xcm[0];
+  r[1] = p[1] - xcm[1];
+  r[2] = p[2] - xcm[2];
+  MathExtra::q_to_exyz(quat,ex_space,ey_space,ez_space);
+  MathExtra::angmom_to_omega(angmom,ex_space,ey_space,ez_space,
+                             inertia,omega);
+  vi[0] = omega[1]*r[2] - omega[2]*r[1] + vcm[0];
+  vi[1] = omega[2]*r[0] - omega[0]*r[2] + vcm[1];
+  vi[2] = omega[0]*r[1] - omega[1]*r[0] + vcm[2];
+}
+
+/* ---------------------------------------------------------------------- */
+
+void PairBodyRoundedPolygon::distance(const double* x2, const double* x1,
+                                      double& r)
+{
+  r = sqrt((x2[0] - x1[0]) * (x2[0] - x1[0])
+    + (x2[1] - x1[1]) * (x2[1] - x1[1])
+    + (x2[2] - x1[2]) * (x2[2] - x1[2]));
+}
+
diff --git a/src/BODY/pair_body_rounded_polygon.h b/src/BODY/pair_body_rounded_polygon.h
new file mode 100644
index 0000000000000000000000000000000000000000..aabe86270cd621a56836370130532cf42c93be59
--- /dev/null
+++ b/src/BODY/pair_body_rounded_polygon.h
@@ -0,0 +1,137 @@
+/* -*- 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 PAIR_CLASS
+
+PairStyle(body/rounded/polygon,PairBodyRoundedPolygon)
+
+#else
+
+#ifndef LMP_PAIR_BODY_ROUNDED_POLYGON_H
+#define LMP_PAIR_BODY_ROUNDED_POLYGON_H
+
+#include "pair.h"
+
+namespace LAMMPS_NS {
+
+class PairBodyRoundedPolygon : public Pair {
+ public:
+  PairBodyRoundedPolygon(class LAMMPS *);
+  ~PairBodyRoundedPolygon();
+  void compute(int, int);
+  void settings(int, char **);
+  void coeff(int, char **);
+  void init_style();
+  double init_one(int, int);
+
+  struct Contact {
+    int ibody, jbody; // body (i.e. atom) indices (not tags)
+    int vertex;       // vertex of the first polygon
+    int edge;         // edge of the second polygon
+    double xv[3];     // coordinates of the vertex
+    double xe[3];     // coordinates of the projection of the vertex on the edge
+    double separation;// separation at contact
+  };
+
+ protected:
+  double **k_n;       // normal repulsion strength
+  double **k_na;      // normal attraction strength
+  double c_n;         // normal damping coefficient
+  double c_t;         // tangential damping coefficient
+  double mu;          // normal friction coefficient during gross sliding
+  double delta_ua;    // contact line (area for 3D models) modification factor
+  double cut_inner;   // cutoff for interaction between vertex-edge surfaces
+
+  class AtomVecBody *avec;
+  class BodyRoundedPolygon *bptr;
+
+  double **discrete;  // list of all sub-particles for all bodies
+  int ndiscrete;      // number of discretes in list
+  int dmax;           // allocated size of discrete list
+  int *dnum;          // number of discretes per line, 0 if uninit
+  int *dfirst;        // index of first discrete per each line
+  int nmax;           // allocated size of dnum,dfirst vectors
+
+  double **edge;      // list of all edge for all bodies
+  int nedge;          // number of edge in list
+  int edmax;          // allocated size of edge list
+  int *ednum;         // number of edges per line, 0 if uninit
+  int *edfirst;       // index of first edge per each line
+  int ednummax;       // allocated size of ednum,edfirst vectors
+
+  double *enclosing_radius; // enclosing radii for all bodies
+  double *rounded_radius;   // rounded radii for all bodies
+  double *maxerad;          // per-type maximum enclosing radius
+
+  void allocate();
+  void body2space(int);
+
+  // sphere-sphere interaction
+  void sphere_against_sphere(int i, int j, double delx, double dely, double delz,
+                             double rsq, double k_n, double k_na,
+                             double** x, double** v, double** f, int evflag);
+  // vertex-edge interaction
+  int vertex_against_edge(int i, int j, double k_n, double k_na,
+                          double** x, double** f, double** torque,
+                          tagint* tag, Contact* contact_list,
+                          int &num_contacts, double &evdwl, double* facc);
+  // compute distance between a point and an edge from another body
+  int compute_distance_to_vertex(int ibody, int edge_index, double* xmi,
+                                 double rounded_radius, double* x0,
+                                 double x0_rounded_radius, double cut_inner,
+                                 double &d, double hi[3], double &t,
+                                 int &contact);
+  // compute contact forces if contact points are detected
+  void contact_forces(Contact& contact, double j_a,
+                      double** x, double** v, double** angmom, double** f,
+                      double** torque, double &evdwl, double* facc);
+
+  // compute the separation between two contacts
+  double contact_separation(const Contact& c1, const Contact& c2);
+
+  // accumulate torque to a body given a force at a given point
+  void sum_torque(double* xm, double *x, double fx,
+                  double fy, double fz, double* torque);
+  // helper functions
+  int opposite_sides(double* x1, double* x2, double* a, double* b);
+  void total_velocity(double* p, double *xcm, double* vcm, double *angmom,
+                      double *inertia, double *quat, double* vi);
+  inline void distance(const double* x2, const double* x1, double& r);
+};
+
+}
+
+#endif
+#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: Incorrect args for pair coefficients
+
+Self-explanatory.  Check the input script or data file.
+
+E: Pair body/rounded/polygon requires atom style body rounded/polygon
+
+Self-explanatory.
+
+E: Pair body requires body style rounded/polygon
+
+This pair style is specific to the rounded/polygon body style.
+
+*/
diff --git a/src/BODY/pair_body_rounded_polyhedron.cpp b/src/BODY/pair_body_rounded_polyhedron.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2ff209d609bf1d5f31f82ddf0c6b3063949b5e2e
--- /dev/null
+++ b/src/BODY/pair_body_rounded_polyhedron.cpp
@@ -0,0 +1,2386 @@
+/* ----------------------------------------------------------------------
+   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: Trung Dac Nguyen (ndactrung@gmail.com)
+   Ref: Wang, Yu, Langston, Fraige, Particle shape effects in discrete
+   element modelling of cohesive angular particles, Granular Matter 2011,
+   13:1-12.
+   Note: The current implementation has not taken into account
+         the contact history for friction forces.
+------------------------------------------------------------------------- */
+
+#include <cmath>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include "pair_body_rounded_polyhedron.h"
+#include "math_extra.h"
+#include "atom.h"
+#include "atom_vec_body.h"
+#include "body_rounded_polyhedron.h"
+#include "comm.h"
+#include "force.h"
+#include "fix.h"
+#include "modify.h"
+#include "neighbor.h"
+#include "neigh_list.h"
+#include "memory.h"
+#include "error.h"
+#include "math_extra.h"
+#include "math_const.h"
+
+using namespace LAMMPS_NS;
+using namespace MathExtra;
+using namespace MathConst;
+
+#define DELTA 10000
+#define EPSILON 1e-3
+#define MAX_FACE_SIZE 4  // maximum number of vertices per face (same as BodyRoundedPolyhedron)
+#define MAX_CONTACTS 32  // for 3D models (including duplicated counts)
+
+//#define _POLYHEDRON_DEBUG
+
+enum {EE_INVALID=0,EE_NONE,EE_INTERACT};
+enum {EF_INVALID=0,EF_NONE,EF_PARALLEL,EF_SAME_SIDE_OF_FACE,
+      EF_INTERSECT_INSIDE,EF_INTERSECT_OUTSIDE};
+
+/* ---------------------------------------------------------------------- */
+
+PairBodyRoundedPolyhedron::PairBodyRoundedPolyhedron(LAMMPS *lmp) : Pair(lmp)
+{
+  dmax = nmax = 0;
+  discrete = NULL;
+  dnum = dfirst = NULL;
+
+  edmax = ednummax = 0;
+  edge = NULL;
+  ednum = edfirst = NULL;
+
+  facmax = facnummax = 0;
+  face = NULL;
+  facnum = facfirst = NULL;
+
+  enclosing_radius = NULL;
+  rounded_radius = NULL;
+  maxerad = NULL;
+
+  single_enable = 0;
+  restartinfo = 0;
+
+  c_n = 0.1;
+  c_t = 0.2;
+  mu = 0.0;
+  A_ua = 1.0;
+
+  k_n = NULL;
+  k_na = NULL;
+}
+
+/* ---------------------------------------------------------------------- */
+
+PairBodyRoundedPolyhedron::~PairBodyRoundedPolyhedron()
+{
+  memory->destroy(discrete);
+  memory->destroy(dnum);
+  memory->destroy(dfirst);
+
+  memory->destroy(edge);
+  memory->destroy(ednum);
+  memory->destroy(edfirst);
+
+  memory->destroy(face);
+  memory->destroy(facnum);
+  memory->destroy(facfirst);
+
+  memory->destroy(enclosing_radius);
+  memory->destroy(rounded_radius);
+  memory->destroy(maxerad);
+
+  if (allocated) {
+    memory->destroy(setflag);
+    memory->destroy(cutsq);
+
+    memory->destroy(k_n);
+    memory->destroy(k_na);
+  }
+}
+
+/* ---------------------------------------------------------------------- */
+
+void PairBodyRoundedPolyhedron::compute(int eflag, int vflag)
+{
+  int i,j,ii,jj,inum,jnum,itype,jtype;
+  int ni,nj,npi,npj,ifirst,jfirst,nei,nej,iefirst,jefirst;
+  double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,facc[3];
+  double rsq,eradi,eradj;
+  int *ilist,*jlist,*numneigh,**firstneigh;
+
+  evdwl = 0.0;
+  if (eflag || vflag) ev_setup(eflag,vflag);
+  else evflag = vflag_fdotr = 0;
+
+  double **x = atom->x;
+  double **v = atom->v;
+  double **f = atom->f;
+  double **torque = atom->torque;
+  double **angmom = atom->angmom;
+  int *body = atom->body;
+  int *type = atom->type;
+  int nlocal = atom->nlocal;
+  int nall = nlocal + atom->nghost;
+  int newton_pair = force->newton_pair;
+
+  inum = list->inum;
+  ilist = list->ilist;
+  numneigh = list->numneigh;
+  firstneigh = list->firstneigh;
+
+  // grow the per-atom lists if necessary and initialize
+
+  if (atom->nmax > nmax) {
+    memory->destroy(dnum);
+    memory->destroy(dfirst);
+    memory->destroy(ednum);
+    memory->destroy(edfirst);
+    memory->destroy(facnum);
+    memory->destroy(facfirst);
+    memory->destroy(enclosing_radius);
+    memory->destroy(rounded_radius);
+    nmax = atom->nmax;
+    memory->create(dnum,nmax,"pair:dnum");
+    memory->create(dfirst,nmax,"pair:dfirst");
+    memory->create(ednum,nmax,"pair:ednum");
+    memory->create(edfirst,nmax,"pair:edfirst");
+    memory->create(facnum,nmax,"pair:facnum");
+    memory->create(facfirst,nmax,"pair:facfirst");
+    memory->create(enclosing_radius,nmax,"pair:enclosing_radius");
+    memory->create(rounded_radius,nmax,"pair:rounded_radius");
+  }
+
+  ndiscrete = nedge = nface = 0;
+  for (i = 0; i < nall; i++)
+    dnum[i] = ednum[i] = facnum[i] = 0;
+
+  // loop over neighbors of my atoms
+
+  for (ii = 0; ii < inum; ii++) {
+    i = ilist[ii];
+    xtmp = x[i][0];
+    ytmp = x[i][1];
+    ztmp = x[i][2];
+    itype = type[i];
+    jlist = firstneigh[i];
+    jnum = numneigh[i];
+
+    if (body[i] >= 0) {
+      if (dnum[i] == 0) body2space(i);
+      npi = dnum[i];
+      ifirst = dfirst[i];
+      nei = ednum[i];
+      iefirst = edfirst[i];
+      eradi = enclosing_radius[i];
+     }
+
+    for (jj = 0; jj < jnum; jj++) {
+      j = jlist[jj];
+      j &= NEIGHMASK;
+
+      delx = xtmp - x[j][0];
+      dely = ytmp - x[j][1];
+      delz = ztmp - x[j][2];
+      rsq = delx*delx + dely*dely + delz*delz;
+      jtype = type[j];
+
+      // body/body interactions
+
+      evdwl = 0.0;
+      facc[0] = facc[1] = facc[2] = 0;
+
+      if (body[i] < 0 || body[j] < 0) continue;
+
+      if (dnum[j] == 0) body2space(j);
+      npj = dnum[j];
+      jfirst = dfirst[j];
+      nej = ednum[j];
+      jefirst = edfirst[j];
+      eradj = enclosing_radius[j];
+
+      // no interaction
+
+      double r = sqrt(rsq);
+      if (r > eradi + eradj + cut_inner) continue;
+
+      // sphere-sphere interaction
+
+      if (npi == 1 && npj == 1) {
+        sphere_against_sphere(i, j, itype, jtype, delx, dely, delz,
+                              rsq, v, f, evflag);
+        continue;
+      }
+
+      // reset vertex and edge forces
+
+      for (ni = 0; ni < npi; ni++) {
+        discrete[ifirst+ni][3] = 0;
+        discrete[ifirst+ni][4] = 0;
+        discrete[ifirst+ni][5] = 0;
+        discrete[ifirst+ni][6] = 0;
+      }
+
+      for (nj = 0; nj < npj; nj++) {
+        discrete[jfirst+nj][3] = 0;
+        discrete[jfirst+nj][4] = 0;
+        discrete[jfirst+nj][5] = 0;
+        discrete[jfirst+nj][6] = 0;
+      }
+
+      for (ni = 0; ni < nei; ni++) {
+        edge[iefirst+ni][2] = 0;
+        edge[iefirst+ni][3] = 0;
+        edge[iefirst+ni][4] = 0;
+        edge[iefirst+ni][5] = 0;
+      }
+
+      for (nj = 0; nj < nej; nj++) {
+        edge[jefirst+nj][2] = 0;
+        edge[jefirst+nj][3] = 0;
+        edge[jefirst+nj][4] = 0;
+        edge[jefirst+nj][5] = 0;
+      }
+
+      // one of the two bodies is a sphere
+
+      if (npj == 1) {
+        sphere_against_face(i, j, itype, jtype, x, v, f, torque,
+                            angmom, evflag);
+        sphere_against_edge(i, j, itype, jtype, x, v, f, torque,
+                            angmom, evflag);
+        continue;
+      } else if (npi == 1) {
+        sphere_against_face(j, i, jtype, itype, x, v, f, torque,
+                            angmom, evflag);
+        sphere_against_edge(j, i, jtype, itype, x, v, f, torque,
+                            angmom, evflag);
+        continue;
+      }
+
+      int interact, num_contacts;
+      Contact contact_list[MAX_CONTACTS];
+
+      num_contacts = 0;
+
+      // check interaction between i's edges and j' faces
+      #ifdef _POLYHEDRON_DEBUG
+      printf("INTERACTION between edges of %d vs. faces of %d:\n", i, j);
+      #endif 
+      interact = edge_against_face(i, j, itype, jtype, x, contact_list,
+                                   num_contacts, evdwl, facc);
+
+      // check interaction between j's edges and i' faces
+      #ifdef _POLYHEDRON_DEBUG
+      printf("\nINTERACTION between edges of %d vs. faces of %d:\n", j, i);
+      #endif
+      interact = edge_against_face(j, i, jtype, itype, x, contact_list,
+                                   num_contacts, evdwl, facc);
+
+      // check interaction between i's edges and j' edges
+      #ifdef _POLYHEDRON_DEBUG
+      printf("INTERACTION between edges of %d vs. edges of %d:\n", i, j);
+      #endif 
+      interact = edge_against_edge(i, j, itype, jtype, x, contact_list,
+                                   num_contacts, evdwl, facc);
+
+      // estimate the contact area
+      // also consider point contacts and line contacts
+
+      if (num_contacts > 0) {
+        rescale_cohesive_forces(x, f, torque, contact_list, num_contacts,
+                                itype, jtype, facc);
+      }
+
+      if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair,evdwl,0.0,
+                               facc[0],facc[1],facc[2],delx,dely,delz);
+
+    } // end for jj
+  }
+
+  if (vflag_fdotr) virial_fdotr_compute();
+}
+
+/* ----------------------------------------------------------------------
+   allocate all arrays
+------------------------------------------------------------------------- */
+
+void PairBodyRoundedPolyhedron::allocate()
+{
+  allocated = 1;
+  int n = atom->ntypes;
+
+  memory->create(setflag,n+1,n+1,"pair:setflag");
+  for (int i = 1; i <= n; i++)
+    for (int j = i; j <= n; j++)
+      setflag[i][j] = 0;
+
+  memory->create(cutsq,n+1,n+1,"pair:cutsq");
+
+  memory->create(k_n,n+1,n+1,"pair:k_n");
+  memory->create(k_na,n+1,n+1,"pair:k_na");
+  memory->create(maxerad,n+1,"pair:maxerad");
+}
+
+/* ----------------------------------------------------------------------
+   global settings
+------------------------------------------------------------------------- */
+
+void PairBodyRoundedPolyhedron::settings(int narg, char **arg)
+{
+  if (narg < 5) error->all(FLERR,"Illegal pair_style command");
+
+  c_n = force->numeric(FLERR,arg[0]);
+  c_t = force->numeric(FLERR,arg[1]);
+  mu = force->numeric(FLERR,arg[2]);
+  A_ua = force->numeric(FLERR,arg[3]);
+  cut_inner = force->numeric(FLERR,arg[4]);
+
+  if (A_ua < 0) A_ua = 1;
+}
+
+/* ----------------------------------------------------------------------
+   set coeffs for one or more type pairs
+------------------------------------------------------------------------- */
+
+void PairBodyRoundedPolyhedron::coeff(int narg, char **arg)
+{
+  if (narg < 4 || narg > 5)
+    error->all(FLERR,"Incorrect args for pair coefficients");
+  if (!allocated) allocate();
+
+  int ilo,ihi,jlo,jhi;
+  force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
+  force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
+
+  double k_n_one = force->numeric(FLERR,arg[2]);
+  double k_na_one = force->numeric(FLERR,arg[3]);
+
+  int count = 0;
+  for (int i = ilo; i <= ihi; i++) {
+    for (int j = MAX(jlo,i); j <= jhi; j++) {
+      k_n[i][j] = k_n_one;
+      k_na[i][j] = k_na_one;
+      setflag[i][j] = 1;
+      count++;
+    }
+  }
+
+  if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
+}
+
+/* ----------------------------------------------------------------------
+   init specific to this pair style
+------------------------------------------------------------------------- */
+
+void PairBodyRoundedPolyhedron::init_style()
+{
+  avec = (AtomVecBody *) atom->style_match("body");
+  if (!avec) error->all(FLERR,"Pair body/rounded/polyhedron requires "
+                        "atom style body");
+  if (strcmp(avec->bptr->style,"rounded/polyhedron") != 0)
+    error->all(FLERR,"Pair body/rounded/polyhedron requires "
+               "body style rounded/polyhedron");
+  bptr = (BodyRoundedPolyhedron *) avec->bptr;
+
+  if (force->newton_pair == 0)
+    error->all(FLERR,"Pair style body/rounded/polyhedron requires "
+               "newton pair on");
+
+  if (comm->ghost_velocity == 0)
+    error->all(FLERR,"Pair body/rounded/polyhedron requires "
+               "ghost atoms store velocity");
+
+  neighbor->request(this);
+
+  // find the maximum enclosing radius for each atom type
+
+  int i, itype;
+  double eradi;
+  int* body = atom->body;
+  int* type = atom->type;
+  int ntypes = atom->ntypes;
+  int nlocal = atom->nlocal;
+
+  if (atom->nmax > nmax) {
+    memory->destroy(dnum);
+    memory->destroy(dfirst);
+    memory->destroy(ednum);
+    memory->destroy(edfirst);
+    memory->destroy(facnum);
+    memory->destroy(facfirst);
+    memory->destroy(enclosing_radius);
+    memory->destroy(rounded_radius);
+    nmax = atom->nmax;
+    memory->create(dnum,nmax,"pair:dnum");
+    memory->create(dfirst,nmax,"pair:dfirst");
+    memory->create(ednum,nmax,"pair:ednum");
+    memory->create(edfirst,nmax,"pair:edfirst");
+    memory->create(facnum,nmax,"pair:facnum");
+    memory->create(facfirst,nmax,"pair:facfirst");
+    memory->create(enclosing_radius,nmax,"pair:enclosing_radius");
+    memory->create(rounded_radius,nmax,"pair:rounded_radius");
+  }
+
+  ndiscrete = nedge = nface = 0;
+  for (i = 0; i < nlocal; i++)
+    dnum[i] = ednum[i] = facnum[i] = 0;
+
+  double *merad = NULL;
+  memory->create(merad,ntypes+1,"pair:merad");
+  for (i = 1; i <= ntypes; i++)
+    maxerad[i] = merad[i] = 0;
+
+  int ipour;
+  for (ipour = 0; ipour < modify->nfix; ipour++)
+    if (strcmp(modify->fix[ipour]->style,"pour") == 0) break;
+  if (ipour == modify->nfix) ipour = -1;
+
+  int idep;
+  for (idep = 0; idep < modify->nfix; idep++)
+    if (strcmp(modify->fix[idep]->style,"deposit") == 0) break;
+  if (idep == modify->nfix) idep = -1;
+
+  for (i = 1; i <= ntypes; i++) {
+    merad[i] = 0.0;
+    if (ipour >= 0) {
+      itype = i;
+      merad[i] =
+        *((double *) modify->fix[ipour]->extract("radius",itype));
+    }
+    if (idep >= 0) {
+      itype = i;
+      merad[i] =
+        *((double *) modify->fix[idep]->extract("radius",itype));
+    }
+  }
+
+  for (i = 0; i < nlocal; i++) {
+    itype = type[i];
+    if (body[i] >= 0) {
+      if (dnum[i] == 0) body2space(i);
+      eradi = enclosing_radius[i];
+      if (eradi > merad[itype]) merad[itype] = eradi;
+    } else 
+      merad[itype] = 0;
+  }
+
+  MPI_Allreduce(&merad[1],&maxerad[1],ntypes,MPI_DOUBLE,MPI_MAX,world);
+
+  memory->destroy(merad);
+
+  sanity_check();
+}
+
+/* ----------------------------------------------------------------------
+   init for one type pair i,j and corresponding j,i
+------------------------------------------------------------------------- */
+
+double PairBodyRoundedPolyhedron::init_one(int i, int j)
+{
+  k_n[j][i] = k_n[i][j];
+  k_na[j][i] = k_na[i][j];
+
+  return (maxerad[i]+maxerad[j]);
+}
+
+/* ----------------------------------------------------------------------
+   convert N sub-particles in body I to space frame using current quaternion
+   store sub-particle space-frame displacements from COM in discrete list
+------------------------------------------------------------------------- */
+
+void PairBodyRoundedPolyhedron::body2space(int i)
+{
+  int ibonus = atom->body[i];
+  AtomVecBody::Bonus *bonus = &avec->bonus[ibonus];
+  int nsub = bptr->nsub(bonus);
+  double *coords = bptr->coords(bonus);
+  int body_num_edges = bptr->nedges(bonus);
+  double* edge_ends = bptr->edges(bonus);
+  int body_num_faces = bptr->nfaces(bonus);
+  double* face_pts = bptr->faces(bonus);
+  double eradius = bptr->enclosing_radius(bonus);
+  double rradius = bptr->rounded_radius(bonus);
+
+  // get the number of sub-particles (vertices)
+  // and the index of the first vertex of my body in the list
+
+  dnum[i] = nsub;
+  dfirst[i] = ndiscrete;
+
+  // grow the vertex list if necessary
+  // the first 3 columns are for coords, the last 3 for forces
+
+  if (ndiscrete + nsub > dmax) {
+    dmax += DELTA;
+    memory->grow(discrete,dmax,7,"pair:discrete");
+  }
+
+  double p[3][3];
+  MathExtra::quat_to_mat(bonus->quat,p);
+
+  for (int m = 0; m < nsub; m++) {
+    MathExtra::matvec(p,&coords[3*m],discrete[ndiscrete]);
+    discrete[ndiscrete][3] = 0;
+    discrete[ndiscrete][4] = 0;
+    discrete[ndiscrete][5] = 0;
+    discrete[ndiscrete][6] = 0;
+    ndiscrete++;
+  }
+
+  // get the number of edges (vertices)
+  // and the index of the first edge of my body in the list
+
+  ednum[i] = body_num_edges;
+  edfirst[i] = nedge;
+
+  // grow the edge list if necessary
+  // the first 2 columns are for vertex indices within body, the last 3 for forces
+
+  if (nedge + body_num_edges > edmax) {
+    edmax += DELTA;
+    memory->grow(edge,edmax,6,"pair:edge");
+  }
+
+  for (int m = 0; m < body_num_edges; m++) {
+    edge[nedge][0] = static_cast<int>(edge_ends[2*m+0]);
+    edge[nedge][1] = static_cast<int>(edge_ends[2*m+1]);
+    edge[nedge][2] = 0;
+    edge[nedge][3] = 0;
+    edge[nedge][4] = 0;
+    edge[nedge][5] = 0;
+    nedge++;
+  }
+
+  // get the number of faces and the index of the first face
+
+  facnum[i] = body_num_faces;
+  facfirst[i] = nface;
+
+  // grow the face list if necessary
+  // the first 3 columns are for vertex indices within body, the last 3 for forces
+
+  if (nface + body_num_faces > facmax) {
+    facmax += DELTA;
+    memory->grow(face,facmax,MAX_FACE_SIZE,"pair:face");
+  }
+
+  for (int m = 0; m < body_num_faces; m++) {
+    for (int k = 0; k < MAX_FACE_SIZE; k++)
+      face[nface][k] = static_cast<int>(face_pts[MAX_FACE_SIZE*m+k]);
+    nface++;
+  }
+
+  enclosing_radius[i] = eradius;
+  rounded_radius[i] = rradius;
+}
+
+/* ----------------------------------------------------------------------
+   Interaction between two spheres with different radii
+   according to the 2D model from Fraige et al.
+---------------------------------------------------------------------- */
+
+void PairBodyRoundedPolyhedron::sphere_against_sphere(int ibody, int jbody,
+  int itype, int jtype, double delx, double dely, double delz, double rsq,
+  double** v, double** f, int evflag)
+{
+  double rradi,rradj,contact_dist;
+  double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3;
+  double rij,rsqinv,R,fx,fy,fz,fn[3],ft[3],fpair,shift,energy;
+  int nlocal = atom->nlocal;
+  int newton_pair = force->newton_pair;
+
+  rradi = rounded_radius[ibody];
+  rradj = rounded_radius[jbody];
+  contact_dist = rradi + rradj;
+
+  rij = sqrt(rsq);
+  R = rij - contact_dist;
+
+  energy = 0;
+  kernel_force(R, itype, jtype, energy, fpair);
+
+  fx = delx*fpair/rij;
+  fy = dely*fpair/rij;
+  fz = delz*fpair/rij;
+
+  if (R <= 0) { // in contact
+
+    // relative translational velocity
+
+    vr1 = v[ibody][0] - v[jbody][0];
+    vr2 = v[ibody][1] - v[jbody][1];
+    vr3 = v[ibody][2] - v[jbody][2];
+
+    // normal component
+    
+    rsqinv = 1.0/rsq;
+    vnnr = vr1*delx + vr2*dely + vr3*delz;
+    vn1 = delx*vnnr * rsqinv;
+    vn2 = dely*vnnr * rsqinv;
+    vn3 = delz*vnnr * rsqinv;
+
+    // tangential component
+
+    vt1 = vr1 - vn1;
+    vt2 = vr2 - vn2;
+    vt3 = vr3 - vn3;
+
+    // normal friction term at contact
+
+    fn[0] = -c_n * vn1;
+    fn[1] = -c_n * vn2;
+    fn[2] = -c_n * vn3;
+
+    // tangential friction term at contact,
+    // excluding the tangential deformation term for now
+
+    ft[0] = -c_t * vt1;
+    ft[1] = -c_t * vt2;
+    ft[2] = -c_t * vt3;
+
+    fx += fn[0] + ft[0];
+    fy += fn[1] + ft[1];
+    fz += fn[2] + ft[2];
+  }
+
+  f[ibody][0] += fx;
+  f[ibody][1] += fy;
+  f[ibody][2] += fz;
+  
+  if (newton_pair || jbody < nlocal) {
+    f[jbody][0] -= fx;
+    f[jbody][1] -= fy;
+    f[jbody][2] -= fz;
+  }
+
+  if (evflag) ev_tally_xyz(ibody,jbody,nlocal,newton_pair,
+                           energy,0.0,fx,fy,fz,delx,dely,delz);
+}
+
+/* ----------------------------------------------------------------------
+   Interaction bt the edges of a polyhedron (ibody) and a sphere (jbody)
+---------------------------------------------------------------------- */
+
+void PairBodyRoundedPolyhedron::sphere_against_edge(int ibody, int jbody,
+  int itype, int jtype, double** x, double** v, double** f, double** torque,
+  double** angmom, int evflag)
+{
+  int ni,nei,ifirst,iefirst,npi1,npi2,ibonus;
+  double xi1[3],xi2[3],vti[3],h[3],fn[3],ft[3],d,t;
+  double delx,dely,delz,rij,rsqinv,R,fx,fy,fz,fpair,shift,energy;
+  double rradi,rradj,contact_dist;
+  double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3;
+  double *quat, *inertia;
+  AtomVecBody::Bonus *bonus;
+
+  int nlocal = atom->nlocal;
+  int newton_pair = force->newton_pair;
+
+  ifirst = dfirst[ibody];
+  iefirst = edfirst[ibody];
+  nei = ednum[ibody];
+
+  rradi = rounded_radius[ibody];
+  rradj = rounded_radius[jbody];
+  contact_dist = rradi + rradj;
+
+  for (ni = 0; ni < nei; ni++) {
+
+    npi1 = static_cast<int>(edge[iefirst+ni][0]);
+    npi2 = static_cast<int>(edge[iefirst+ni][1]);
+
+    // compute the space-fixed coordinates for the vertices of the face
+
+    xi1[0] = x[ibody][0] + discrete[ifirst+npi1][0];
+    xi1[1] = x[ibody][1] + discrete[ifirst+npi1][1];
+    xi1[2] = x[ibody][2] + discrete[ifirst+npi1][2];
+
+    xi2[0] = x[ibody][0] + discrete[ifirst+npi2][0];
+    xi2[1] = x[ibody][1] + discrete[ifirst+npi2][1];
+    xi2[2] = x[ibody][2] + discrete[ifirst+npi2][2];
+
+    // find the projection of the jbody's COM on the edge
+
+    project_pt_line(x[jbody], xi1, xi2, h, d, t);
+
+    if (d > contact_dist + cut_inner) continue;
+    if (t < 0 || t > 1) continue;
+
+    if (fabs(t) < EPSILON) {
+      if (static_cast<int>(discrete[ifirst+npi1][6]) == 1)
+        continue;
+      else {
+        h[0] = xi1[0];
+        h[1] = xi1[1];
+        h[2] = xi1[2];
+        discrete[ifirst+npi1][6] = 1;
+      }
+    }
+
+    if (fabs(t-1) < EPSILON) {
+      if (static_cast<int>(discrete[ifirst+npi2][6]) == 1)
+        continue;
+      else {
+        h[0] = xi2[0];
+        h[1] = xi2[1];
+        h[2] = xi2[2];
+        discrete[ifirst+npi2][6] = 1;
+      }
+    }
+
+    delx = h[0] - x[jbody][0];
+    dely = h[1] - x[jbody][1];
+    delz = h[2] - x[jbody][2];
+    rij = sqrt(delx*delx + dely*dely + delz*delz);
+    R = rij - contact_dist;
+
+    energy = 0;
+    kernel_force(R, itype, jtype, energy, fpair);
+
+    fx = delx*fpair/rij;
+    fy = dely*fpair/rij;
+    fz = delz*fpair/rij;
+
+    if (R <= 0) { // in contact
+
+      // compute the velocity of the vertex in the space-fixed frame
+
+      ibonus = atom->body[ibody];
+      bonus = &avec->bonus[ibonus];
+      quat = bonus->quat;
+      inertia = bonus->inertia;
+      total_velocity(h, x[ibody], v[ibody], angmom[ibody],
+                     inertia, quat, vti);
+
+      // relative translational velocity
+
+      vr1 = vti[0] - v[jbody][0];
+      vr2 = vti[1] - v[jbody][1];
+      vr3 = vti[2] - v[jbody][2];
+
+      // normal component
+
+      vnnr = vr1*delx + vr2*dely + vr3*delz;
+      vn1 = delx*vnnr * rsqinv;
+      vn2 = dely*vnnr * rsqinv;
+      vn3 = delz*vnnr * rsqinv;
+
+      // tangential component
+
+      vt1 = vr1 - vn1;
+      vt2 = vr2 - vn2;
+      vt3 = vr3 - vn3;
+
+      // normal friction term at contact
+
+      fn[0] = -c_n * vn1;
+      fn[1] = -c_n * vn2;
+      fn[2] = -c_n * vn3;
+
+      // tangential friction term at contact, 
+      // excluding the tangential deformation term
+
+      ft[0] = -c_t * vt1;
+      ft[1] = -c_t * vt2;
+      ft[2] = -c_t * vt3;
+
+      fx += fn[0] + ft[0];
+      fy += fn[1] + ft[1];
+      fz += fn[2] + ft[2];
+    }
+
+    f[ibody][0] += fx;
+    f[ibody][1] += fy;
+    f[ibody][2] += fz;
+    sum_torque(x[ibody], h, fx, fy, fz, torque[ibody]);
+
+    if (newton_pair || jbody < nlocal) {
+      f[jbody][0] -= fx;
+      f[jbody][1] -= fy;
+      f[jbody][2] -= fz;
+    }
+
+    if (evflag) ev_tally_xyz(ibody,jbody,nlocal,newton_pair,
+                           energy,0.0,fx,fy,fz,delx,dely,delz);
+  }
+}
+
+/* ----------------------------------------------------------------------
+   Interaction bt the faces of a polyhedron (ibody) and a sphere (jbody)
+---------------------------------------------------------------------- */
+
+void PairBodyRoundedPolyhedron::sphere_against_face(int ibody, int jbody,
+ int itype, int jtype, double** x, double** v, double** f, double** torque,
+ double** angmom, int evflag)
+{
+  int ni,nfi,inside,ifirst,iffirst,npi1,npi2,npi3,ibonus,tmp;
+  double xi1[3],xi2[3],xi3[3],ui[3],vi[3],vti[3],n[3],h[3],fn[3],ft[3],d;
+  double delx,dely,delz,rsq,rij,rsqinv,R,fx,fy,fz,fpair,shift,energy;
+  double rradi,rradj,contact_dist;
+  double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3;
+  double *quat, *inertia;
+  AtomVecBody::Bonus *bonus;
+
+  int nlocal = atom->nlocal;
+  int newton_pair = force->newton_pair;
+
+  ifirst = dfirst[ibody];
+  iffirst = facfirst[ibody];
+  nfi = facnum[ibody];
+
+  rradi = rounded_radius[ibody];
+  rradj = rounded_radius[jbody];
+  contact_dist = rradi + rradj;
+
+  for (ni = 0; ni < nfi; ni++) {
+
+    npi1 = static_cast<int>(face[iffirst+ni][0]);
+    npi2 = static_cast<int>(face[iffirst+ni][1]);
+    npi3 = static_cast<int>(face[iffirst+ni][2]);
+
+    // compute the space-fixed coordinates for the vertices of the face
+
+    xi1[0] = x[ibody][0] + discrete[ifirst+npi1][0];
+    xi1[1] = x[ibody][1] + discrete[ifirst+npi1][1];
+    xi1[2] = x[ibody][2] + discrete[ifirst+npi1][2];
+
+    xi2[0] = x[ibody][0] + discrete[ifirst+npi2][0];
+    xi2[1] = x[ibody][1] + discrete[ifirst+npi2][1];
+    xi2[2] = x[ibody][2] + discrete[ifirst+npi2][2];
+
+    xi3[0] = x[ibody][0] + discrete[ifirst+npi3][0];
+    xi3[1] = x[ibody][1] + discrete[ifirst+npi3][1];
+    xi3[2] = x[ibody][2] + discrete[ifirst+npi3][2];
+
+    // find the normal unit vector of the face
+  
+    MathExtra::sub3(xi2, xi1, ui);
+    MathExtra::sub3(xi3, xi1, vi);
+    MathExtra::cross3(ui, vi, n);
+    MathExtra::norm3(n);
+
+    // skip if the COM of the two bodies are in the same side of the face
+
+    if (opposite_sides(n, xi1, x[ibody], x[jbody]) == 0) continue;
+
+    // find the projection of the sphere on the face
+
+    project_pt_plane(x[jbody], xi1, xi2, xi3, h, d, inside);
+
+    inside_polygon(ibody, ni, x[ibody], h, NULL, inside, tmp);
+    if (inside == 0) continue;
+
+    delx = h[0] - x[jbody][0];
+    dely = h[1] - x[jbody][1];
+    delz = h[2] - x[jbody][2];
+    rsq = delx*delx + dely*dely + delz*delz;
+    rij = sqrt(rsq);
+    R = rij - contact_dist;
+
+    energy = 0;
+    kernel_force(R, itype, jtype, energy, fpair);
+
+    fx = delx*fpair/rij;
+    fy = dely*fpair/rij;
+    fz = delz*fpair/rij;
+
+    if (R <= 0) { // in contact
+
+      // compute the velocity of the vertex in the space-fixed frame
+
+      ibonus = atom->body[ibody];
+      bonus = &avec->bonus[ibonus];
+      quat = bonus->quat;
+      inertia = bonus->inertia;
+      total_velocity(h, x[ibody], v[ibody], angmom[ibody],
+                     inertia, quat, vti);
+
+      // relative translational velocity
+
+      vr1 = vti[0] - v[jbody][0];
+      vr2 = vti[1] - v[jbody][1];
+      vr3 = vti[2] - v[jbody][2];
+
+      // normal component
+
+      rsqinv = 1.0/rsq;
+      vnnr = vr1*delx + vr2*dely + vr3*delz;
+      vn1 = delx*vnnr * rsqinv;
+      vn2 = dely*vnnr * rsqinv;
+      vn3 = delz*vnnr * rsqinv;
+
+      // tangential component
+
+      vt1 = vr1 - vn1;
+      vt2 = vr2 - vn2;
+      vt3 = vr3 - vn3;
+
+      // normal friction term at contact
+
+      fn[0] = -c_n * vn1;
+      fn[1] = -c_n * vn2;
+      fn[2] = -c_n * vn3;
+
+      // tangential friction term at contact,
+      // excluding the tangential deformation term for now
+
+      ft[0] = -c_t * vt1;
+      ft[1] = -c_t * vt2;
+      ft[2] = -c_t * vt3;
+
+      fx += fn[0] + ft[0];
+      fy += fn[1] + ft[1];
+      fz += fn[2] + ft[2];
+    }
+
+    f[ibody][0] += fx;
+    f[ibody][1] += fy;
+    f[ibody][2] += fz;
+    sum_torque(x[ibody], h, fx, fy, fz, torque[ibody]);
+
+    if (newton_pair || jbody < nlocal) {
+      f[jbody][0] -= fx;
+      f[jbody][1] -= fy;
+      f[jbody][2] -= fz;
+    }
+
+    if (evflag) ev_tally_xyz(ibody,jbody,nlocal,newton_pair,
+                           energy,0.0,fx,fy,fz,delx,dely,delz);
+  }
+}
+
+/* ----------------------------------------------------------------------
+   Determine the interaction mode between i's edges against j's edges
+
+   i = atom i (body i)
+   j = atom j (body j)
+   x      = atoms' coordinates
+   f      = atoms' forces
+   torque = atoms' torques
+   tag    = atoms' tags
+   contact_list = list of contacts
+   num_contacts = number of contacts between i's edges and j's edges
+   Return:
+
+---------------------------------------------------------------------- */
+
+int PairBodyRoundedPolyhedron::edge_against_edge(int ibody, int jbody,
+  int itype, int jtype, double** x, Contact* contact_list, int &num_contacts,
+  double &evdwl, double* facc)
+{
+  int ni,nei,nj,nej,contact,interact;
+  double rradi,rradj,energy;
+
+  nei = ednum[ibody];
+  rradi = rounded_radius[ibody];
+  nej = ednum[jbody];
+  rradj = rounded_radius[jbody];
+
+  energy = 0;
+  interact = EE_NONE;
+
+  // loop through body i's edges
+
+  for (ni = 0; ni < nei; ni++) {
+
+    for (nj = 0; nj < nej; nj++) {
+
+      // compute the distance between the edge nj to the edge ni
+      #ifdef _POLYHEDRON_DEBUG
+      printf("Compute interaction between edge %d of body %d "
+             "with edge %d of body %d:\n",
+             nj, jbody, ni, ibody);
+      #endif
+
+      interact = interaction_edge_to_edge(ibody, ni, x[ibody], rradi,
+                                          jbody, nj, x[jbody], rradj,
+                                          itype, jtype, cut_inner,
+                                          contact_list, num_contacts,
+                                          energy, facc);
+    }
+
+  } // end for looping through the edges of body i
+
+  evdwl += energy;
+
+  return interact;
+}
+
+/* ----------------------------------------------------------------------
+   Determine the interaction mode between i's edges against j's faces
+
+   i = atom i (body i)
+   j = atom j (body j)
+   x      = atoms' coordinates
+   f      = atoms' forces
+   torque = atoms' torques
+   tag    = atoms' tags
+   contact_list = list of contacts
+   num_contacts = number of contacts between i's edges and j's faces
+   Return:
+
+---------------------------------------------------------------------- */
+
+int PairBodyRoundedPolyhedron::edge_against_face(int ibody, int jbody,
+  int itype, int jtype, double** x, Contact* contact_list, int &num_contacts,
+  double &evdwl, double* facc)
+{
+  int ni,nei,nj,nfj,contact,interact;
+  double rradi,rradj,energy;
+
+  nei = ednum[ibody];
+  rradi = rounded_radius[ibody];
+  nfj = facnum[jbody];
+  rradj = rounded_radius[jbody];
+
+  energy = 0;
+  interact = EF_NONE;
+
+  // loop through body i's edges
+
+  for (ni = 0; ni < nei; ni++) {
+
+    // loop through body j's faces
+
+    for (nj = 0; nj < nfj; nj++) {
+
+      // compute the distance between the face nj to the edge ni
+      #ifdef _POLYHEDRON_DEBUG
+      printf("Compute interaction between face %d of body %d with "
+             "edge %d of body %d:\n",
+             nj, jbody, ni, ibody);
+      #endif
+
+      interact = interaction_face_to_edge(jbody, nj, x[jbody], rradj,
+                                          ibody, ni, x[ibody], rradi,
+                                          itype, jtype, cut_inner,
+                                          contact_list, num_contacts,
+                                          energy, facc);
+    } 
+
+  } // end for looping through the edges of body i
+
+  evdwl += energy;
+
+  return interact;
+}
+
+/* -------------------------------------------------------------------------
+  Compute the distance between an edge of body i and an edge from
+  another body
+  Input:
+    ibody      = body i (i.e. atom i)
+    face_index = face index of body i
+    xmi        = atom i's coordinates (body i's center of mass)
+    rounded_radius_i = rounded radius of the body i
+    jbody      = body i (i.e. atom j)
+    edge_index = coordinate of the tested edge from another body
+    xmj        = atom j's coordinates (body j's center of mass)
+    rounded_radius_j = rounded radius of the body j
+    cut_inner  = cutoff for vertex-vertex and vertex-edge interaction
+  Output:
+    d          = Distance from a point x0 to an edge
+    hi         = coordinates of the projection of x0 on the edge
+
+  contact      = 0 no contact between the queried edge and the face
+                 1 contact detected
+  return
+    INVALID if the face index is invalid
+    NONE    if there is no interaction
+------------------------------------------------------------------------- */
+
+int PairBodyRoundedPolyhedron::interaction_edge_to_edge(int ibody,
+  int edge_index_i,  double *xmi, double rounded_radius_i,
+  int jbody, int edge_index_j, double *xmj, double rounded_radius_j,
+  int itype, int jtype, double cut_inner,
+  Contact* contact_list, int &num_contacts, double &energy, double* facc)
+{
+  int ifirst,iefirst,jfirst,jefirst,npi1,npi2,npj1,npj2,interact;
+  double xi1[3],xi2[3],xpj1[3],xpj2[3];
+  double r,t1,t2,h1[3],h2[3];
+  double contact_dist, shift;
+
+  double** x = atom->x;
+  double** v = atom->v;
+  double** f = atom->f;
+  double** torque = atom->torque;
+  double** angmom = atom->angmom;
+
+  ifirst = dfirst[ibody];
+  iefirst = edfirst[ibody];
+  npi1 = static_cast<int>(edge[iefirst+edge_index_i][0]);
+  npi2 = static_cast<int>(edge[iefirst+edge_index_i][1]);
+
+  // compute the space-fixed coordinates for the edge ends
+
+  xi1[0] = xmi[0] + discrete[ifirst+npi1][0];
+  xi1[1] = xmi[1] + discrete[ifirst+npi1][1];
+  xi1[2] = xmi[2] + discrete[ifirst+npi1][2];
+
+  xi2[0] = xmi[0] + discrete[ifirst+npi2][0];
+  xi2[1] = xmi[1] + discrete[ifirst+npi2][1];
+  xi2[2] = xmi[2] + discrete[ifirst+npi2][2];
+
+  // two ends of the edge from body j
+
+  jfirst = dfirst[jbody];
+  jefirst = edfirst[jbody];
+  npj1 = static_cast<int>(edge[jefirst+edge_index_j][0]);
+  npj2 = static_cast<int>(edge[jefirst+edge_index_j][1]);
+
+  xpj1[0] = xmj[0] + discrete[jfirst+npj1][0];
+  xpj1[1] = xmj[1] + discrete[jfirst+npj1][1];
+  xpj1[2] = xmj[2] + discrete[jfirst+npj1][2];
+
+  xpj2[0] = xmj[0] + discrete[jfirst+npj2][0];
+  xpj2[1] = xmj[1] + discrete[jfirst+npj2][1];
+  xpj2[2] = xmj[2] + discrete[jfirst+npj2][2];
+
+  contact_dist = rounded_radius_i + rounded_radius_j;
+
+  int jflag = 1;
+  distance_bt_edges(xpj1, xpj2, xi1, xi2, h1, h2, t1, t2, r);
+
+  #ifdef _POLYHEDRON_DEBUG
+  double ui[3],uj[3];
+  MathExtra::sub3(xi1,xi2,ui);
+  MathExtra::norm3(ui);
+  MathExtra::sub3(xpj1,xpj2,uj);
+  MathExtra::norm3(uj);
+  double dot = MathExtra::dot3(ui, uj);
+  printf("  edge npi1 = %d (%f %f %f); npi2 = %d (%f %f %f) vs."
+         "  edge npj1 = %d (%f %f %f); npj2 = %d (%f %f %f): "
+         "t1 = %f; t2 = %f; r = %f; dot = %f\n",
+    npi1, xi1[0], xi1[1], xi1[2], npi2, xi2[0], xi2[1], xi2[2], 
+    npj1, xpj1[0], xpj1[1], xpj1[2], npj2, xpj2[0], xpj2[1], xpj2[2],
+    t1, t2, r, dot);
+  #endif
+
+  interact = EE_NONE;
+
+  // singularity case, ignore interactions
+
+  if (r < EPSILON) return interact;
+
+  // include the vertices for interactions
+
+  if (t1 >= 0 && t1 <= 1 && t2 >= 0 && t2 <= 1 &&
+      r < contact_dist + cut_inner) {
+    pair_force_and_torque(jbody, ibody, h1, h2, r, contact_dist,
+                          jtype, itype, x, v, f, torque, angmom,
+                          jflag, energy, facc);
+
+    interact = EE_INTERACT;
+    if (r <= contact_dist) {
+      // store the contact info
+      contact_list[num_contacts].ibody = ibody;
+      contact_list[num_contacts].jbody = jbody;
+      contact_list[num_contacts].xi[0] = h2[0];
+      contact_list[num_contacts].xi[1] = h2[1];
+      contact_list[num_contacts].xi[2] = h2[2];
+      contact_list[num_contacts].xj[0] = h1[0];
+      contact_list[num_contacts].xj[1] = h1[1];
+      contact_list[num_contacts].xj[2] = h1[2];
+      contact_list[num_contacts].type = 1;
+      contact_list[num_contacts].separation = r - contact_dist;
+      contact_list[num_contacts].unique = 1;
+      num_contacts++;
+    }
+  } else {
+
+  }
+
+  return interact;
+}
+
+/* -------------------------------------------------------------------------
+  Compute the interaction between a face of body i and an edge from
+  another body
+  Input:
+    ibody      = body i (i.e. atom i)
+    face_index = face index of body i
+    xmi        = atom i's coordinates (body i's center of mass)
+    rounded_radius_i = rounded radius of the body i
+    jbody      = body i (i.e. atom j)
+    edge_index = coordinate of the tested edge from another body
+    xmj        = atom j's coordinates (body j's center of mass)
+    rounded_radius_j = rounded radius of the body j
+    cut_inner  = cutoff for vertex-vertex and vertex-edge interaction
+  Output:
+    d          = Distance from a point x0 to an edge
+    hi         = coordinates of the projection of x0 on the edge
+
+  contact      = 0 no contact between the queried edge and the face
+                 1 contact detected
+  return
+    INVALID if the face index is invalid
+    NONE    if there is no interaction
+------------------------------------------------------------------------- */
+
+int PairBodyRoundedPolyhedron::interaction_face_to_edge(int ibody,
+  int face_index, double *xmi, double rounded_radius_i,
+  int jbody, int edge_index, double *xmj, double rounded_radius_j,
+  int itype, int jtype, double cut_inner,
+  Contact* contact_list, int &num_contacts, double &energy, double* facc)
+{
+  if (face_index >= facnum[ibody]) return EF_INVALID;
+
+  int ifirst,iffirst,jfirst,npi1,npi2,npi3;
+  int jefirst,npj1,npj2;
+  double xi1[3],xi2[3],xi3[3],xpj1[3],xpj2[3],ui[3],vi[3],n[3];
+
+  double** x = atom->x;
+  double** v = atom->v;
+  double** f = atom->f;
+  double** torque = atom->torque;
+  double** angmom = atom->angmom;
+
+  ifirst = dfirst[ibody];
+  iffirst = facfirst[ibody];
+  npi1 = static_cast<int>(face[iffirst+face_index][0]);
+  npi2 = static_cast<int>(face[iffirst+face_index][1]);
+  npi3 = static_cast<int>(face[iffirst+face_index][2]);
+
+  // compute the space-fixed coordinates for the vertices of the face
+
+  xi1[0] = xmi[0] + discrete[ifirst+npi1][0];
+  xi1[1] = xmi[1] + discrete[ifirst+npi1][1];
+  xi1[2] = xmi[2] + discrete[ifirst+npi1][2];
+
+  xi2[0] = xmi[0] + discrete[ifirst+npi2][0];
+  xi2[1] = xmi[1] + discrete[ifirst+npi2][1];
+  xi2[2] = xmi[2] + discrete[ifirst+npi2][2];
+
+  xi3[0] = xmi[0] + discrete[ifirst+npi3][0];
+  xi3[1] = xmi[1] + discrete[ifirst+npi3][1];
+  xi3[2] = xmi[2] + discrete[ifirst+npi3][2];
+
+  // find the normal unit vector of the face, ensure it point outward of the body
+  
+  MathExtra::sub3(xi2, xi1, ui);
+  MathExtra::sub3(xi3, xi1, vi);
+  MathExtra::cross3(ui, vi, n);
+  MathExtra::norm3(n);
+
+  double xc[3], dot, ans[3];
+  xc[0] = (xi1[0] + xi2[0] + xi3[0])/3.0;
+  xc[1] = (xi1[1] + xi2[1] + xi3[1])/3.0;
+  xc[2] = (xi1[2] + xi2[2] + xi3[2])/3.0;
+  MathExtra::sub3(xc, xmi, ans);
+  dot = MathExtra::dot3(ans, n);
+  if (dot < 0) MathExtra::negate3(n);
+
+  // two ends of the edge from body j
+
+  jfirst = dfirst[jbody];
+  jefirst = edfirst[jbody];
+  npj1 = static_cast<int>(edge[jefirst+edge_index][0]);
+  npj2 = static_cast<int>(edge[jefirst+edge_index][1]);
+
+  xpj1[0] = xmj[0] + discrete[jfirst+npj1][0];
+  xpj1[1] = xmj[1] + discrete[jfirst+npj1][1];
+  xpj1[2] = xmj[2] + discrete[jfirst+npj1][2];
+
+  xpj2[0] = xmj[0] + discrete[jfirst+npj2][0];
+  xpj2[1] = xmj[1] + discrete[jfirst+npj2][1];
+  xpj2[2] = xmj[2] + discrete[jfirst+npj2][2];
+
+  // no interaction if two ends of the edge 
+  // are on the same side with the COM wrt the face
+
+  if (opposite_sides(n, xi1, xmi, xpj1) == 0 &&
+      opposite_sides(n, xi1, xmi, xpj2) == 0)
+    return EF_NONE;
+
+  // determine the intersection of the edge to the face
+
+  double hi1[3], hi2[3], d1, d2, contact_dist, shift;
+  int inside1 = 0;
+  int inside2 = 0;
+
+  // enum {EF_PARALLEL=0,EF_SAME_SIDE_OF_FACE,
+  //       EF_INTERSECT_INSIDE,EF_INTERSECT_OUTSIDE};
+
+  int interact = edge_face_intersect(xi1, xi2, xi3, xpj1, xpj2,
+                                     hi1, hi2, d1, d2, inside1, inside2);
+
+  inside_polygon(ibody, face_index, xmi, hi1, hi2, inside1, inside2);
+
+  contact_dist = rounded_radius_i + rounded_radius_j;
+
+  // both endpoints are on the same side of, or parallel to, the face
+  // and both are out of the interaction zone
+
+  if (interact == EF_SAME_SIDE_OF_FACE || interact == EF_PARALLEL) {
+
+    if (d1 > contact_dist + cut_inner && d2 > contact_dist + cut_inner)
+      return EF_NONE;
+
+    int num_outside = 0;
+    int jflag = 1;
+
+    #ifdef _POLYHEDRON_DEBUG
+    if (interact == EF_SAME_SIDE_OF_FACE) 
+      printf(" - same side of face\n");
+    else if (interact == EF_PARALLEL) 
+      printf(" - parallel\n");
+    printf("     face: xi1 (%f %f %f) xi2 (%f %f %f) xi3 (%f %f %f)\n",
+      xi1[0], xi1[1], xi1[2], xi2[0], xi2[1], xi2[2], xi3[0], xi3[1], xi3[2]);
+    printf("     edge: xpj1 (%f %f %f) xpj2 (%f %f %f)\n",
+      xpj1[0], xpj1[1], xpj1[2], xpj2[0], xpj2[1], xpj2[2]);
+    #endif
+
+    // xpj1 is in the interaction zone
+    // and its projection on the face is inside the triangle
+    // compute vertex-face interaction and accumulate force/torque to both bodies
+
+    if (d1 <= contact_dist + cut_inner) {
+      if (inside1) {
+        if (static_cast<int>(discrete[jfirst+npj1][6]) == 0) {
+          pair_force_and_torque(jbody, ibody, xpj1, hi1, d1, contact_dist,
+                                jtype, itype, x, v, f, torque, angmom,
+                                jflag, energy, facc);
+          #ifdef _POLYHEDRON_DEBUG
+          printf(" - compute pair force between vertex %d from edge %d of body %d "
+                 "with face %d of body %d: d1 = %f\n",
+            npj1, edge_index, jbody, face_index, ibody, d1);
+          #endif
+
+          if (d1 <= contact_dist) {
+            // store the contact info
+            contact_list[num_contacts].ibody = ibody;
+            contact_list[num_contacts].jbody = jbody;
+            contact_list[num_contacts].xi[0] = hi1[0];
+            contact_list[num_contacts].xi[1] = hi1[1];
+            contact_list[num_contacts].xi[2] = hi1[2];
+            contact_list[num_contacts].xj[0] = xpj1[0];
+            contact_list[num_contacts].xj[1] = xpj1[1];
+            contact_list[num_contacts].xj[2] = xpj1[2];
+            contact_list[num_contacts].type = 0;
+            contact_list[num_contacts].separation = d1 - contact_dist;
+            contact_list[num_contacts].unique = 1;
+            num_contacts++;
+          }
+
+          discrete[jfirst+npj1][6] = 1;
+        }
+      } else {
+        num_outside++;
+      }
+    } 
+
+    // xpj2 is in the interaction zone 
+    // and its projection on the face is inside the triangle
+    // compute vertex-face interaction and accumulate force/torque to both bodies
+
+    if (d2 <= contact_dist + cut_inner) {
+      if (inside2) {
+        if (static_cast<int>(discrete[jfirst+npj2][6]) == 0) {
+          pair_force_and_torque(jbody, ibody, xpj2, hi2, d2, contact_dist,
+                                jtype, itype, x, v, f, torque, angmom,
+                                jflag, energy, facc);
+          #ifdef _POLYHEDRON_DEBUG
+          printf(" - compute pair force between vertex %d from edge %d of body %d "
+                 "with face %d of body %d: d2 = %f\n", 
+                 npj2, edge_index, jbody, face_index, ibody, d2);
+          #endif
+
+          if (d2 <= contact_dist) {
+            // store the contact info
+            contact_list[num_contacts].ibody = ibody;
+            contact_list[num_contacts].jbody = jbody;
+            contact_list[num_contacts].xi[0] = hi2[0];
+            contact_list[num_contacts].xi[1] = hi2[1];
+            contact_list[num_contacts].xi[2] = hi2[2];
+            contact_list[num_contacts].xj[0] = xpj2[0];
+            contact_list[num_contacts].xj[1] = xpj2[1];
+            contact_list[num_contacts].xj[2] = xpj2[2];
+            contact_list[num_contacts].type = 0;
+            contact_list[num_contacts].separation = d2 - contact_dist;
+            contact_list[num_contacts].unique = 1;
+            num_contacts++;
+          }
+          discrete[jfirst+npj2][6] = 1;
+        }
+      } else {
+        num_outside++;
+      }
+    }
+
+    // both ends have projection outside of the face
+    // compute interaction between the edge with the three edges of the face
+
+    if (num_outside == 2) {
+
+      #ifdef _POLYHEDRON_DEBUG
+      printf(" - outside = 2\n");
+      printf(" - compute pair force between edge %d of body %d "
+             "with 3 edges of face %d of body %d\n",
+        edge_index, jbody, face_index, ibody);
+      #endif
+
+      interact = EF_INTERSECT_OUTSIDE;
+
+    }
+
+  } else if (interact == EF_INTERSECT_OUTSIDE) {
+
+    // compute interaction between the edge with the three edges of the face
+
+    #ifdef _POLYHEDRON_DEBUG
+    printf(" - intersect outside triangle\n"); 
+    printf(" - compute pair force between edge %d of body %d "
+           "with face %d of body %d\n", edge_index, jbody, face_index, ibody);
+    printf("     face: xi1 (%f %f %f) xi2 (%f %f %f) xi3 (%f %f %f)\n",
+      xi1[0], xi1[1], xi1[2], xi2[0], xi2[1], xi2[2], xi3[0], xi3[1], xi3[2]);
+    printf("     edge: xpj1 (%f %f %f) xpj2 (%f %f %f)\n",
+      xpj1[0], xpj1[1], xpj1[2], xpj2[0], xpj2[1], xpj2[2]);
+
+    #endif
+  } else if (interact == EF_INTERSECT_INSIDE) {
+    // need to do something here to resolve overlap!!
+    // p is the intersection between the edge and the face
+    int jflag = 1;
+    if (d1 < d2)
+      pair_force_and_torque(jbody, ibody, xpj1, hi1, d1, contact_dist,
+                            jtype, itype, x, v, f, torque, angmom,
+                            jflag, energy, facc);
+    else
+      pair_force_and_torque(jbody, ibody, xpj2, hi2, d2, contact_dist,
+                            jtype, itype, x, v, f, torque, angmom,
+                            jflag, energy, facc);
+  }
+
+  return interact;
+}
+
+/* ----------------------------------------------------------------------
+  Compute forces and torques between two bodies caused by the interaction
+  between a pair of points on either bodies (similar to sphere-sphere)
+------------------------------------------------------------------------- */
+
+void PairBodyRoundedPolyhedron::pair_force_and_torque(int ibody, int jbody,
+                 double* pi, double* pj, double r, double contact_dist,
+                 int itype, int jtype, double** x,
+                 double** v, double** f, double** torque, double** angmom,
+                 int jflag, double& energy, double* facc)
+{
+  double delx,dely,delz,R,fx,fy,fz,fpair;
+
+  delx = pi[0] - pj[0];
+  dely = pi[1] - pj[1];
+  delz = pi[2] - pj[2];
+  R = r - contact_dist;
+
+  kernel_force(R, itype, jtype, energy, fpair);
+
+  fx = delx*fpair/r;
+  fy = dely*fpair/r;
+  fz = delz*fpair/r;
+
+  #ifdef _POLYHEDRON_DEBUG
+  printf("  - R = %f; r = %f; k_na = %f; shift = %f; fpair = %f;"
+         " energy = %f; jflag = %d\n", R, r, k_na, shift, fpair,
+         energy, jflag);
+  #endif
+
+  if (R <= 0) {
+
+    // contact: accumulate normal and tangential contact force components
+
+    contact_forces(ibody, jbody, pi, pj, delx, dely, delz, fx, fy, fz,
+                   x, v, angmom, f, torque, facc);
+  } else {
+
+    // accumulate force and torque to both bodies directly
+
+    f[ibody][0] += fx;
+    f[ibody][1] += fy;
+    f[ibody][2] += fz;
+    sum_torque(x[ibody], pi, fx, fy, fz, torque[ibody]);
+
+    facc[0] += fx; facc[1] += fy; facc[2] += fz;
+
+    if (jflag) {
+      f[jbody][0] -= fx;
+      f[jbody][1] -= fy;
+      f[jbody][2] -= fz;
+      sum_torque(x[jbody], pj, -fx, -fy, -fz, torque[jbody]);
+    }
+  }
+}
+
+/* ----------------------------------------------------------------------
+  Kernel force is model-dependent and can be derived for other styles
+    here is the harmonic potential (linear piece-wise forces) in Wang et al.
+------------------------------------------------------------------------- */
+
+void PairBodyRoundedPolyhedron::kernel_force(double R, int itype, int jtype,
+  double& energy, double& fpair)
+{
+  double kn = k_n[itype][jtype];
+  double kna = k_na[itype][jtype];
+  double shift = kna * cut_inner;
+  double e = 0;
+  if (R <= 0) {           // deformation occurs
+    fpair = -kn * R - shift;
+    e = (0.5 * kn * R + shift) * R;
+  } else if (R <= cut_inner) {   // not deforming but cohesive ranges overlap
+    fpair = kna * R - shift;
+    e = (-0.5 * kna * R + shift) * R;
+  } else fpair = 0.0;
+  energy += e;
+}
+
+/* ----------------------------------------------------------------------
+  Compute contact forces between two bodies
+  modify the force stored at the vertex and edge in contact by j_a
+  sum forces and torque to the corresponding bodies
+  fx,fy,fz = unscaled cohesive forces
+  fn = normal friction component
+  ft = tangential friction component (-c_t * v_t)
+------------------------------------------------------------------------- */
+
+void PairBodyRoundedPolyhedron::contact_forces(int ibody, int jbody,
+  double *xi, double *xj, double delx, double dely, double delz,
+  double fx, double fy, double fz, double** x, double** v, double** angmom,
+  double** f, double** torque, double* facc)
+{
+  int ibonus,jbonus;
+  double rsq,rsqinv,vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3;
+  double fn[3],ft[3],vi[3],vj[3];
+  double *quat, *inertia;
+  AtomVecBody::Bonus *bonus;
+
+  // compute the velocity of the vertex in the space-fixed frame
+
+  ibonus = atom->body[ibody];
+  bonus = &avec->bonus[ibonus];
+  quat = bonus->quat;
+  inertia = bonus->inertia;
+  total_velocity(xi, x[ibody], v[ibody], angmom[ibody],
+                 inertia, quat, vi);
+
+  // compute the velocity of the point on the edge in the space-fixed frame
+
+  jbonus = atom->body[jbody];
+  bonus = &avec->bonus[jbonus];
+  quat = bonus->quat;
+  inertia = bonus->inertia;
+  total_velocity(xj, x[jbody], v[jbody], angmom[jbody],
+                 inertia, quat, vj);
+
+  // vector pointing from the contact point on ibody to that on jbody
+
+  rsq = delx*delx + dely*dely + delz*delz;
+  rsqinv = 1.0/rsq;
+
+  // relative translational velocity
+
+  vr1 = vi[0] - vj[0];
+  vr2 = vi[1] - vj[1];
+  vr3 = vi[2] - vj[2];
+
+  // normal component
+
+  vnnr = vr1*delx + vr2*dely + vr3*delz;
+  vn1 = delx*vnnr * rsqinv;
+  vn2 = dely*vnnr * rsqinv;
+  vn3 = delz*vnnr * rsqinv;
+
+  // tangential component
+
+  vt1 = vr1 - vn1;
+  vt2 = vr2 - vn2;
+  vt3 = vr3 - vn3;
+
+  // normal friction term at contact
+
+  fn[0] = -c_n * vn1;
+  fn[1] = -c_n * vn2;
+  fn[2] = -c_n * vn3;
+
+  // tangential friction term at contact
+  // excluding the tangential deformation term for now
+
+  ft[0] = -c_t * vt1;
+  ft[1] = -c_t * vt2;
+  ft[2] = -c_t * vt3;
+
+  // these are contact forces (F_n, F_t and F_ne) only
+  // cohesive forces will be scaled by j_a after contact area is computed
+  // mu * fne = tangential friction deformation during gross sliding
+  // see Eq. 4, Fraige et al.
+
+  fx = fn[0] + ft[0] + mu * fx;
+  fy = fn[1] + ft[1] + mu * fy;
+  fz = fn[2] + ft[2] + mu * fz;
+
+  f[ibody][0] += fx;
+  f[ibody][1] += fy;
+  f[ibody][2] += fz;
+  sum_torque(x[ibody], xi, fx, fy, fz, torque[ibody]);
+
+  f[jbody][0] -= fx;
+  f[jbody][1] -= fy;
+  f[jbody][2] -= fz;
+  sum_torque(x[jbody], xj, -fx, -fy, -fz, torque[jbody]);
+
+  facc[0] += fx; facc[1] += fy; facc[2] += fz;
+
+  #ifdef _POLYHEDRON_DEBUG
+  printf("contact ibody = %d: f = %f %f %f; torque = %f %f %f\n", ibody,
+     f[ibody][0], f[ibody][1], f[ibody][2],
+     torque[ibody][0], torque[ibody][1], torque[ibody][2]);
+  printf("contact jbody = %d: f = %f %f %f; torque = %f %f %f\n", jbody,
+     f[jbody][0], f[jbody][1], f[jbody][2],
+     torque[jbody][0], torque[jbody][1], torque[jbody][2]);
+  #endif
+}
+
+/* ----------------------------------------------------------------------
+  Rescale the forces and torques for all the contacts
+------------------------------------------------------------------------- */
+
+void PairBodyRoundedPolyhedron::rescale_cohesive_forces(double** x,
+     double** f, double** torque, Contact* contact_list, int &num_contacts,
+     int itype, int jtype, double* facc)
+{
+  int m,ibody,jbody;
+  double delx,dely,delz,fx,fy,fz,R,fpair,r,contact_area;
+
+  int num_unique_contacts = 0;
+  if (num_contacts == 1) {
+    num_unique_contacts = 1;
+    contact_area = 0;
+  } else if (num_contacts == 2) {
+    num_unique_contacts = 2;
+    contact_area = num_contacts * A_ua;
+  } else {
+    find_unique_contacts(contact_list, num_contacts);
+
+    double xc[3],dx,dy,dz;
+    xc[0] = xc[1] = xc[2] = 0;
+    num_unique_contacts = 0;
+    for (int m = 0; m < num_contacts; m++) {
+      if (contact_list[m].unique == 0) continue;
+      xc[0] += contact_list[m].xi[0];
+      xc[1] += contact_list[m].xi[1];
+      xc[2] += contact_list[m].xi[2];
+      num_unique_contacts++;
+    }
+
+    xc[0] /= (double)num_unique_contacts;
+    xc[1] /= (double)num_unique_contacts;
+    xc[2] /= (double)num_unique_contacts;
+    
+    contact_area = 0.0;
+    for (int m = 0; m < num_contacts; m++) {
+      if (contact_list[m].unique == 0) continue;
+      dx = contact_list[m].xi[0] - xc[0];
+      dy = contact_list[m].xi[1] - xc[1];
+      dz = contact_list[m].xi[2] - xc[2];
+      contact_area += (dx*dx + dy*dy + dz*dz);
+    }
+    contact_area *= (MY_PI/(double)num_unique_contacts);
+  }
+
+  double j_a = contact_area / (num_unique_contacts * A_ua);
+  if (j_a < 1.0) j_a = 1.0;
+  for (m = 0; m < num_contacts; m++) {
+    if (contact_list[m].unique == 0) continue;
+
+    ibody = contact_list[m].ibody;
+    jbody = contact_list[m].jbody;
+
+    delx = contact_list[m].xi[0] - contact_list[m].xj[0];
+    dely = contact_list[m].xi[1] - contact_list[m].xj[1];
+    delz = contact_list[m].xi[2] - contact_list[m].xj[2];
+    r = sqrt(delx*delx + dely*dely + delz*delz);
+    R = contact_list[m].separation;
+
+    double energy = 0;
+    kernel_force(R, itype, jtype, energy, fpair);
+
+    fpair *= j_a;
+    fx = delx*fpair/r;
+    fy = dely*fpair/r;
+    fz = delz*fpair/r;
+
+    f[ibody][0] += fx;
+    f[ibody][1] += fy;
+    f[ibody][2] += fz;
+    sum_torque(x[ibody], contact_list[m].xi, fx, fy, fz, torque[ibody]);
+
+    f[jbody][0] -= fx;
+    f[jbody][1] -= fy;
+    f[jbody][2] -= fz;
+    sum_torque(x[jbody], contact_list[m].xj, -fx, -fy, -fz, torque[jbody]);
+
+    facc[0] += fx; facc[1] += fy; facc[2] += fz;
+  }
+}
+
+/* ----------------------------------------------------------------------
+  Accumulate torque to body from the force f=(fx,fy,fz) acting at point x
+------------------------------------------------------------------------- */
+
+void PairBodyRoundedPolyhedron::sum_torque(double* xm, double *x, double fx,
+                                      double fy, double fz, double* torque)
+{
+  double rx = x[0] - xm[0];
+  double ry = x[1] - xm[1];
+  double rz = x[2] - xm[2];
+  double tx = ry * fz - rz * fy;
+  double ty = rz * fx - rx * fz;
+  double tz = rx * fy - ry * fx;
+  torque[0] += tx;
+  torque[1] += ty;
+  torque[2] += tz;
+}
+
+/* ----------------------------------------------------------------------
+  Test if two points a and b are in opposite sides of a plane defined by
+  a normal vector n and a point x0
+------------------------------------------------------------------------- */
+
+int PairBodyRoundedPolyhedron::opposite_sides(double* n, double* x0,
+                                           double* a, double* b)
+{
+  double m_a = n[0]*(a[0] - x0[0])+n[1]*(a[1] - x0[1])+n[2]*(a[2] - x0[2]);
+  double m_b = n[0]*(b[0] - x0[0])+n[1]*(b[1] - x0[1])+n[2]*(b[2] - x0[2]);
+  // equal to zero when either a or b is on the plane
+  if (m_a * m_b <= 0)
+    return 1;
+  else
+    return 0;
+}
+
+/* ----------------------------------------------------------------------
+  Test if a line segment defined by two points a and b intersects with
+  a triangle defined by three points x1, x2 and x3
+------------------------------------------------------------------------- */
+
+int PairBodyRoundedPolyhedron::edge_face_intersect(double* x1, double* x2,
+               double* x3, double* a, double* b, double* h_a, double* h_b,
+               double& d_a, double& d_b, int& inside_a, int& inside_b)
+{
+  double s[3], u[3], v[3], n[3];
+
+  // line director
+
+  MathExtra::sub3(b, a, s);
+
+  // plane normal vector
+
+  MathExtra::sub3(x2, x1, u);
+  MathExtra::sub3(x3, x1, v);
+  MathExtra::cross3(u, v, n);
+  MathExtra::norm3(n);
+
+  // find the projection of a and b to the plane and the corresponding distances
+
+  project_pt_plane(a, x1, x2, x3, h_a, d_a, inside_a);
+
+  project_pt_plane(b, x1, x2, x3, h_b, d_b, inside_b);
+
+  // check if the line segment is parallel to the plane
+
+  double dot = MathExtra::dot3(s, n);
+  if (fabs(dot) < EPSILON) return EF_PARALLEL;
+
+  // solve for the intersection between the line and the plane
+
+  double m[3][3], invm[3][3], p[3], ans[3];
+  m[0][0] = -s[0];
+  m[0][1] = u[0];
+  m[0][2] = v[0];
+
+  m[1][0] = -s[1];
+  m[1][1] = u[1];
+  m[1][2] = v[1];
+
+  m[2][0] = -s[2];
+  m[2][1] = u[2];
+  m[2][2] = v[2];
+
+  MathExtra::sub3(a, x1, p);
+  MathExtra::invert3(m, invm);
+  MathExtra::matvec(invm, p, ans);
+
+  // p is reused for the intersection point
+  // s = b - a
+
+  double t = ans[0];
+  p[0] = a[0] + s[0] * t;
+  p[1] = a[1] + s[1] * t;
+  p[2] = a[2] + s[2] * t;
+
+  // check if p is inside the triangle, excluding the edges and vertices
+  // the edge-edge and edge-vertices are handled separately
+
+  int inside = 0;
+  if (ans[1] > 0 && ans[2] > 0 && ans[1] + ans[2] < 1)
+    inside = 1;
+
+  int interact;
+  if (t < 0 || t > 1) {
+    interact = EF_SAME_SIDE_OF_FACE;
+  } else {
+    if (inside == 1) 
+      interact = EF_INTERSECT_INSIDE;
+    else
+      interact = EF_INTERSECT_OUTSIDE;
+  }
+  
+  return interact;
+}
+
+/* ----------------------------------------------------------------------
+  Find the projection of q on the plane defined by point p and the normal
+  unit vector n: q_proj = q - dot(q - p, n) * n
+  and the distance d from q to the plane
+------------------------------------------------------------------------- */
+
+void PairBodyRoundedPolyhedron::project_pt_plane(const double* q,
+                                        const double* p, const double* n,
+                                        double* q_proj, double &d)
+{
+  double dot, ans[3], n_p[3];
+  n_p[0] = n[0]; n_p[1] = n[1]; n_p[2] = n[2];
+  MathExtra::sub3(q, p, ans);
+  dot = MathExtra::dot3(ans, n_p);
+  MathExtra::scale3(dot, n_p);
+  MathExtra::sub3(q, n_p, q_proj);
+  MathExtra::sub3(q, q_proj, ans);
+  d = MathExtra::len3(ans);
+}
+
+/* ----------------------------------------------------------------------
+  Check if points q1 and q2 are inside a convex polygon, i.e. a face of
+  a polyhedron
+    ibody       = atom i's index
+    face_index  = face index of the body
+    xmi         = atom i's coordinates
+    q1          = tested point on the face (e.g. the projection of a point)
+    q2          = another point (can be NULL) for face-edge intersection
+  Output:
+    inside1     = 1 if q1 is inside the polygon, 0 otherwise
+    inside2     = 1 if q2 is inside the polygon, 0 otherwise
+------------------------------------------------------------------------- */
+
+void PairBodyRoundedPolyhedron::inside_polygon(int ibody, int face_index,
+                            double* xmi, const double* q1, const double* q2,
+                            int& inside1, int& inside2)
+
+{
+  int i,n,ifirst,iffirst,npi1,npi2;
+  double xi1[3],xi2[3],u[3],v[3],costheta,anglesum1,anglesum2,magu,magv;
+
+  ifirst = dfirst[ibody];
+  iffirst = facfirst[ibody];
+  anglesum1 = anglesum2 = 0;;
+  for (i = 0; i < MAX_FACE_SIZE; i++) {
+    npi1 = static_cast<int>(face[iffirst+face_index][i]);
+    if (npi1 < 0) break;
+    n = i + 1;
+    if (n <= MAX_FACE_SIZE - 1) {
+      npi2 = static_cast<int>(face[iffirst+face_index][n]);
+      if (npi2 < 0) npi2 = static_cast<int>(face[iffirst+face_index][0]);
+    } else {
+      npi2 = static_cast<int>(face[iffirst+face_index][0]);
+    }
+
+    xi1[0] = xmi[0] + discrete[ifirst+npi1][0];
+    xi1[1] = xmi[1] + discrete[ifirst+npi1][1];
+    xi1[2] = xmi[2] + discrete[ifirst+npi1][2];
+
+    xi2[0] = xmi[0] + discrete[ifirst+npi2][0];
+    xi2[1] = xmi[1] + discrete[ifirst+npi2][1];
+    xi2[2] = xmi[2] + discrete[ifirst+npi2][2];
+
+    MathExtra::sub3(xi1,q1,u);
+    MathExtra::sub3(xi2,q1,v);
+    magu = MathExtra::len3(u);
+    magv = MathExtra::len3(v);
+
+    // the point is at either vertices
+
+    if (magu * magv < EPSILON) inside1 = 1;
+    else {
+      costheta = MathExtra::dot3(u,v)/(magu*magv);
+      anglesum1 += acos(costheta);
+    }
+
+    if (q2 != NULL) {
+      MathExtra::sub3(xi1,q2,u);
+      MathExtra::sub3(xi2,q2,v);
+      magu = MathExtra::len3(u);
+      magv = MathExtra::len3(v);
+      if (magu * magv < EPSILON) inside2 = 1;
+      else {
+        costheta = MathExtra::dot3(u,v)/(magu*magv);
+        anglesum2 += acos(costheta);
+      }
+    }
+  }
+
+  if (fabs(anglesum1 - MY_2PI) < EPSILON) inside1 = 1;
+  else inside1 = 0;
+
+  if (q2 != NULL) {
+    if (fabs(anglesum2 - MY_2PI) < EPSILON) inside2 = 1;
+    else inside2 = 0;
+  }
+}
+
+/* ----------------------------------------------------------------------
+  Find the projection of q on the plane defined by 3 points x1, x2 and x3
+  returns the distance d from q to the plane and whether the projected
+  point is inside the triangle defined by (x1, x2, x3)
+------------------------------------------------------------------------- */
+
+void PairBodyRoundedPolyhedron::project_pt_plane(const double* q,
+      const double* x1, const double* x2, const double* x3, double* q_proj,
+      double &d, int& inside)
+{
+  double u[3],v[3],n[3];
+
+  // plane normal vector
+
+  MathExtra::sub3(x2, x1, u);
+  MathExtra::sub3(x3, x1, v);
+  MathExtra::cross3(u, v, n);
+  MathExtra::norm3(n);
+
+  // solve for the intersection between the line and the plane
+
+  double m[3][3], invm[3][3], p[3], ans[3];
+  m[0][0] = -n[0];
+  m[0][1] = u[0];
+  m[0][2] = v[0];
+
+  m[1][0] = -n[1];
+  m[1][1] = u[1];
+  m[1][2] = v[1];
+
+  m[2][0] = -n[2];
+  m[2][1] = u[2];
+  m[2][2] = v[2];
+
+  MathExtra::sub3(q, x1, p);
+  MathExtra::invert3(m, invm);
+  MathExtra::matvec(invm, p, ans);
+
+  double t = ans[0];
+  q_proj[0] = q[0] + n[0] * t;
+  q_proj[1] = q[1] + n[1] * t;
+  q_proj[2] = q[2] + n[2] * t;
+
+  // check if the projection point is inside the triangle
+  // exclude the edges and vertices 
+  // edge-sphere and sphere-sphere interactions are handled separately
+
+  inside = 0;
+  if (ans[1] > 0 && ans[2] > 0 && ans[1] + ans[2] < 1) {
+    inside = 1;
+  }
+
+  // distance from q to q_proj
+
+  MathExtra::sub3(q, q_proj, ans);
+  d = MathExtra::len3(ans);
+}
+
+/* ---------------------------------------------------------------------- */
+
+void PairBodyRoundedPolyhedron::project_pt_line(const double* q,
+     const double* xi1, const double* xi2, double* h, double& d, double& t)
+{
+  double u[3],v[3],r[3],s;
+
+  MathExtra::sub3(xi2, xi1, u);
+  MathExtra::norm3(u);
+  MathExtra::sub3(q, xi1, v);
+  
+  s = MathExtra::dot3(u, v);
+  h[0] = xi1[0] + s * u[0];
+  h[1] = xi1[1] + s * u[1];
+  h[2] = xi1[2] + s * u[2];
+
+  MathExtra::sub3(q, h, r);
+  d = MathExtra::len3(r);
+
+  if (fabs(xi2[0] - xi1[0]) > 0)
+    t = (h[0] - xi1[0])/(xi2[0] - xi1[0]);
+  else if (fabs(xi2[1] - xi1[1]) > 0)
+    t = (h[1] - xi1[1])/(xi2[1] - xi1[1]);
+  else if (fabs(xi2[2] - xi1[2]) > 0)
+    t = (h[2] - xi1[2])/(xi2[2] - xi1[2]);
+}
+
+/* ---------------------------------------------------------------------- 
+  compute the shortest distance between two edges (line segments)
+  x1, x2: two endpoints of the first edge
+  x3, x4: two endpoints of the second edge
+  h1: the end point of the shortest segment perpendicular to both edges 
+      on the line (x1;x2)
+  h2: the end point of the shortest segment perpendicular to both edges 
+      on the line (x3;x4)
+  t1: fraction of h1 in the segment (x1,x2)
+  t2: fraction of h2 in the segment (x3,x4)
+------------------------------------------------------------------------- */
+
+void PairBodyRoundedPolyhedron::distance_bt_edges(const double* x1,
+                  const double* x2, const double* x3, const double* x4,
+                  double* h1, double* h2, double& t1, double& t2, double& r)
+{
+  double u[3],v[3],n[3],dot;
+
+  // set the default returned values
+
+  t1 = -2;
+  t2 = 2;
+  r = 0;
+
+  // find the edge unit directors and their dot product
+
+  MathExtra::sub3(x2, x1, u);
+  MathExtra::norm3(u);
+  MathExtra::sub3(x4, x3, v);
+  MathExtra::norm3(v);
+  dot = MathExtra::dot3(u,v);
+  dot = fabs(dot);
+
+  // check if two edges are parallel
+  // find the two ends of the overlapping segment, if any
+
+  if (fabs(dot - 1.0) < EPSILON) {
+
+    double s1,s2,x13[3],x23[3],x13h[3];
+    double t13,t23,t31,t41,x31[3],x41[3];
+    
+    MathExtra::sub3(x1,x3,x13); // x13 = x1 - x3
+    MathExtra::sub3(x2,x3,x23); // x23 = x2 - x3
+
+    s1 = MathExtra::dot3(x13,v);
+    x13h[0] = x13[0] - s1*v[0];
+    x13h[1] = x13[1] - s1*v[1];
+    x13h[2] = x13[2] - s1*v[2];
+    r = MathExtra::len3(x13h);
+    
+    // x13 is the projection of x1 on x3-x4
+
+    x13[0] = x3[0] + s1*v[0];
+    x13[1] = x3[1] + s1*v[1];
+    x13[2] = x3[2] + s1*v[2];
+
+    // x23 is the projection of x2 on x3-x4
+
+    s2 = MathExtra::dot3(x23,v);
+    x23[0] = x3[0] + s2*v[0];
+    x23[1] = x3[1] + s2*v[1];
+    x23[2] = x3[2] + s2*v[2];
+    
+    // find the fraction of the projection points on the edges
+
+    if (fabs(x4[0] - x3[0]) > 0)
+      t13 = (x13[0] - x3[0])/(x4[0] - x3[0]);
+    else if (fabs(x4[1] - x3[1]) > 0)
+      t13 = (x13[1] - x3[1])/(x4[1] - x3[1]);
+    else if (fabs(x4[2] - x3[2]) > 0)
+      t13 = (x13[2] - x3[2])/(x4[2] - x3[2]);
+
+    if (fabs(x4[0] - x3[0]) > 0)
+      t23 = (x23[0] - x3[0])/(x4[0] - x3[0]);
+    else if (fabs(x4[1] - x3[1]) > 0)
+      t23 = (x23[1] - x3[1])/(x4[1] - x3[1]);
+    else if (fabs(x4[2] - x3[2]) > 0)
+      t23 = (x23[2] - x3[2])/(x4[2] - x3[2]);
+
+    if (fabs(x23[0] - x13[0]) > 0)
+      t31 = (x3[0] - x13[0])/(x23[0] - x13[0]);
+    else if (fabs(x23[1] - x13[1]) > 0)
+      t31 = (x3[1] - x13[1])/(x23[1] - x13[1]);
+    else if (fabs(x23[2] - x13[2]) > 0)
+      t31 = (x3[2] - x13[2])/(x23[2] - x13[2]);
+
+    // x31 is the projection of x3 on x1-x2
+
+    x31[0] = x1[0] + t31*(x2[0] - x1[0]);
+    x31[1] = x1[1] + t31*(x2[1] - x1[1]);
+    x31[2] = x1[2] + t31*(x2[2] - x1[2]);
+
+    if (fabs(x23[0] - x13[0]) > 0)
+      t41 = (x4[0] - x13[0])/(x23[0] - x13[0]);
+    else if (fabs(x23[1] - x13[1]) > 0)
+      t41 = (x4[1] - x13[1])/(x23[1] - x13[1]);
+    else if (fabs(x23[2] - x13[2]) > 0)
+      t41 = (x4[2] - x13[2])/(x23[2] - x13[2]);
+
+    // x41 is the projection of x4 on x1-x2
+
+    x41[0] = x1[0] + t41*(x2[0] - x1[0]);
+    x41[1] = x1[1] + t41*(x2[1] - x1[1]);
+    x41[2] = x1[2] + t41*(x2[2] - x1[2]);
+
+    // determine two ends from the overlapping segments
+
+    int n1 = 0;
+    int n2 = 0;
+    if (t13 >= 0 && t13 <= 1) {
+      h1[0] = x1[0];
+      h1[1] = x1[1];
+      h1[2] = x1[2];
+      h2[0] = x13[0];
+      h2[1] = x13[1];
+      h2[2] = x13[2];
+      t1 = 0;
+      t2 = t13;
+      n1++;
+      n2++;
+    }
+    if (t23 >= 0 && t23 <= 1) {
+      if (n1 == 0) {
+        h1[0] = x2[0];
+        h1[1] = x2[1];
+        h1[2] = x2[2];
+        h2[0] = x23[0];
+        h2[1] = x23[1];
+        h2[2] = x23[2];
+        t1 = 1;
+        t2 = t23;
+        n1++;
+        n2++;
+      } else {
+        h1[0] = (x1[0]+x2[0])/2;
+        h1[1] = (x1[1]+x2[1])/2;
+        h1[2] = (x1[2]+x2[2])/2;
+        h2[0] = (x13[0]+x23[0])/2; 
+        h2[1] = (x13[1]+x23[1])/2; 
+        h2[2] = (x13[2]+x23[2])/2;
+        t1 = 0.5;
+        t2 = (t13+t23)/2;
+        n1++;
+        n2++;
+      }
+    }
+
+    if (n1 == 0 && n2 == 0) {
+      if (t31 >= 0 && t31 <= 1) {
+        h1[0] = x31[0];
+        h1[1] = x31[1];
+        h1[2] = x31[2];
+        h2[0] = x3[0];
+        h2[1] = x3[1];
+        h2[2] = x3[2];
+        t1 = t31;
+        t2 = 0;
+        n1++;
+        n2++;
+      }
+      if (t41 >= 0 && t41 <= 1) {
+        if (n1 == 0) {
+          h1[0] = x41[0];
+          h1[1] = x41[1];
+          h1[2] = x41[2];
+          h2[0] = x4[0];
+          h2[1] = x4[1];
+          h2[2] = x4[2];
+          t1 = t41;
+          t2 = 1;
+          n1++;
+          n2++;
+        } else {
+          h1[0] = (x31[0]+x41[0])/2;
+          h1[1] = (x31[1]+x41[1])/2;
+          h1[2] = (x31[2]+x41[2])/2;
+          h2[0] = (x3[0]+x4[0])/2; 
+          h2[1] = (x3[1]+x4[1])/2; 
+          h2[2] = (x3[2]+x4[2])/2;
+          t1 = (t31+t41)/2;
+          t2 = 0.5;
+          n1++;
+          n2++;
+        }
+      }
+    }   
+
+    // if n1 == 0 and n2 == 0 at this point,
+    // which means no overlapping segments bt two parallel edges,
+    // return the default values of t1 and t2
+
+    return;
+
+  } 
+
+  // find the vector n perpendicular to both edges
+ 
+  MathExtra::cross3(u, v, n);
+  MathExtra::norm3(n);
+
+  // find the intersection of the line (x3,x4) and the plane (x1,x2,n)
+  // s = director of the line (x3,x4)
+  // n_p = plane normal vector of the plane (x1,x2,n)
+
+  double s[3], n_p[3];
+  MathExtra::sub3(x4, x3, s);
+  MathExtra::sub3(x2, x1, u);
+  MathExtra::cross3(u, n, n_p);
+  MathExtra::norm3(n_p);
+
+  // solve for the intersection between the line and the plane
+
+  double m[3][3], invm[3][3], p[3], ans[3];
+  m[0][0] = -s[0];
+  m[0][1] = u[0];
+  m[0][2] = n[0];
+
+  m[1][0] = -s[1];
+  m[1][1] = u[1];
+  m[1][2] = n[1];
+
+  m[2][0] = -s[2];
+  m[2][1] = u[2];
+  m[2][2] = n[2];
+
+  MathExtra::sub3(x3, x1, p);
+  MathExtra::invert3(m, invm);
+  MathExtra::matvec(invm, p, ans);
+
+  t2 = ans[0];
+  h2[0] = x3[0] + s[0] * t2;
+  h2[1] = x3[1] + s[1] * t2;
+  h2[2] = x3[2] + s[2] * t2;
+
+  project_pt_plane(h2, x1, n, h1, r);
+
+  if (fabs(x2[0] - x1[0]) > 0)
+    t1 = (h1[0] - x1[0])/(x2[0] - x1[0]);
+  else if (fabs(x2[1] - x1[1]) > 0)
+    t1 = (h1[1] - x1[1])/(x2[1] - x1[1]);
+  else if (fabs(x2[2] - x1[2]) > 0)
+    t1 = (h1[2] - x1[2])/(x2[2] - x1[2]);
+}
+
+/* ----------------------------------------------------------------------
+  Calculate the total velocity of a point (vertex, a point on an edge):
+    vi = vcm + omega ^ (p - xcm)
+------------------------------------------------------------------------- */
+
+void PairBodyRoundedPolyhedron::total_velocity(double* p, double *xcm,
+  double* vcm, double *angmom, double *inertia, double *quat, double* vi)
+{
+  double r[3],omega[3],ex_space[3],ey_space[3],ez_space[3];
+  r[0] = p[0] - xcm[0];
+  r[1] = p[1] - xcm[1];
+  r[2] = p[2] - xcm[2];
+  MathExtra::q_to_exyz(quat,ex_space,ey_space,ez_space);
+  MathExtra::angmom_to_omega(angmom,ex_space,ey_space,ez_space,
+                             inertia,omega);
+  vi[0] = omega[1]*r[2] - omega[2]*r[1] + vcm[0];
+  vi[1] = omega[2]*r[0] - omega[0]*r[2] + vcm[1];
+  vi[2] = omega[0]*r[1] - omega[1]*r[0] + vcm[2];
+}
+
+/* ----------------------------------------------------------------------
+  Determine the length of the contact segment, i.e. the separation between
+  2 contacts, should be extended for 3D models.
+------------------------------------------------------------------------- */
+
+double PairBodyRoundedPolyhedron::contact_separation(const Contact& c1,
+                                                     const Contact& c2)
+{
+  double x1 = 0.5*(c1.xi[0] + c1.xj[0]);
+  double y1 = 0.5*(c1.xi[1] + c1.xj[1]);
+  double z1 = 0.5*(c1.xi[2] + c1.xj[2]);
+  double x2 = 0.5*(c2.xi[0] + c2.xj[0]);
+  double y2 = 0.5*(c2.xi[1] + c2.xj[1]);
+  double z2 = 0.5*(c2.xi[2] + c2.xj[2]);
+  double rsq = (x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1) + (z2 - z1)*(z2 - z1);
+  return rsq;
+}
+
+/* ----------------------------------------------------------------------
+   find the number of unique contacts
+------------------------------------------------------------------------- */
+
+void PairBodyRoundedPolyhedron::find_unique_contacts(Contact* contact_list, 
+                                                     int& num_contacts)
+{
+  int n = num_contacts;
+  for (int i = 0; i < n - 1; i++) {
+
+    for (int j = i + 1; j < n; j++) {
+      if (contact_list[i].unique == 0) continue;
+      double d = contact_separation(contact_list[i], contact_list[j]);
+      if (d < EPSILON) contact_list[j].unique = 0;
+    }
+  }
+}
+
+/* ---------------------------------------------------------------------- */
+
+void PairBodyRoundedPolyhedron::sanity_check()
+{
+
+  double x1[3],x2[3],x3[3],x4[3],h_a[3],h_b[3],d_a,d_b,u[3],v[3],n[3];
+  double a[3],b[3],t_a,t_b;
+  int inside_a, inside_b;
+
+  x1[0] = 0; x1[1] = 3; x1[2] = 0;
+  x2[0] = 3; x2[1] = 0; x2[2] = 0;
+  x3[0] = 4; x3[1] = 3; x3[2] = 0;
+  x4[0] = 5; x4[1] = 3; x4[2] = 0;
+
+  a[0] = 0; a[1] = 0; a[2] = 0;
+  b[0] = 4; b[1] = 0; b[2] = 0;
+
+  project_pt_line(a, x1, x2, h_a, d_a, t_a);
+  project_pt_line(b, x1, x2, h_b, d_b, t_b);
+/*
+  printf("h_a: %f %f %f; h_b: %f %f %f; t_a = %f; t_b = %f; d = %f; d_b = %f\n",
+    h_a[0], h_a[1], h_a[2], h_b[0], h_b[1], h_b[2], t_a, t_b, d_a, d_b);
+*/
+/*
+  int mode = edge_face_intersect(x1, x2, x3, a, b, h_a, h_b, d_a, d_b,
+                                 inside_a, inside_b);
+
+  MathExtra::sub3(x2, x1, u);
+  MathExtra::sub3(x3, x1, v);
+  MathExtra::cross3(u, v, n);
+  MathExtra::norm3(n);
+*/
+/*
+  project_pt_plane(a, x1, x2, x3, h_a, d_a, inside_a);
+  printf("h_a: %f %f %f; d = %f: inside %d\n",
+    h_a[0], h_a[1], h_a[2], d_a, inside_a);
+  project_pt_plane(b, x1, x2, x3, h_b, d_b, inside_b);
+  printf("h_b: %f %f %f; d = %f: inside %d\n",
+    h_b[0], h_b[1], h_b[2], d_b, inside_b);
+*/
+/*
+  distance_bt_edges(x1, x2, x3, x4, h_a, h_b, t_a, t_b, d_a);
+  printf("h_a: %f %f %f; h_b: %f %f %f; t_a = %f; t_b = %f; d = %f\n",
+    h_a[0], h_a[1], h_a[2], h_b[0], h_b[1], h_b[2], t_a, t_b, d_a);
+*/
+}
+
diff --git a/src/BODY/pair_body_rounded_polyhedron.h b/src/BODY/pair_body_rounded_polyhedron.h
new file mode 100644
index 0000000000000000000000000000000000000000..71c04ff9665aa0b24b7e7f4069cc4f4f4766bf4d
--- /dev/null
+++ b/src/BODY/pair_body_rounded_polyhedron.h
@@ -0,0 +1,200 @@
+/* -*- 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 PAIR_CLASS
+
+PairStyle(body/rounded/polyhedron,PairBodyRoundedPolyhedron)
+
+#else
+
+#ifndef LMP_PAIR_BODY_ROUNDED_POLYHEDRON_H
+#define LMP_PAIR_BODY_ROUNDED_POLYHEDRON_H
+
+#include "pair.h"
+
+namespace LAMMPS_NS {
+
+class PairBodyRoundedPolyhedron : public Pair {
+ public:
+  PairBodyRoundedPolyhedron(class LAMMPS *);
+  ~PairBodyRoundedPolyhedron();
+  void compute(int, int);
+  void settings(int, char **);
+  void coeff(int, char **);
+  void init_style();
+  double init_one(int, int);
+
+  virtual void kernel_force(double R, int itype, int jtype,
+    double& energy, double& fpair);
+
+  struct Contact {
+    int ibody, jbody;  // body (i.e. atom) indices (not tags)
+    int type;          // 0 = VERTEX-FACE; 1 = EDGE-EDGE
+    double fx,fy,fz;   // unscaled cohesive forces at contact
+    double xi[3];      // coordinates of the contact point on ibody
+    double xj[3];      // coordinates of the contact point on jbody
+    double separation; // contact surface separation
+    int unique;
+  };
+
+ protected:
+  double **k_n;       // normal repulsion strength
+  double **k_na;      // normal attraction strength
+  double c_n;         // normal damping coefficient
+  double c_t;         // tangential damping coefficient
+  double mu;          // normal friction coefficient during gross sliding
+  double A_ua;        // characteristic contact area
+  double cut_inner;   // cutoff for interaction between vertex-edge surfaces
+
+  class AtomVecBody *avec;
+  class BodyRoundedPolyhedron *bptr;
+
+  double **discrete;  // list of all sub-particles for all bodies
+  int ndiscrete;      // number of discretes in list
+  int dmax;           // allocated size of discrete list
+  int *dnum;          // number of discretes per line, 0 if uninit
+  int *dfirst;        // index of first discrete per each line
+  int nmax;           // allocated size of dnum,dfirst vectors
+
+  double **edge;      // list of all edge for all bodies
+  int nedge;          // number of edge in list
+  int edmax;          // allocated size of edge list
+  int *ednum;         // number of edges per line, 0 if uninit
+  int *edfirst;       // index of first edge per each line
+  int ednummax;       // allocated size of ednum,edfirst vectors
+
+  double **face;      // list of all edge for all bodies
+  int nface;          // number of faces in list
+  int facmax;         // allocated size of face list
+  int *facnum;        // number of faces per line, 0 if uninit
+  int *facfirst;      // index of first face per each line
+  int facnummax;      // allocated size of facnum,facfirst vectors
+
+  double *enclosing_radius; // enclosing radii for all bodies
+  double *rounded_radius;   // rounded radii for all bodies
+  double *maxerad;          // per-type maximum enclosing radius
+
+  void allocate();
+  void body2space(int);
+
+  // sphere-sphere interaction
+  void sphere_against_sphere(int ibody, int jbody, int itype, int jtype,
+                             double delx, double dely, double delz, double rsq,
+                             double** v, double** f, int evflag);
+  // sphere-edge interaction
+  void sphere_against_edge(int ibody, int jbody, int itype, int jtype,
+                           double** x, double** v, double** f, double** torque,
+                           double** angmom, int evflag);
+  // sphere-face interaction
+  void sphere_against_face(int ibody, int jbody, int itype, int jtype,
+                           double** x, double** v, double** f, double** torque,
+                           double** angmom, int evflag);
+  // edge-edge interactions
+  int edge_against_edge(int ibody, int jbody, int itype, int jtype,
+                        double** x,Contact* contact_list, int &num_contacts,
+                        double &evdwl, double* facc);
+  // edge-face interactions
+  int edge_against_face(int ibody, int jbody, int itype, int jtype,
+                        double** x, Contact* contact_list, int &num_contacts,
+                        double &evdwl, double* facc);
+
+  // a face vs. a single edge
+  int interaction_face_to_edge(int ibody, int face_index, double* xmi,
+                               double rounded_radius_i, int jbody, int edge_index,
+                               double* xmj, double rounded_radius_j,
+                               int itype, int jtype, double cut_inner,
+                               Contact* contact_list, int &num_contacts,
+                               double& energy, double* facc);
+  // an edge vs. an edge from another body
+  int interaction_edge_to_edge(int ibody, int edge_index_i, double* xmi,
+                               double rounded_radius_i, int jbody, int edge_index_j,
+                               double* xmj, double rounded_radius_j,
+                               int itype, int jtype, double cut_inner,
+                               Contact* contact_list, int &num_contacts,
+                               double& energy, double* facc);
+
+  // compute contact forces if contact points are detected
+  void contact_forces(int ibody, int jbody, double *xi, double *xj,
+    double delx, double dely, double delz, double fx, double fy, double fz,
+    double** x, double** v, double** angmom, double** f, double** torque,
+    double* facc);
+
+  // compute force and torque between two bodies given a pair of interacting points
+  void pair_force_and_torque(int ibody, int jbody, double* pi, double* pj,
+                             double r, double contact_dist, int itype, int jtype,
+                             double** x, double** v, double** f, double** torque,
+                             double** angmom, int jflag, double& energy, double* facc);
+
+  // rescale the cohesive forces if a contact area is detected
+  void rescale_cohesive_forces(double** x, double** f, double** torque,
+                               Contact* contact_list, int &num_contacts,
+                               int itype, int jtype, double* facc);
+
+  // compute the separation between two contacts
+  double contact_separation(const Contact& c1, const Contact& c2);
+
+  // detect the unique contact points (as there may be double counts)
+  void find_unique_contacts(Contact* contact_list, int& num_contacts);
+
+  // accumulate torque to a body given a force at a given point
+  void sum_torque(double* xm, double *x, double fx, double fy, double fz, double* torque);
+
+  // find the intersection point (if any) between an edge and a face
+  int edge_face_intersect(double* x1, double* x2, double* x3, double* a, double* b,
+                          double* hi1, double* hi2, double& d1, double& d2,
+                          int& inside_a, int& inside_b);
+  // helper functions
+  int opposite_sides(double* n, double* x0, double* a, double* b);
+  void project_pt_plane(const double* q, const double* p, 
+                        const double* n, double* q_proj, double &d);
+  void project_pt_plane(const double* q, const double* x1, const double* x2, 
+                        const double* x3, double* q_proj, double &d, int& inside);
+  void project_pt_line(const double* q, const double* xi1, const double* xi2,
+                          double* h, double& d, double& t);
+  void inside_polygon(int ibody, int face_index, double* xmi, 
+                     const double* q1, const double* q2, int& inside1, int& inside2);
+
+  void distance_bt_edges(const double* x1, const double* x2,
+                      const double* x3, const double* x4,
+                      double* h1, double* h2, double& t1, double& t2, double& r);
+  void total_velocity(double* p, double *xcm, double* vcm, double *angmom,
+                      double *inertia, double *quat, double* vi);
+  void sanity_check();
+};
+
+}
+
+#endif
+#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: Incorrect args for pair coefficients
+
+Self-explanatory.  Check the input script or data file.
+
+E: Pair body/rounded/polyhedron requires atom style body rounded/polyhedron
+
+Self-explanatory.
+
+E: Pair body requires body style rounded/polyhedron
+
+This pair style is specific to the rounded/polyhedron body style.
+
+*/
diff --git a/src/GPU/gpu_extra.h b/src/GPU/gpu_extra.h
index 56a4f15f1bff5a18ee050badf8acfb420c97b28b..111d13c563a2fc129c1d6e816f38dd7479c8c97a 100644
--- a/src/GPU/gpu_extra.h
+++ b/src/GPU/gpu_extra.h
@@ -58,6 +58,9 @@ namespace GPU_EXTRA {
       else if (all_success == -11)
         error->all(FLERR,
                    "Invalid custom OpenCL parameter string.");
+      else if (all_success == -12)
+        error->all(FLERR,
+                   "Invalid OpenCL platform ID.");
       else
         error->all(FLERR,"Unknown error in GPU library");
     }
diff --git a/src/KOKKOS/fix_shardlow_kokkos.cpp b/src/KOKKOS/fix_shardlow_kokkos.cpp
index 70055bf8c9df4fd0f70f32b83e012e9eec0132c9..99e51ebe38e0a154683ff6b5476a467e3fba4941 100644
--- a/src/KOKKOS/fix_shardlow_kokkos.cpp
+++ b/src/KOKKOS/fix_shardlow_kokkos.cpp
@@ -157,7 +157,6 @@ void FixShardlowKokkos<DeviceType>::init()
   k_pairDPDE->k_cutsq.template sync<DeviceType>();
   d_cutsq = k_pairDPDE->k_cutsq.template view<DeviceType>();
 
-  const double boltz2 = 2.0*force->boltz;
   for (int i = 1; i <= ntypes; i++) {
     for (int j = i; j <= ntypes; j++) {
       F_FLOAT cutone = k_pairDPDE->cut[i][j];
@@ -165,7 +164,7 @@ void FixShardlowKokkos<DeviceType>::init()
       else k_params.h_view(i,j).cutinv = FLT_MAX;
       k_params.h_view(i,j).halfsigma = 0.5*k_pairDPDE->sigma[i][j];
       k_params.h_view(i,j).kappa = k_pairDPDE->kappa[i][j];
-      k_params.h_view(i,j).alpha = sqrt(boltz2*k_pairDPDE->kappa[i][j]);
+      k_params.h_view(i,j).alpha = k_pairDPDE->alpha[i][j];
 
       k_params.h_view(j,i) = k_params.h_view(i,j);
 
diff --git a/src/KOKKOS/pair_dpd_fdt_energy_kokkos.cpp b/src/KOKKOS/pair_dpd_fdt_energy_kokkos.cpp
index 7ff536f8dd792c77515ec0e0f55a569d1f4763ef..038d95394ac6947036e44e39c0f684251e5ddd31 100644
--- a/src/KOKKOS/pair_dpd_fdt_energy_kokkos.cpp
+++ b/src/KOKKOS/pair_dpd_fdt_energy_kokkos.cpp
@@ -591,7 +591,7 @@ void PairDPDfdtEnergyKokkos<DeviceType>::operator()(TagPairDPDfdtEnergyComputeNo
       // Compute uCond
       randnum = rand_gen.normal();
       kappa_ij = STACKPARAMS?m_params[itype][jtype].kappa:params(itype,jtype).kappa;
-      alpha_ij = sqrt(2.0*boltz*kappa_ij);
+      alpha_ij = STACKPARAMS?m_params[itype][jtype].alpha:params(itype,jtype).alpha;
       randPair = alpha_ij*wr*randnum*dtinvsqrt;
 
       uTmp = kappa_ij*(1.0/dpdTheta[i] - 1.0/dpdTheta[j])*wd;
@@ -676,6 +676,7 @@ double PairDPDfdtEnergyKokkos<DeviceType>::init_one(int i, int j)
   k_params.h_view(i,j).a0 = a0[i][j];
   k_params.h_view(i,j).sigma = sigma[i][j];
   k_params.h_view(i,j).kappa = kappa[i][j];
+  k_params.h_view(i,j).alpha = alpha[i][j];
   k_params.h_view(j,i) = k_params.h_view(i,j);
   if(i<MAX_TYPES_STACKPARAMS+1 && j<MAX_TYPES_STACKPARAMS+1) {
     m_params[i][j] = m_params[j][i] = k_params.h_view(i,j);
diff --git a/src/KOKKOS/pair_dpd_fdt_energy_kokkos.h b/src/KOKKOS/pair_dpd_fdt_energy_kokkos.h
index 424779f839240d90bf4fb51495c97fcfad2fe627..12ffb668e200a01e51555376c78f235ee0739358 100644
--- a/src/KOKKOS/pair_dpd_fdt_energy_kokkos.h
+++ b/src/KOKKOS/pair_dpd_fdt_energy_kokkos.h
@@ -88,10 +88,10 @@ class PairDPDfdtEnergyKokkos : public PairDPDfdtEnergy {
 
   struct params_dpd {
     KOKKOS_INLINE_FUNCTION
-    params_dpd(){cut=0;a0=0;sigma=0;kappa=0;};
+    params_dpd(){cut=0;a0=0;sigma=0;kappa=0;alpha=0;};
     KOKKOS_INLINE_FUNCTION
-    params_dpd(int i){cut=0;a0=0;sigma=0;kappa=0;};
-    F_FLOAT cut,a0,sigma,kappa;
+    params_dpd(int i){cut=0;a0=0;sigma=0;kappa=0;alpha=0;};
+    F_FLOAT cut,a0,sigma,kappa,alpha;
   };
 
   DAT::tdual_efloat_1d k_duCond,k_duMech;
diff --git a/src/MC/fix_gcmc.cpp b/src/MC/fix_gcmc.cpp
index 6221e6d52c26b359d9efd7d87460a1ed3ceacaf3..b40ce6a1b3342bf185846a37b7caa0ca8c6a0c10 100644
--- a/src/MC/fix_gcmc.cpp
+++ b/src/MC/fix_gcmc.cpp
@@ -1589,6 +1589,7 @@ void FixGCMC::attempt_atomic_deletion_full()
     }
   }
   if (force->kspace) force->kspace->qsum_qsq();
+  if (force->pair->tail_flag) force->pair->reinit();
   double energy_after = energy_full();
 
   if (random_equal->uniform() <
@@ -1607,6 +1608,7 @@ void FixGCMC::attempt_atomic_deletion_full()
       if (q_flag) atom->q[i] = q_tmp;
     }
     if (force->kspace) force->kspace->qsum_qsq();
+    if (force->pair->tail_flag) force->pair->reinit();
     energy_stored = energy_before;
   }
   update_gas_atoms_list();
@@ -1700,6 +1702,7 @@ void FixGCMC::attempt_atomic_insertion_full()
   comm->borders();
   if (triclinic) domain->lamda2x(atom->nlocal+atom->nghost);
   if (force->kspace) force->kspace->qsum_qsq();
+  if (force->pair->tail_flag) force->pair->reinit();
   double energy_after = energy_full();
 
   if (energy_after < MAXENERGYTEST &&
@@ -1712,6 +1715,7 @@ void FixGCMC::attempt_atomic_insertion_full()
     atom->natoms--;
     if (proc_flag) atom->nlocal--;
     if (force->kspace) force->kspace->qsum_qsq();
+    if (force->pair->tail_flag) force->pair->reinit();
     energy_stored = energy_before;
   }
   update_gas_atoms_list();
@@ -1949,6 +1953,7 @@ void FixGCMC::attempt_molecule_deletion_full()
     }
   }
   if (force->kspace) force->kspace->qsum_qsq();
+  if (force->pair->tail_flag) force->pair->reinit();
   double energy_after = energy_full();
 
   // energy_before corrected by energy_intra
@@ -1981,6 +1986,7 @@ void FixGCMC::attempt_molecule_deletion_full()
       }
     }
     if (force->kspace) force->kspace->qsum_qsq();
+    if (force->pair->tail_flag) force->pair->reinit();
   }
   update_gas_atoms_list();
   delete[] tmpmask;
@@ -2151,6 +2157,7 @@ void FixGCMC::attempt_molecule_insertion_full()
   comm->borders();
   if (triclinic) domain->lamda2x(atom->nlocal+atom->nghost);
   if (force->kspace) force->kspace->qsum_qsq();
+  if (force->pair->tail_flag) force->pair->reinit();
   double energy_after = energy_full();
 
   // energy_after corrected by energy_intra
@@ -2181,6 +2188,7 @@ void FixGCMC::attempt_molecule_insertion_full()
       } else i++;
     }
     if (force->kspace) force->kspace->qsum_qsq();
+    if (force->pair->tail_flag) force->pair->reinit();
   }
   update_gas_atoms_list();
 }
diff --git a/src/Purge.list b/src/Purge.list
index 402fc409e6069980a034b9cc83aefa4d06d3b6a0..cd4eb17dab5d142b0fde5bb4673d3266271645fd 100644
--- a/src/Purge.list
+++ b/src/Purge.list
@@ -24,6 +24,9 @@ style_nstencil.h
 style_ntopo.h
 # other auto-generated files
 lmpinstalledpkgs.h
+# renamed on 20 July 2018
+pair_body.h
+pair_body.cpp
 # deleted on 4 April 2018
 pair_kim_version.h
 # deleted on 15 December 2017
diff --git a/src/USER-DPD/fix_shardlow.cpp b/src/USER-DPD/fix_shardlow.cpp
index 06185dee7ec702d2dfb3a4686fa88c2c7e3b16f8..7fe865c8e6a9bce50d863c5f5cb14d8b119c1fef 100644
--- a/src/USER-DPD/fix_shardlow.cpp
+++ b/src/USER-DPD/fix_shardlow.cpp
@@ -354,9 +354,8 @@ void FixShardlow::ssa_update_dpde(
   double *uMech = atom->uMech;
   double *dpdTheta = atom->dpdTheta;
 
-  double *cut_i, *cut2_i, *sigma_i, *kappa_i;
+  double *cut_i, *cut2_i, *sigma_i, *kappa_i, *alpha_i;
   double theta_ij_inv, theta_i_inv;
-  const double boltz2 = 2.0*force->boltz;
   const double boltz_inv = 1.0/force->boltz;
   const double ftm2v = force->ftm2v;
 
@@ -389,6 +388,7 @@ while (ct-- > 0) {
   cut_i  = pairDPDE->cut[itype];
   sigma_i = pairDPDE->sigma[itype];
   kappa_i = pairDPDE->kappa[itype];
+  alpha_i = pairDPDE->alpha[itype];
   theta_i_inv = 1.0/dpdTheta[i];
   const double mass_i = (rmass) ? rmass[i] : mass[itype];
   const double massinv_i = 1.0 / mass_i;
@@ -448,7 +448,7 @@ while (ct-- > 0) {
 
       // Compute uCond
       double kappa_ij = kappa_i[jtype];
-      double alpha_ij = sqrt(boltz2*kappa_ij);
+      double alpha_ij = alpha_i[jtype];
       double del_uCond = alpha_ij*wr*dtsqrt * es_normal(RNGstate);
 
       del_uCond += kappa_ij*(theta_i_inv - theta_j_inv)*wdt;
diff --git a/src/USER-DPD/pair_dpd_fdt_energy.cpp b/src/USER-DPD/pair_dpd_fdt_energy.cpp
index d1f3cceed4ca14db73014d7e252770b007d8db95..05dc52eac787b974cf628bf9fd22b984763fab57 100644
--- a/src/USER-DPD/pair_dpd_fdt_energy.cpp
+++ b/src/USER-DPD/pair_dpd_fdt_energy.cpp
@@ -65,6 +65,7 @@ PairDPDfdtEnergy::~PairDPDfdtEnergy()
     memory->destroy(a0);
     memory->destroy(sigma);
     memory->destroy(kappa);
+    memory->destroy(alpha);
     memory->destroy(duCond);
     memory->destroy(duMech);
   }
@@ -269,7 +270,7 @@ void PairDPDfdtEnergy::compute(int eflag, int vflag)
           // Compute uCond
           randnum = random->gaussian();
           kappa_ij = kappa[itype][jtype];
-          alpha_ij = sqrt(2.0*force->boltz*kappa_ij);
+          alpha_ij = alpha[itype][jtype];
           randPair = alpha_ij*wr*randnum*dtinvsqrt;
 
           uTmp = kappa_ij*(1.0/dpdTheta[i] - 1.0/dpdTheta[j])*wd;
@@ -322,6 +323,7 @@ void PairDPDfdtEnergy::allocate()
   memory->create(a0,n+1,n+1,"pair:a0");
   memory->create(sigma,n+1,n+1,"pair:sigma");
   memory->create(kappa,n+1,n+1,"pair:kappa");
+  memory->create(alpha,n+1,n+1,"pair:alpha");
   if (!splitFDT_flag) {
     memory->create(duCond,nlocal+nghost+1,"pair:duCond");
     memory->create(duMech,nlocal+nghost+1,"pair:duMech");
@@ -374,11 +376,12 @@ void PairDPDfdtEnergy::coeff(int narg, char **arg)
   double a0_one = force->numeric(FLERR,arg[2]);
   double sigma_one = force->numeric(FLERR,arg[3]);
   double cut_one = cut_global;
-  double kappa_one;
+  double kappa_one, alpha_one;
 
   a0_is_zero = (a0_one == 0.0); // Typical use with SSA is to set a0 to zero
 
   kappa_one = force->numeric(FLERR,arg[4]);
+  alpha_one = sqrt(2.0*force->boltz*kappa_one);
   if (narg == 6) cut_one = force->numeric(FLERR,arg[5]);
 
   int count = 0;
@@ -387,6 +390,7 @@ void PairDPDfdtEnergy::coeff(int narg, char **arg)
       a0[i][j] = a0_one;
       sigma[i][j] = sigma_one;
       kappa[i][j] = kappa_one;
+      alpha[i][j] = alpha_one;
       cut[i][j] = cut_one;
       setflag[i][j] = 1;
       count++;
@@ -435,6 +439,7 @@ double PairDPDfdtEnergy::init_one(int i, int j)
   a0[j][i] = a0[i][j];
   sigma[j][i] = sigma[i][j];
   kappa[j][i] = kappa[i][j];
+  alpha[j][i] = alpha[i][j];
 
   return cut[i][j];
 }
@@ -488,6 +493,7 @@ void PairDPDfdtEnergy::read_restart(FILE *fp)
         MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world);
         MPI_Bcast(&kappa[i][j],1,MPI_DOUBLE,0,world);
         MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world);
+        alpha[i][j] = sqrt(2.0*force->boltz*kappa[i][j]);
         a0_is_zero = a0_is_zero && (a0[i][j] == 0.0); // verify the zero assumption
       }
     }
diff --git a/src/USER-DPD/pair_dpd_fdt_energy.h b/src/USER-DPD/pair_dpd_fdt_energy.h
index dce39f83f071904a0e8d832095edc0f1a7d85a0a..e21b48f7bdb99a28b0735f1a25d38f47c60a8ada 100644
--- a/src/USER-DPD/pair_dpd_fdt_energy.h
+++ b/src/USER-DPD/pair_dpd_fdt_energy.h
@@ -43,7 +43,7 @@ class PairDPDfdtEnergy : public Pair {
 
   double **cut;
   double **a0;
-  double **sigma,**kappa;
+  double **sigma,**kappa,**alpha;
   double *duCond,*duMech;
 
   int seed;
diff --git a/src/error.cpp b/src/error.cpp
index d516050385c212ae0c8eb7da4466778baf96a447..3feaf1d1acde855d71ca3d3fd79ed5afd83934d2 100644
--- a/src/error.cpp
+++ b/src/error.cpp
@@ -16,6 +16,7 @@
 #include <cstring>
 #include "error.h"
 #include "universe.h"
+#include "update.h"
 #include "output.h"
 #include "input.h"
 
@@ -69,6 +70,10 @@ void Error::universe_all(const char *file, int line, const char *str)
   if (universe->ulogfile) fclose(universe->ulogfile);
 
 #ifdef LAMMPS_EXCEPTIONS
+
+  // allow commands if an exception was caught in a run
+  update->whichflag = 0;
+
   char msg[100];
   sprintf(msg, "ERROR: %s (%s:%d)\n", str, file, line);
   throw LAMMPSException(msg);
@@ -90,6 +95,10 @@ void Error::universe_one(const char *file, int line, const char *str)
             universe->me,str,truncpath(file),line);
 
 #ifdef LAMMPS_EXCEPTIONS
+
+  // allow commands if an exception was caught in a run
+  update->whichflag = 0;
+
   char msg[100];
   sprintf(msg, "ERROR: %s (%s:%d)\n", str, file, line);
   throw LAMMPSAbortException(msg, universe->uworld);
@@ -137,6 +146,10 @@ void Error::all(const char *file, int line, const char *str)
   }
 
 #ifdef LAMMPS_EXCEPTIONS
+
+  // allow commands if an exception was caught in a run
+  update->whichflag = 0;
+
   char msg[100];
   sprintf(msg, "ERROR: %s (%s:%d)\n", str, file, line);
 
@@ -183,6 +196,10 @@ void Error::one(const char *file, int line, const char *str)
               universe->me,str,truncpath(file),line);
 
 #ifdef LAMMPS_EXCEPTIONS
+
+  // allow commands if an exception was caught in a run
+  update->whichflag = 0;
+
   char msg[100];
   sprintf(msg, "ERROR on proc %d: %s (%s:%d)\n", me, str, file, line);
   throw LAMMPSAbortException(msg, world);
diff --git a/src/pair.cpp b/src/pair.cpp
index 9bb1ad212f19de34473e5f115d22b3c8bebe2acb..5c308cc7ce51e840713abfaeacdcbd8190ce95e9 100644
--- a/src/pair.cpp
+++ b/src/pair.cpp
@@ -693,17 +693,19 @@ void Pair::compute_dummy(int eflag, int vflag)
 }
 
 /* ---------------------------------------------------------------------- */
+
 void Pair::read_restart(FILE *)
 {
   if (comm->me == 0)
-    error->warning(FLERR,"BUG: restartinfo=1 but no restart support in pair style");
+    error->warning(FLERR,"Pair style restartinfo set but has no restart support");
 }
 
 /* ---------------------------------------------------------------------- */
+
 void Pair::write_restart(FILE *)
 {
   if (comm->me == 0)
-    error->warning(FLERR,"BUG: restartinfo=1 but no restart support in pair style");
+    error->warning(FLERR,"Pair style restartinfo set but has no restart support");
 }
 
 /* -------------------------------------------------------------------