diff --git a/src/BODY/Install.sh b/src/BODY/Install.sh
new file mode 100644
index 000000000..1836224e1
--- /dev/null
+++ b/src/BODY/Install.sh
@@ -0,0 +1,27 @@
+# Install/unInstall package files in LAMMPS
+
+if (test $1 = 1) then
+
+  cp body_nparticle.cpp ..
+  cp compute_body_local.cpp ..
+  cp fix_nve_body.cpp ..
+  cp pair_body.cpp ..
+
+  cp body_nparticle.h ..
+  cp compute_body_local.h ..
+  cp fix_nve_body.h ..
+  cp pair_body.h ..
+
+elif (test $1 = 0) then
+
+  rm -f ../body_nparticle.cpp
+  rm -f ../compute_body_local.cpp
+  rm -f ../fix_nve_body.cpp
+  rm -f ../pair_body.cpp
+
+  rm -f ../body_nparticle.h
+  rm -f ../compute_body_local.h
+  rm -f ../fix_nve_body.h
+  rm -f ../pair_body.h
+
+fi
diff --git a/src/BODY/body_nparticle.cpp b/src/BODY/body_nparticle.cpp
new file mode 100644
index 000000000..6d3ceecac
--- /dev/null
+++ b/src/BODY/body_nparticle.cpp
@@ -0,0 +1,201 @@
+/* ----------------------------------------------------------------------
+   LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
+   http://lammps.sandia.gov, Sandia National Laboratories
+   Steve Plimpton, sjplimp@sandia.gov
+
+   Copyright (2003) Sandia Corporation.  Under the terms of Contract
+   DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
+   certain rights in this software.  This software is distributed under
+   the GNU General Public License.
+
+   See the README file in the top-level LAMMPS directory.
+------------------------------------------------------------------------- */
+
+#include "stdlib.h"
+#include "body_nparticle.h"
+#include "math_extra.h"
+#include "atom_vec_body.h"
+#include "atom.h"
+#include "memory.h"
+#include "error.h"
+
+using namespace LAMMPS_NS;
+
+#define EPSILON 1.0e-7
+
+/* ---------------------------------------------------------------------- */
+
+BodyNparticle::BodyNparticle(LAMMPS *lmp, int narg, char **arg) : 
+  Body(lmp, narg, arg)
+{
+  if (narg != 3) error->all(FLERR,"Invalid body nparticle command");
+
+  int nmin = atoi(arg[1]);
+  int nmax = atoi(arg[2]);
+  if (nmin <= 0 || nmin > nmax) 
+    error->all(FLERR,"Invalid body nparticle command");
+
+  size_forward = 0;
+  size_border = 1 + 3*nmax;
+}
+
+/* ---------------------------------------------------------------------- */
+
+int BodyNparticle::nsub(AtomVecBody::Bonus *bonus)
+{
+  return bonus->ivalue[0];
+}
+
+/* ---------------------------------------------------------------------- */
+
+double *BodyNparticle::coords(AtomVecBody::Bonus *bonus)
+{
+  return bonus->dvalue;
+}
+
+/* ---------------------------------------------------------------------- */
+
+int BodyNparticle::pack_border_body(AtomVecBody::Bonus *bonus, double *buf)
+{
+  int nsub = bonus->ivalue[0];
+  buf[0] = nsub;
+  memcpy(&buf[1],bonus->dvalue,3*nsub*sizeof(double));
+  return 1+3*nsub;
+}
+
+/* ---------------------------------------------------------------------- */
+
+int BodyNparticle::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*sizeof(double));
+  return 1+3*nsub;
+}
+
+/* ----------------------------------------------------------------------
+   populate bonus data structure with data file values
+------------------------------------------------------------------------- */
+
+void BodyNparticle::data_body(int ibonus, int ninteger, int ndouble, 
+                              char **ifile, char **dfile)
+{
+  AtomVecBody::Bonus *bonus = &avec->bonus[ibonus];
+
+  // error in data file if any values are NULL
+
+  for (int i = 0; i < ninteger; i++)
+    if (ifile[0] == NULL) error->one(FLERR,"");
+  for (int i = 0; i < ndouble; i++)
+    if (dfile[0] == NULL) error->one(FLERR,"");
+
+  // set ninteger, ndouble in bonus and allocate 2 vectors of ints, doubles  
+
+  if (ninteger != 1) error->one(FLERR,"");
+  int nsub = atoi(ifile[0]);
+  if (nsub < 1) error->one(FLERR,"");
+  if (ndouble != 6 + 3*nsub) error->one(FLERR,"");
+
+  bonus->ninteger = 1;
+  memory->create(bonus->ivalue,bonus->ninteger,"body:ivalue");
+  bonus->ivalue[0] = nsub;
+  bonus->ndouble = 3*nsub;
+  memory->create(bonus->dvalue,3*nsub,"body:dvalue");
+
+  // diagonalize inertia tensor
+
+  double tensor[3][3];
+  tensor[0][0] = atof(dfile[0]);
+  tensor[1][1] = atof(dfile[1]);
+  tensor[2][2] = atof(dfile[2]);
+  tensor[0][1] = tensor[1][0] = atof(dfile[3]);
+  tensor[0][2] = tensor[2][0] = atof(dfile[4]);
+  tensor[1][2] = tensor[2][1] = atof(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 = sub-particle displacements in body frame
+
+  double delta[3],displace[3];
+
+  int j = 6;
+  int k = 0;
+  for (int i = 0; i < nsub; i++) {
+    delta[0] = atof(dfile[j]);
+    delta[1] = atof(dfile[j+1]);
+    delta[2] = atof(dfile[j+2]);
+    MathExtra::transpose_matvec(ex_space,ey_space,ez_space,
+                                delta,&bonus->dvalue[k]);
+    j += 3;
+    k += 3;
+  }
+}
+
+/* ---------------------------------------------------------------------- */
+
+int BodyNparticle::noutcol()
+{
+  return 3;
+}
+
+/* ---------------------------------------------------------------------- */
+
+int BodyNparticle::noutrow(int ibonus)
+{
+  return avec->bonus[ibonus].ivalue[0];
+}
+
+/* ---------------------------------------------------------------------- */
+
+void BodyNparticle::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];
+}
diff --git a/src/BODY/body_nparticle.h b/src/BODY/body_nparticle.h
new file mode 100644
index 000000000..3263e3456
--- /dev/null
+++ b/src/BODY/body_nparticle.h
@@ -0,0 +1,57 @@
+/* ----------------------------------------------------------------------
+   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(nparticle,BodyNparticle)
+
+#else
+
+#ifndef LMP_BODY_NPARTICLE_H
+#define LMP_BODY_NPARTICLE_H
+
+#include "body.h"
+#include "atom_vec_body.h"
+
+namespace LAMMPS_NS {
+
+class BodyNparticle : public Body {
+ public:
+  BodyNparticle(class LAMMPS *, int, char **);
+  ~BodyNparticle() {}
+  int nsub(class AtomVecBody::Bonus *);
+  double *coords(class AtomVecBody::Bonus *);
+
+  int pack_border_body(class AtomVecBody::Bonus *, double *);
+  int unpack_border_body(class AtomVecBody::Bonus *, double *);
+  void data_body(int, int, int, char **, char **);
+
+  int noutrow(int);
+  int noutcol();
+  void output(int, int, double *);
+};
+
+}
+
+#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.
+
+*/
diff --git a/src/BODY/compute_body_local.cpp b/src/BODY/compute_body_local.cpp
new file mode 100644
index 000000000..a7a4fecfa
--- /dev/null
+++ b/src/BODY/compute_body_local.cpp
@@ -0,0 +1,206 @@
+/* ----------------------------------------------------------------------
+   LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
+   http://lammps.sandia.gov, Sandia National Laboratories
+   Steve Plimpton, sjplimp@sandia.gov
+
+   Copyright (2003) Sandia Corporation.  Under the terms of Contract
+   DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
+   certain rights in this software.  This software is distributed under
+   the GNU General Public License.
+
+   See the README file in the top-level LAMMPS directory.
+------------------------------------------------------------------------- */
+
+#include "math.h"
+#include "string.h"
+#include "compute_body_local.h"
+#include "atom.h"
+#include "atom_vec_body.h"
+#include "body.h"
+#include "update.h"
+#include "domain.h"
+#include "force.h"
+#include "bond.h"
+#include "memory.h"
+#include "error.h"
+
+using namespace LAMMPS_NS;
+
+#define DELTA 10000
+
+enum{TYPE,INDEX};
+
+/* ---------------------------------------------------------------------- */
+
+ComputeBodyLocal::ComputeBodyLocal(LAMMPS *lmp, int narg, char **arg) :
+  Compute(lmp, narg, arg)
+{
+  if (narg < 4) error->all(FLERR,"Illegal compute body/local command");
+
+  local_flag = 1;
+  nvalues = narg - 3;
+  if (nvalues == 1) size_local_cols = 0;
+  else size_local_cols = nvalues;
+
+  which = new int[nvalues];
+  index = new int[nvalues];
+  nvalues = 0;
+
+  for (int iarg = 3; iarg < narg; iarg++) {
+    if (strcmp(arg[iarg],"type") == 0) which[nvalues++] = TYPE;
+    else {
+      which[nvalues] = INDEX;
+      index[nvalues] = force->inumeric(arg[iarg]) - 1;
+      nvalues++;
+    }
+  }
+
+  avec = (AtomVecBody *) atom->style_match("body");
+  if (!avec) error->all(FLERR,"Compute body/local requires atom style body");
+  bptr = avec->bptr;
+
+  int indexmax = bptr->noutcol();
+  for (int i = 0; i < nvalues; i++) {
+    if (which[i] == INDEX && (index[i] < 0 || index[i] >= indexmax)) 
+      error->all(FLERR,"Invalid index in compute body/local command");
+  }
+
+  nmax = 0;
+  vector = NULL;
+  array = NULL;
+}
+
+/* ---------------------------------------------------------------------- */
+
+ComputeBodyLocal::~ComputeBodyLocal()
+{
+  delete [] which;
+  delete [] index;
+  memory->destroy(vector);
+  memory->destroy(array);
+}
+
+/* ---------------------------------------------------------------------- */
+
+void ComputeBodyLocal::init()
+{
+  // do initial memory allocation so that memory_usage() is correct
+
+  int ncount = compute_body(0);
+  if (ncount > nmax) reallocate(ncount);
+  size_local_rows = ncount;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void ComputeBodyLocal::compute_local()
+{
+  invoked_local = update->ntimestep;
+
+  // count local entries and compute body info
+
+  int ncount = compute_body(0);
+  if (ncount > nmax) reallocate(ncount);
+  size_local_rows = ncount;
+  ncount = compute_body(1);
+}
+
+/* ----------------------------------------------------------------------
+   count body info and compute body info on this proc
+   flag = 0, only count
+   flag = 1, also compute
+------------------------------------------------------------------------- */
+
+int ComputeBodyLocal::compute_body(int flag)
+{
+  // perform count
+
+  int *mask = atom->mask;
+  int *body = atom->body;
+  int nlocal = atom->nlocal;
+
+  int ncount = 0;
+  for (int i = 0; i < nlocal; i++)
+    if (mask[i] & groupbit) {
+      if (body[i] < 0) ncount++;
+      else ncount += bptr->noutrow(body[i]);
+    }
+
+  if (flag == 0) return ncount;
+
+  // perform computation and fill output vector/array
+
+  int m,n,ibonus;
+  double *values = new double[bptr->noutcol()];
+
+  double **x = atom->x;
+  int *type = atom->type;
+
+  ncount = 0;
+  for (int i = 0; i < nlocal; i++) {
+    if (mask[i] & groupbit) {
+      if (body[i] < 0) {
+        if (nvalues == 1) {
+          if (which[0] == TYPE) vector[ncount] = type[i];
+          else vector[ncount] = x[i][index[0]];
+        } else {
+          for (m = 0; m < nvalues; m++) {
+            if (which[m] == TYPE) array[ncount][m] = type[i];
+            else array[ncount][m] = x[i][index[m]];
+          }
+        }
+        ncount++;
+
+      } else {
+        ibonus = body[i];
+        AtomVecBody::Bonus *bonus = &avec->bonus[ibonus];
+        n = bptr->noutrow(ibonus);
+        for (int j = 0; j < n; j++) {
+          bptr->output(ibonus,j,values);
+          if (nvalues == 1) {
+            if (which[0] == TYPE) vector[ncount] = type[i];
+            else vector[ncount] = values[index[0]];
+          } else {
+            for (m = 0; m < nvalues; m++) {
+              if (which[m] == TYPE) array[ncount][m] = type[i];
+              else array[ncount][m] = values[index[m]];
+            }
+          }
+          ncount++;
+        }
+      }
+    }
+  }
+
+  delete [] values;
+  return ncount;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void ComputeBodyLocal::reallocate(int n)
+{
+  // grow vector or array and indices array
+
+  while (nmax < n) nmax += DELTA;
+
+  if (nvalues == 1) {
+    memory->destroy(vector);
+    memory->create(vector,nmax,"body/local:vector");
+    vector_local = vector;
+  } else {
+    memory->destroy(array);
+    memory->create(array,nmax,nvalues,"body/local:array");
+    array_local = array;
+  }
+}
+
+/* ----------------------------------------------------------------------
+   memory usage of local data
+------------------------------------------------------------------------- */
+
+double ComputeBodyLocal::memory_usage()
+{
+  double bytes = nmax*nvalues * sizeof(double);
+  return bytes;
+}
diff --git a/src/BODY/compute_body_local.h b/src/BODY/compute_body_local.h
new file mode 100644
index 000000000..6226c589f
--- /dev/null
+++ b/src/BODY/compute_body_local.h
@@ -0,0 +1,53 @@
+/* ----------------------------------------------------------------------
+   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 COMPUTE_CLASS
+
+ComputeStyle(body/local,ComputeBodyLocal)
+
+#else
+
+#ifndef LMP_COMPUTE_BODY_LOCAL_H
+#define LMP_COMPUTE_BODY_LOCAL_H
+
+#include "compute.h"
+
+namespace LAMMPS_NS {
+
+class ComputeBodyLocal : public Compute {
+ public:
+  ComputeBodyLocal(class LAMMPS *, int, char **);
+  ~ComputeBodyLocal();
+  void init();
+  void compute_local();
+  double memory_usage();
+
+ private:
+  int nvalues;
+  int *which,*index;
+
+  int nmax;
+  double *vector;
+  double **array;
+
+  class AtomVecBody *avec;
+  class Body *bptr;
+
+  int compute_body(int);
+  void reallocate(int);
+};
+
+}
+
+#endif
+#endif
diff --git a/src/BODY/fix_nve_body.cpp b/src/BODY/fix_nve_body.cpp
new file mode 100644
index 000000000..27212ce0a
--- /dev/null
+++ b/src/BODY/fix_nve_body.cpp
@@ -0,0 +1,132 @@
+/* ----------------------------------------------------------------------
+   LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
+   http://lammps.sandia.gov, Sandia National Laboratories
+   Steve Plimpton, sjplimp@sandia.gov
+
+   Copyright (2003) Sandia Corporation.  Under the terms of Contract
+   DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
+   certain rights in this software.  This software is distributed under
+   the GNU General Public License.
+
+   See the README file in the top-level LAMMPS directory.
+------------------------------------------------------------------------- */
+
+#include "math.h"
+#include "stdio.h"
+#include "string.h"
+#include "fix_nve_body.h"
+#include "math_extra.h"
+#include "atom.h"
+#include "atom_vec_body.h"
+#include "force.h"
+#include "update.h"
+#include "memory.h"
+#include "error.h"
+
+using namespace LAMMPS_NS;
+using namespace FixConst;
+
+/* ---------------------------------------------------------------------- */
+
+FixNVEBody::FixNVEBody(LAMMPS *lmp, int narg, char **arg) :
+  FixNVE(lmp, narg, arg) {}
+
+/* ---------------------------------------------------------------------- */
+
+void FixNVEBody::init()
+{
+  avec = (AtomVecBody *) atom->style_match("body");
+  if (!avec) error->all(FLERR,"Fix nve/body requires atom style body");
+
+  // check that all particles are bodies
+  // no point particles allowed
+
+  int *body = atom->body;
+  int *mask = atom->mask;
+  int nlocal = atom->nlocal;
+
+  for (int i = 0; i < nlocal; i++)
+    if (mask[i] & groupbit)
+      if (body[i] < 0) error->one(FLERR,"Fix nve/body requires bodies");
+
+  FixNVE::init();
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixNVEBody::initial_integrate(int vflag)
+{
+  double dtfm;
+  double omega[3];
+  double *quat,*inertia;
+
+  AtomVecBody::Bonus *bonus = avec->bonus;
+  int *body = atom->body;
+  double **x = atom->x;
+  double **v = atom->v;
+  double **f = atom->f;
+  double **angmom = atom->angmom;
+  double **torque = atom->torque;
+  double *rmass = atom->rmass;
+  int *mask = atom->mask;
+  int nlocal = atom->nlocal;
+  if (igroup == atom->firstgroup) nlocal = atom->nfirst;
+
+  // set timestep here since dt may have changed or come via rRESPA
+
+  dtq = 0.5 * dtv;
+
+  for (int i = 0; i < nlocal; i++)
+    if (mask[i] & groupbit) {
+      dtfm = dtf / rmass[i];
+      v[i][0] += dtfm * f[i][0];
+      v[i][1] += dtfm * f[i][1];
+      v[i][2] += dtfm * f[i][2];
+      x[i][0] += dtv * v[i][0];
+      x[i][1] += dtv * v[i][1];
+      x[i][2] += dtv * v[i][2];
+
+      // update angular momentum by 1/2 step
+
+      angmom[i][0] += dtf * torque[i][0];
+      angmom[i][1] += dtf * torque[i][1];
+      angmom[i][2] += dtf * torque[i][2];
+
+      // compute omega at 1/2 step from angmom at 1/2 step and current q
+      // update quaternion a full step via Richardson iteration
+      // returns new normalized quaternion
+
+      inertia = bonus[body[i]].inertia;
+      quat = bonus[body[i]].quat;
+      MathExtra::mq_to_omega(angmom[i],quat,inertia,omega);
+      MathExtra::richardson(quat,angmom[i],omega,inertia,dtq);
+    }
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixNVEBody::final_integrate()
+{
+  double dtfm;
+
+  double **v = atom->v;
+  double **f = atom->f;
+  double **angmom = atom->angmom;
+  double **torque = atom->torque;
+  double *rmass = atom->rmass;
+  int *mask = atom->mask;
+  int nlocal = atom->nlocal;
+  if (igroup == atom->firstgroup) nlocal = atom->nfirst;
+
+  for (int i = 0; i < nlocal; i++)
+    if (mask[i] & groupbit) {
+      dtfm = dtf / rmass[i];
+      v[i][0] += dtfm * f[i][0];
+      v[i][1] += dtfm * f[i][1];
+      v[i][2] += dtfm * f[i][2];
+
+      angmom[i][0] += dtf * torque[i][0];
+      angmom[i][1] += dtf * torque[i][1];
+      angmom[i][2] += dtf * torque[i][2];
+    }
+}
diff --git a/src/BODY/fix_nve_body.h b/src/BODY/fix_nve_body.h
new file mode 100644
index 000000000..639e06d85
--- /dev/null
+++ b/src/BODY/fix_nve_body.h
@@ -0,0 +1,41 @@
+/* ----------------------------------------------------------------------
+   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(nve/body,FixNVEBody)
+
+#else
+
+#ifndef LMP_FIX_NVE_BODY_H
+#define LMP_FIX_NVE_BODY_H
+
+#include "fix_nve.h"
+
+namespace LAMMPS_NS {
+
+class FixNVEBody : public FixNVE {
+ public:
+  FixNVEBody(class LAMMPS *, int, char **);
+  void init();
+  void initial_integrate(int);
+  void final_integrate();
+
+ private:
+  double dtq;
+  class AtomVecBody *avec;
+};
+
+}
+#endif
+#endif
diff --git a/src/BODY/pair_body.cpp b/src/BODY/pair_body.cpp
new file mode 100644
index 000000000..5f9b4faea
--- /dev/null
+++ b/src/BODY/pair_body.cpp
@@ -0,0 +1,484 @@
+/* ----------------------------------------------------------------------
+   LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
+   http://lammps.sandia.gov, Sandia National Laboratories
+   Steve Plimpton, sjplimp@sandia.gov
+
+   Copyright (2003) Sandia Corporation.  Under the terms of Contract
+   DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
+   certain rights in this software.  This software is distributed under
+   the GNU General Public License.
+
+   See the README file in the top-level LAMMPS directory.
+------------------------------------------------------------------------- */
+
+#include "math.h"
+#include "stdio.h"
+#include "stdlib.h"
+#include "string.h"
+#include "pair_body.h"
+#include "math_extra.h"
+#include "atom.h"
+#include "atom_vec_body.h"
+#include "body_nparticle.h"
+#include "force.h"
+#include "neighbor.h"
+#include "neigh_list.h"
+#include "memory.h"
+#include "error.h"
+
+using namespace LAMMPS_NS;
+
+#define DELTA 10000
+
+/* ---------------------------------------------------------------------- */
+
+PairBody::PairBody(LAMMPS *lmp) : Pair(lmp)
+{
+  dmax = nmax = 0;
+  discrete = NULL;
+  dnum = dfirst = NULL;
+
+  single_enable = 0;
+  restartinfo = 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+PairBody::~PairBody()
+{
+  memory->destroy(discrete);
+  memory->destroy(dnum);
+  memory->destroy(dfirst);
+
+  if (allocated) {
+    memory->destroy(setflag);
+    memory->destroy(cutsq);
+
+    memory->destroy(cut);
+    memory->destroy(epsilon);
+    memory->destroy(sigma);
+    memory->destroy(lj1);
+    memory->destroy(lj2);
+    memory->destroy(lj3);
+    memory->destroy(lj4);
+  }
+}
+
+/* ---------------------------------------------------------------------- */
+
+void PairBody::compute(int eflag, int vflag)
+{
+  int i,j,ii,jj,inum,jnum,itype,jtype;
+  int ni,nj,npi,npj,ifirst,jfirst;
+  double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair;
+  double rsq,r2inv,r6inv,forcelj;
+  double xi[3],xj[3],fi[3],fj[3],ti[3],tj[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 **f = atom->f;
+  double **torque = atom->torque;
+  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 discrete list if necessary and initialize
+
+  if (nall > nmax) {
+    nmax = nall;
+    memory->destroy(dnum);
+    memory->destroy(dfirst);
+    memory->create(dnum,nall,"pair:dnum");
+    memory->create(dfirst,nall,"pair:dfirst");
+  }
+  for (i = 0; i < nall; i++) dnum[i] = 0;
+  ndiscrete = 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];
+
+    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];
+
+      if (rsq >= cutsq[itype][jtype]) continue;
+
+      // body/body interactions = NxM sub-particles
+
+      evdwl = 0.0;
+      if (body[i] >= 0 && body[j] >= 0) {
+        if (dnum[i] == 0) body2space(i);
+        npi = dnum[i];
+        ifirst = dfirst[i];
+        if (dnum[j] == 0) body2space(j);
+        npj = dnum[j];
+        jfirst = dfirst[j];
+
+        for (ni = 0; ni < npi; ni++) {
+          dxi = discrete[ifirst+ni];
+
+          for (nj = 0; nj < npj; nj++) {
+            dxj = discrete[jfirst+nj];
+
+            xi[0] = x[i][0] + dxi[0];
+            xi[1] = x[i][1] + dxi[1];
+            xi[2] = x[i][2] + dxi[2];
+            xj[0] = x[j][0] + dxj[0];
+            xj[1] = x[j][1] + dxj[1];
+            xj[2] = x[j][2] + dxj[2];
+
+            delx = xi[0] - xj[0];
+            dely = xi[1] - xj[1];
+            delz = xi[2] - xj[2];
+            rsq = delx*delx + dely*dely + delz*delz;
+
+            r2inv = 1.0/rsq;
+            r6inv = r2inv*r2inv*r2inv;
+            forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]);
+            fpair = forcelj*r2inv;
+
+            if (eflag)
+              evdwl += r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]);
+
+            fi[0] = delx*fpair;
+            fi[1] = dely*fpair;
+            fi[2] = delz*fpair;
+            f[i][0] += fi[0];
+            f[i][1] += fi[1];
+            f[i][2] += fi[2];
+            ti[0] = dxi[1]*fi[2] - dxi[2]*fi[1];
+            ti[1] = dxi[2]*fi[0] - dxi[0]*fi[2];
+            ti[2] = dxi[0]*fi[1] - dxi[1]*fi[0];
+            torque[i][0] += ti[0];
+            torque[i][1] += ti[1];
+            torque[i][2] += ti[2];
+            
+            if (newton_pair || j < nlocal) {
+              fj[0] = -delx*fpair;
+              fj[1] = -dely*fpair;
+              fj[2] = -delz*fpair;
+              f[j][0] += fj[0];
+              f[j][1] += fj[1];
+              f[j][2] += fj[2];
+              tj[0] = dxj[1]*fj[2] - dxj[2]*fj[1];
+              tj[1] = dxj[2]*fj[0] - dxj[0]*fj[2];
+              tj[2] = dxj[0]*fj[1] - dxj[1]*fj[0];
+              torque[j][0] += tj[0];
+              torque[j][1] += tj[1];
+              torque[j][2] += tj[2];
+            }
+          }
+        }
+
+      // body/particle interaction = Nx1 sub-particles
+
+      } else if (body[i] >= 0) {
+        if (dnum[i] == 0) body2space(i);
+        npi = dnum[i];
+        ifirst = dfirst[i];
+
+        for (ni = 0; ni < npi; ni++) {
+          dxi = discrete[ifirst+ni];
+
+          xi[0] = x[i][0] + dxi[0];
+          xi[1] = x[i][1] + dxi[1];
+          xi[2] = x[i][2] + dxi[2];
+          xj[0] = x[j][0];
+          xj[1] = x[j][1];
+          xj[2] = x[j][2];
+
+          delx = xi[0] - xj[0];
+          dely = xi[1] - xj[1];
+          delz = xi[2] - xj[2];
+          rsq = delx*delx + dely*dely + delz*delz;
+
+          r2inv = 1.0/rsq;
+          r6inv = r2inv*r2inv*r2inv;
+          forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]);
+          fpair = forcelj*r2inv;
+
+          if (eflag)
+            evdwl += r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]);
+
+          fi[0] = delx*fpair;
+          fi[1] = dely*fpair;
+          fi[2] = delz*fpair;
+          f[i][0] += fi[0];
+          f[i][1] += fi[1];
+          f[i][2] += fi[2];
+          ti[0] = dxi[1]*fi[2] - dxi[2]*fi[1];
+          ti[1] = dxi[2]*fi[0] - dxi[0]*fi[2];
+          ti[2] = dxi[0]*fi[1] - dxi[1]*fi[0];
+          torque[i][0] += ti[0];
+          torque[i][1] += ti[1];
+          torque[i][2] += ti[2];
+
+          if (newton_pair || j < nlocal) {
+            fj[0] = -delx*fpair;
+            fj[1] = -dely*fpair;
+            fj[2] = -delz*fpair;
+            f[j][0] += fj[0];
+            f[j][1] += fj[1];
+            f[j][2] += fj[2];
+          }
+        }
+
+
+      // particle/body interaction = Nx1 sub-particles
+
+      } else if (body[j] >= 0) {
+        if (dnum[j] == 0) body2space(j);
+        npj = dnum[j];
+        jfirst = dfirst[j];
+
+        for (nj = 0; nj < npj; nj++) {
+          dxj = discrete[jfirst+nj];
+
+          xi[0] = x[i][0];
+          xi[1] = x[i][1];
+          xi[2] = x[i][2];
+          xj[0] = x[j][0] + dxj[0];
+          xj[1] = x[j][1] + dxj[1];
+          xj[2] = x[j][2] + dxj[2];
+
+          delx = xi[0] - xj[0];
+          dely = xi[1] - xj[1];
+          delz = xi[2] - xj[2];
+          rsq = delx*delx + dely*dely + delz*delz;
+
+          r2inv = 1.0/rsq;
+          r6inv = r2inv*r2inv*r2inv;
+          forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]);
+          fpair = forcelj*r2inv;
+
+          if (eflag)
+            evdwl += r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]);
+
+          fi[0] = delx*fpair;
+          fi[1] = dely*fpair;
+          fi[2] = delz*fpair;
+          f[i][0] += fi[0];
+          f[i][1] += fi[1];
+          f[i][2] += fi[2];
+
+          if (newton_pair || j < nlocal) {
+            fj[0] = -delx*fpair;
+            fj[1] = -dely*fpair;
+            fj[2] = -delz*fpair;
+            f[j][0] += fj[0];
+            f[j][1] += fj[1];
+            f[j][2] += fj[2];
+            tj[0] = dxj[1]*fj[2] - dxj[2]*fj[1];
+            tj[1] = dxj[2]*fj[0] - dxj[0]*fj[2];
+            tj[2] = dxj[0]*fj[1] - dxj[1]*fj[0];
+            torque[j][0] += tj[0];
+            torque[j][1] += tj[1];
+            torque[j][2] += tj[2];
+          }
+        }
+
+      // particle/particle interaction = 1x1 particles
+
+      } else {
+        r2inv = 1.0/rsq;
+        r6inv = r2inv*r2inv*r2inv;
+        forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]);
+        fpair = forcelj*r2inv;
+
+        if (eflag)
+          evdwl += r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]);
+
+        f[i][0] += delx*fpair;
+        f[i][1] += dely*fpair;
+        f[i][2] += delz*fpair;
+        if (newton_pair || j < nlocal) {
+          f[j][0] -= delx*fpair;
+          f[j][1] -= dely*fpair;
+          f[j][2] -= delz*fpair;
+        }
+      }
+
+      if (evflag) ev_tally(i,j,nlocal,newton_pair,
+                           evdwl,0.0,fpair,delx,dely,delz);
+    }
+  }
+
+  if (vflag_fdotr) virial_fdotr_compute();
+}
+
+/* ----------------------------------------------------------------------
+   allocate all arrays
+------------------------------------------------------------------------- */
+
+void PairBody::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(cut,n+1,n+1,"pair:cut");
+  memory->create(epsilon,n+1,n+1,"pair:epsilon");
+  memory->create(sigma,n+1,n+1,"pair:sigma");
+  memory->create(lj1,n+1,n+1,"pair:lj1");
+  memory->create(lj2,n+1,n+1,"pair:lj2");
+  memory->create(lj3,n+1,n+1,"pair:lj3");
+  memory->create(lj4,n+1,n+1,"pair:lj4");
+}
+
+/* ----------------------------------------------------------------------
+   global settings
+------------------------------------------------------------------------- */
+
+void PairBody::settings(int narg, char **arg)
+{
+  if (narg != 1) error->all(FLERR,"Illegal pair_style command");
+
+  cut_global = force->numeric(arg[0]);
+
+  // reset cutoffs that have been explicitly set
+
+  if (allocated) {
+    int i,j;
+    for (i = 1; i <= atom->ntypes; i++)
+      for (j = i+1; j <= atom->ntypes; j++)
+        if (setflag[i][j]) cut[i][j] = cut_global;
+  }
+}
+
+/* ----------------------------------------------------------------------
+   set coeffs for one or more type pairs
+------------------------------------------------------------------------- */
+
+void PairBody::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(arg[0],atom->ntypes,ilo,ihi);
+  force->bounds(arg[1],atom->ntypes,jlo,jhi);
+
+  double epsilon_one = force->numeric(arg[2]);
+  double sigma_one = force->numeric(arg[3]);
+
+  double cut_one = cut_global;
+  if (narg == 5) cut_one = force->numeric(arg[4]);
+
+  int count = 0;
+  for (int i = ilo; i <= ihi; i++) {
+    for (int j = MAX(jlo,i); j <= jhi; j++) {
+      epsilon[i][j] = epsilon_one;
+      sigma[i][j] = sigma_one;
+      cut[i][j] = cut_one;
+      setflag[i][j] = 1;
+      count++;
+    }
+  }
+
+  if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
+}
+
+/* ----------------------------------------------------------------------
+   init specific to this pair style
+------------------------------------------------------------------------- */
+
+void PairBody::init_style()
+{
+  avec = (AtomVecBody *) atom->style_match("body");
+  if (!avec) error->all(FLERR,"Pair body requires atom style body");
+  if (strcmp(avec->bptr->style,"nparticle") != 0)
+    error->all(FLERR,"Pair body requires body style nparticle");
+  bptr = (BodyNparticle *) avec->bptr;
+
+  neighbor->request(this);
+}
+
+/* ----------------------------------------------------------------------
+   init for one type pair i,j and corresponding j,i
+------------------------------------------------------------------------- */
+
+double PairBody::init_one(int i, int j)
+{
+  if (setflag[i][j] == 0) {
+    epsilon[i][j] = mix_energy(epsilon[i][i],epsilon[j][j],
+                               sigma[i][i],sigma[j][j]);
+    sigma[i][j] = mix_distance(sigma[i][i],sigma[j][j]);
+    cut[i][j] = mix_distance(cut[i][i],cut[j][j]);
+  }
+
+  lj1[i][j] = 48.0 * epsilon[i][j] * pow(sigma[i][j],12.0);
+  lj2[i][j] = 24.0 * epsilon[i][j] * pow(sigma[i][j],6.0);
+  lj3[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],12.0);
+  lj4[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],6.0);
+
+  epsilon[j][i] = epsilon[i][j];
+  sigma[j][i] = sigma[i][j];
+  lj1[j][i] = lj1[i][j];
+  lj2[j][i] = lj2[i][j];
+  lj3[j][i] = lj3[i][j];
+  lj4[j][i] = lj4[i][j];
+
+  return cut[i][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 PairBody::body2space(int i)
+{
+  int ibonus = atom->body[i];
+  AtomVecBody::Bonus *bonus = &avec->bonus[ibonus];
+  int nsub = bptr->nsub(bonus);
+  double *coords = bptr->coords(bonus);
+  
+  dnum[i] = nsub;
+  dfirst[i] = ndiscrete;
+
+  if (ndiscrete + nsub > dmax) {
+    dmax += DELTA;
+    memory->grow(discrete,dmax,3,"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]);
+    ndiscrete++;
+  }
+}
diff --git a/src/BODY/pair_body.h b/src/BODY/pair_body.h
new file mode 100644
index 000000000..a1cc2cddf
--- /dev/null
+++ b/src/BODY/pair_body.h
@@ -0,0 +1,60 @@
+/* ----------------------------------------------------------------------
+   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,PairBody)
+
+#else
+
+#ifndef LMP_PAIR_BODY_H
+#define LMP_PAIR_BODY_H
+
+#include "pair.h"
+
+namespace LAMMPS_NS {
+
+class PairBody : public Pair {
+ public:
+  PairBody(class LAMMPS *);
+  ~PairBody();
+  void compute(int, int);
+  void settings(int, char **);
+  void coeff(int, char **);
+  void init_style();
+  double init_one(int, int);
+
+ protected:
+  double cut_global;
+  double **cut;
+  double **epsilon,**sigma;
+  double **lj1,**lj2,**lj3,**lj4;
+
+  class AtomVecBody *avec;
+  class BodyNparticle *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
+
+  void allocate();
+  void body2space(int);
+};
+
+}
+
+#endif
+#endif