From bfd6a79fe67f747f00bf81577ef261691fb36d41 Mon Sep 17 00:00:00 2001
From: sjplimp <sjplimp@f3b2605a-c512-4ea7-a41b-209d697bcdaa>
Date: Tue, 26 Oct 2010 16:14:31 +0000
Subject: [PATCH] git-svn-id: svn://svn.icms.temple.edu/lammps-ro/trunk@5143
 f3b2605a-c512-4ea7-a41b-209d697bcdaa

---
 src/USER-REAXC/Install.sh               |  115 ++
 src/USER-REAXC/README                   |   61 +
 src/USER-REAXC/fix_qeq_reax.cpp         |  851 +++++++++++
 src/USER-REAXC/fix_qeq_reax.h           |  134 ++
 src/USER-REAXC/fix_reax_c.cpp           |  156 +++
 src/USER-REAXC/fix_reax_c.h             |   53 +
 src/USER-REAXC/pair_reax_c.cpp          |  664 +++++++++
 src/USER-REAXC/pair_reax_c.h            |   66 +
 src/USER-REAXC/reaxc_allocate.cpp       | 1011 +++++++++++++
 src/USER-REAXC/reaxc_allocate.h         |   49 +
 src/USER-REAXC/reaxc_basic_comm.cpp     |  312 +++++
 src/USER-REAXC/reaxc_basic_comm.h       |   47 +
 src/USER-REAXC/reaxc_bond_orders.cpp    | 1219 ++++++++++++++++
 src/USER-REAXC/reaxc_bond_orders.h      |   58 +
 src/USER-REAXC/reaxc_bonds.cpp          |  148 ++
 src/USER-REAXC/reaxc_bonds.h            |   29 +
 src/USER-REAXC/reaxc_control.cpp        |  395 ++++++
 src/USER-REAXC/reaxc_control.h          |   29 +
 src/USER-REAXC/reaxc_defs.h             |  141 ++
 src/USER-REAXC/reaxc_ffield.cpp         |  715 ++++++++++
 src/USER-REAXC/reaxc_ffield.h           |   29 +
 src/USER-REAXC/reaxc_forces.cpp         |  929 ++++++++++++
 src/USER-REAXC/reaxc_forces.h           |   35 +
 src/USER-REAXC/reaxc_hydrogen_bonds.cpp |  220 +++
 src/USER-REAXC/reaxc_hydrogen_bonds.h   |   30 +
 src/USER-REAXC/reaxc_init_md.cpp        |  916 ++++++++++++
 src/USER-REAXC/reaxc_init_md.h          |   35 +
 src/USER-REAXC/reaxc_io_tools.cpp       | 1712 +++++++++++++++++++++++
 src/USER-REAXC/reaxc_io_tools.h         |  107 ++
 src/USER-REAXC/reaxc_list.cpp           |  157 +++
 src/USER-REAXC/reaxc_list.h             |   63 +
 src/USER-REAXC/reaxc_lookup.cpp         |  339 +++++
 src/USER-REAXC/reaxc_lookup.h           |   32 +
 src/USER-REAXC/reaxc_multi_body.cpp     |  311 ++++
 src/USER-REAXC/reaxc_multi_body.h       |   31 +
 src/USER-REAXC/reaxc_nonbonded.cpp      |  424 ++++++
 src/USER-REAXC/reaxc_nonbonded.h        |   37 +
 src/USER-REAXC/reaxc_reset_tools.cpp    |  254 ++++
 src/USER-REAXC/reaxc_reset_tools.h      |   40 +
 src/USER-REAXC/reaxc_system_props.cpp   |  411 ++++++
 src/USER-REAXC/reaxc_system_props.h     |   41 +
 src/USER-REAXC/reaxc_tool_box.cpp       |  467 +++++++
 src/USER-REAXC/reaxc_tool_box.h         |   69 +
 src/USER-REAXC/reaxc_torsion_angles.cpp |  590 ++++++++
 src/USER-REAXC/reaxc_torsion_angles.h   |   30 +
 src/USER-REAXC/reaxc_traj.cpp           | 1072 ++++++++++++++
 src/USER-REAXC/reaxc_traj.h             |   77 +
 src/USER-REAXC/reaxc_types.h            |  977 +++++++++++++
 src/USER-REAXC/reaxc_valence_angles.cpp |  535 +++++++
 src/USER-REAXC/reaxc_valence_angles.h   |   34 +
 src/USER-REAXC/reaxc_vector.cpp         |  518 +++++++
 src/USER-REAXC/reaxc_vector.h           |   89 ++
 52 files changed, 16864 insertions(+)
 create mode 100755 src/USER-REAXC/Install.sh
 create mode 100644 src/USER-REAXC/README
 create mode 100644 src/USER-REAXC/fix_qeq_reax.cpp
 create mode 100644 src/USER-REAXC/fix_qeq_reax.h
 create mode 100644 src/USER-REAXC/fix_reax_c.cpp
 create mode 100644 src/USER-REAXC/fix_reax_c.h
 create mode 100644 src/USER-REAXC/pair_reax_c.cpp
 create mode 100644 src/USER-REAXC/pair_reax_c.h
 create mode 100644 src/USER-REAXC/reaxc_allocate.cpp
 create mode 100644 src/USER-REAXC/reaxc_allocate.h
 create mode 100644 src/USER-REAXC/reaxc_basic_comm.cpp
 create mode 100644 src/USER-REAXC/reaxc_basic_comm.h
 create mode 100644 src/USER-REAXC/reaxc_bond_orders.cpp
 create mode 100644 src/USER-REAXC/reaxc_bond_orders.h
 create mode 100644 src/USER-REAXC/reaxc_bonds.cpp
 create mode 100644 src/USER-REAXC/reaxc_bonds.h
 create mode 100644 src/USER-REAXC/reaxc_control.cpp
 create mode 100644 src/USER-REAXC/reaxc_control.h
 create mode 100644 src/USER-REAXC/reaxc_defs.h
 create mode 100644 src/USER-REAXC/reaxc_ffield.cpp
 create mode 100644 src/USER-REAXC/reaxc_ffield.h
 create mode 100644 src/USER-REAXC/reaxc_forces.cpp
 create mode 100644 src/USER-REAXC/reaxc_forces.h
 create mode 100644 src/USER-REAXC/reaxc_hydrogen_bonds.cpp
 create mode 100644 src/USER-REAXC/reaxc_hydrogen_bonds.h
 create mode 100644 src/USER-REAXC/reaxc_init_md.cpp
 create mode 100644 src/USER-REAXC/reaxc_init_md.h
 create mode 100644 src/USER-REAXC/reaxc_io_tools.cpp
 create mode 100644 src/USER-REAXC/reaxc_io_tools.h
 create mode 100644 src/USER-REAXC/reaxc_list.cpp
 create mode 100644 src/USER-REAXC/reaxc_list.h
 create mode 100644 src/USER-REAXC/reaxc_lookup.cpp
 create mode 100644 src/USER-REAXC/reaxc_lookup.h
 create mode 100644 src/USER-REAXC/reaxc_multi_body.cpp
 create mode 100644 src/USER-REAXC/reaxc_multi_body.h
 create mode 100644 src/USER-REAXC/reaxc_nonbonded.cpp
 create mode 100644 src/USER-REAXC/reaxc_nonbonded.h
 create mode 100644 src/USER-REAXC/reaxc_reset_tools.cpp
 create mode 100644 src/USER-REAXC/reaxc_reset_tools.h
 create mode 100644 src/USER-REAXC/reaxc_system_props.cpp
 create mode 100644 src/USER-REAXC/reaxc_system_props.h
 create mode 100644 src/USER-REAXC/reaxc_tool_box.cpp
 create mode 100644 src/USER-REAXC/reaxc_tool_box.h
 create mode 100644 src/USER-REAXC/reaxc_torsion_angles.cpp
 create mode 100644 src/USER-REAXC/reaxc_torsion_angles.h
 create mode 100644 src/USER-REAXC/reaxc_traj.cpp
 create mode 100644 src/USER-REAXC/reaxc_traj.h
 create mode 100644 src/USER-REAXC/reaxc_types.h
 create mode 100644 src/USER-REAXC/reaxc_valence_angles.cpp
 create mode 100644 src/USER-REAXC/reaxc_valence_angles.h
 create mode 100644 src/USER-REAXC/reaxc_vector.cpp
 create mode 100644 src/USER-REAXC/reaxc_vector.h

diff --git a/src/USER-REAXC/Install.sh b/src/USER-REAXC/Install.sh
new file mode 100755
index 0000000000..a19874fb51
--- /dev/null
+++ b/src/USER-REAXC/Install.sh
@@ -0,0 +1,115 @@
+# Install/unInstall package classes in LAMMPS
+
+if (test $1 = 1) then
+
+    cp -p pair_reax_c.cpp ..
+    cp -p fix_qeq_reax.cpp ..
+    cp -p fix_reax_c.cpp ..
+
+    cp -p pair_reax_c.h ..
+    cp -p fix_qeq_reax.h ..
+    cp -p fix_reax_c.h ..
+
+    cp -p reaxc_allocate.cpp ..
+    cp -p reaxc_basic_comm.cpp ..
+    cp -p reaxc_bond_orders.cpp ..
+    cp -p reaxc_bonds.cpp ..
+    cp -p reaxc_control.cpp ..
+    cp -p reaxc_ffield.cpp ..
+    cp -p reaxc_forces.cpp ..
+    cp -p reaxc_hydrogen_bonds.cpp ..
+    cp -p reaxc_init_md.cpp ..
+    cp -p reaxc_io_tools.cpp ..
+    cp -p reaxc_list.cpp ..
+    cp -p reaxc_lookup.cpp ..
+    cp -p reaxc_multi_body.cpp ..
+    cp -p reaxc_nonbonded.cpp ..
+    cp -p reaxc_reset_tools.cpp ..
+    cp -p reaxc_system_props.cpp ..
+    cp -p reaxc_tool_box.cpp ..
+    cp -p reaxc_torsion_angles.cpp ..
+    cp -p reaxc_traj.cpp ..
+    cp -p reaxc_valence_angles.cpp ..
+    cp -p reaxc_vector.cpp ..
+
+    cp -p reaxc_allocate.h ..
+    cp -p reaxc_basic_comm.h ..
+    cp -p reaxc_bond_orders.h ..
+    cp -p reaxc_bonds.h ..
+    cp -p reaxc_control.h ..
+    cp -p reaxc_defs.h ..
+    cp -p reaxc_ffield.h ..
+    cp -p reaxc_forces.h ..
+    cp -p reaxc_hydrogen_bonds.h ..
+    cp -p reaxc_init_md.h ..
+    cp -p reaxc_io_tools.h ..
+    cp -p reaxc_list.h ..
+    cp -p reaxc_lookup.h ..
+    cp -p reaxc_multi_body.h ..
+    cp -p reaxc_nonbonded.h ..
+    cp -p reaxc_reset_tools.h ..
+    cp -p reaxc_system_props.h ..
+    cp -p reaxc_tool_box.h ..
+    cp -p reaxc_torsion_angles.h ..
+    cp -p reaxc_traj.h ..
+    cp -p reaxc_types.h ..
+    cp -p reaxc_valence_angles.h ..
+    cp -p reaxc_vector.h ..
+
+elif (test $1 = 0) then
+
+    rm ../pair_reax_c.cpp
+    rm ../fix_qeq_reax.cpp
+    rm ../fix_reax_c.cpp
+
+    rm ../pair_reax_c.h
+    rm ../fix_qeq_reax.h
+    rm ../fix_reax_c.h
+
+    rm ../reaxc_allocate.cpp
+    rm ../reaxc_basic_comm.cpp
+    rm ../reaxc_bond_orders.cpp
+    rm ../reaxc_bonds.cpp
+    rm ../reaxc_control.cpp
+    rm ../reaxc_ffield.cpp
+    rm ../reaxc_forces.cpp
+    rm ../reaxc_hydrogen_bonds.cpp
+    rm ../reaxc_init_md.cpp
+    rm ../reaxc_io_tools.cpp
+    rm ../reaxc_list.cpp
+    rm ../reaxc_lookup.cpp
+    rm ../reaxc_multi_body.cpp
+    rm ../reaxc_nonbonded.cpp
+    rm ../reaxc_reset_tools.cpp
+    rm ../reaxc_system_props.cpp
+    rm ../reaxc_tool_box.cpp
+    rm ../reaxc_torsion_angles.cpp
+    rm ../reaxc_traj.cpp
+    rm ../reaxc_valence_angles.cpp
+    rm ../reaxc_vector.cpp
+
+    rm ../reaxc_allocate.h
+    rm ../reaxc_basic_comm.h
+    rm ../reaxc_bond_orders.h
+    rm ../reaxc_bonds.h
+    rm ../reaxc_control.h
+    rm ../reaxc_defs.h
+    rm ../reaxc_ffield.h
+    rm ../reaxc_forces.h
+    rm ../reaxc_hydrogen_bonds.h
+    rm ../reaxc_init_md.h
+    rm ../reaxc_io_tools.h
+    rm ../reaxc_list.h
+    rm ../reaxc_lookup.h
+    rm ../reaxc_multi_body.h
+    rm ../reaxc_nonbonded.h
+    rm ../reaxc_reset_tools.h
+    rm ../reaxc_system_props.h
+    rm ../reaxc_tool_box.h
+    rm ../reaxc_torsion_angles.h
+    rm ../reaxc_traj.h
+    rm ../reaxc_types.h
+    rm ../reaxc_valence_angles.h
+    rm ../reaxc_vector.h
+
+fi
diff --git a/src/USER-REAXC/README b/src/USER-REAXC/README
new file mode 100644
index 0000000000..7830147200
--- /dev/null
+++ b/src/USER-REAXC/README
@@ -0,0 +1,61 @@
+The files in this directory are a user-contributed package for LAMMPS.
+
+The person who created this package is Hasan Metin Aktulga, haktulga
+at cs.purdue.edu, while at Purdue University.  Contact him directly,
+or Aidan Thompson (Sandia) at athomps at sandia.gov, if you have
+questions.
+
+--------------------------------------
+
+Note that the files with names starting with "reaxc" in this package
+are from PuReMD, the Purdue ReaxFF Molecular Dynamics Program.  Its
+copyright info and authorship info are listed below.
+  
+PACKAGE DESCRIPTION:
+
+Contains a implementation for LAMMPS of the ReaxFF force field.
+ReaxFF uses distance-dependent bond-order functions to represent the
+contributions of chemical bonding to the potential energy.  It was
+originally developed by Adri van Duin and the Goddard group at
+CalTech.
+
+The USER-REAXC version of ReaxFF (pair_style reax/c), implemented in
+C++, should give identical or very similar results to pair_style reax,
+which is a ReaxFF implementation on top of a Fortran library, a
+version of which was originally authored by Adri van Duin.
+
+The reax/c version should be somewhat faster and more scalable,
+particularly with respect to the charge equilibration calculation.  It
+should also be easier to build and use since there are no complicating
+issues due to linking to a Fortran library.
+
+OTHERS FILES INCLUDED:
+
+User examples for pair_style reax/c are in examples/reax.
+
+Thanks to Steve Plimpton and Aidan Thompson for their input on the
+LAMMPS architecture and for their help in understanding and
+customizing some of the required LAMMPS interfaces.
+
+--------------------------------------
+
+The reaxc files in this directory have the following header:
+
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
diff --git a/src/USER-REAXC/fix_qeq_reax.cpp b/src/USER-REAXC/fix_qeq_reax.cpp
new file mode 100644
index 0000000000..640f102459
--- /dev/null
+++ b/src/USER-REAXC/fix_qeq_reax.cpp
@@ -0,0 +1,851 @@
+/* ----------------------------------------------------------------------
+   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: Hasan Metin Aktulga, Purdue University
+------------------------------------------------------------------------- */
+
+#include "math.h"
+#include "stdio.h"
+#include "stdlib.h"
+#include "string.h"
+#include "fix_qeq_reax.h"
+#include "atom.h"
+#include "comm.h"
+#include "domain.h"
+#include "neighbor.h"
+#include "neigh_list.h"
+#include "neigh_request.h"
+#include "update.h"
+#include "force.h"
+#include "pair.h"
+#include "respa.h"
+#include "memory.h"
+#include "error.h"
+
+using namespace LAMMPS_NS;
+
+#define EV_TO_KCAL_PER_MOL 14.4
+#define SAFE_ZONE       1.2
+#define DANGER_ZONE     0.95
+#define LOOSE_ZONE      0.7
+#define SQR(x) ((x)*(x))
+#define CUBE(x) ((x)*(x)*(x))
+#define MIN_CAP 50
+#define MIN_NBRS 100
+
+#define MIN(A,B) ((A) < (B)) ? (A) : (B)
+#define MAX(A,B) ((A) > (B)) ? (A) : (B)
+
+/* ---------------------------------------------------------------------- */
+
+FixQEqReax::FixQEqReax(LAMMPS *lmp, int narg, char **arg) : 
+  Fix(lmp, narg, arg)
+{
+  if (narg != 8) error->all("Illegal fix qeq/reax command"); 
+  
+  nevery = atoi(arg[3]);
+  swa = atof(arg[4]);
+  swb = atof(arg[5]);
+  tolerance = atof(arg[6]);
+  pertype_parameters(arg[7]);
+
+  shld = NULL;
+
+  n = n_cap = 0;
+  N = nmax = 0;
+  m_fill = m_cap = 0;
+  pack_flag = 0;
+  s = NULL;
+  t = NULL;
+  nprev = 5;
+  
+  Hdia_inv = NULL;
+  b_s = NULL;
+  b_t = NULL;
+  b_prc = NULL;
+  b_prm = NULL;
+
+  // CG
+  p = NULL;
+  q = NULL;
+  r = NULL;
+  d = NULL;
+
+  // GMRES
+  //g = NULL;
+  //y = NULL;
+  //hstr = NULL;
+  //v = NULL;
+  //h = NULL;
+  //hc = NULL;
+  //hs = NULL;
+
+  // perform initial allocation of atom-based arrays
+  // register with Atom class
+
+  s_hist = t_hist = NULL;
+  grow_arrays(atom->nmax);
+  atom->add_callback(0);
+  for( int i = 0; i < atom->nmax; i++ )
+    for (int j = 0; j < nprev; ++j )
+      s_hist[i][j] = t_hist[i][j] = 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+FixQEqReax::~FixQEqReax()
+{
+  // unregister callbacks to this fix from Atom class
+ 
+  atom->delete_callback(id,0);
+
+  memory->destroy_2d_double_array(s_hist);
+  memory->destroy_2d_double_array(t_hist);
+
+  deallocate_storage();
+  deallocate_matrix();
+
+  memory->destroy_2d_double_array(shld);
+
+  if (!reaxflag) {
+    memory->sfree(chi);
+    memory->sfree(eta);
+    memory->sfree(gamma);
+  }
+}
+
+/* ---------------------------------------------------------------------- */
+
+int FixQEqReax::setmask()
+{
+  int mask = 0;
+  mask |= PRE_FORCE;
+  mask |= MIN_PRE_FORCE;
+  return mask;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixQEqReax::pertype_parameters(char *arg)
+{
+  if (strcmp(arg,"reax/c") == 0) {
+    reaxflag = 1;
+    Pair *pair = force->pair_match("reax/c",1);
+    if (pair == NULL) error->all("No pair reax/c for fix qeq/reax");
+    int tmp;
+    chi = (double *) pair->extract("chi",tmp);
+    eta = (double *) pair->extract("eta",tmp);
+    gamma = (double *) pair->extract("gamma",tmp);
+    if (chi == NULL || eta == NULL || gamma == NULL)
+      error->all("Fix qeq/reax could not extract params from pair reax/c");
+    return;
+  }
+
+  int i,itype,ntypes;
+  double v1,v2,v3;
+  FILE *pf;
+
+  reaxflag = 0;
+  ntypes = atom->ntypes;
+
+  chi = (double*) memory->smalloc(sizeof(double)*(ntypes+1),"qeq/reax:chi");
+  eta = (double*) memory->smalloc(sizeof(double)*(ntypes+1),"qeq/reax:eta");
+  gamma = (double*) memory->smalloc(sizeof(double)*(ntypes+1),
+				    "qeq/reax:gamma");
+
+  if (comm->me == 0) {
+    if ((pf = fopen(arg,"r")) == NULL)
+      error->one("Fix qeq/reax parameter file could not be found");
+    
+    for (i = 1; i <= ntypes && !feof(pf); i++) {
+      fscanf(pf,"%d %lg %lg %lg",&itype,&v1,&v2,&v3);
+      if (itype < 1 || itype > ntypes)
+	error->one("Fix qeq/reax invalid atom type in param file");
+      chi[itype] = v1;
+      eta[itype] = v2;
+      gamma[itype] = v3;
+    }
+    if (i <= ntypes) error->one("Invalid param file for fix qeq/reax");
+    fclose(pf);
+  }
+
+  MPI_Bcast(&chi[1],ntypes,MPI_DOUBLE,0,world);
+  MPI_Bcast(&eta[1],ntypes,MPI_DOUBLE,0,world);
+  MPI_Bcast(&gamma[1],ntypes,MPI_DOUBLE,0,world);
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixQEqReax::allocate_storage()
+{
+  nmax = atom->nmax;
+
+  s = (double*) memory->smalloc( nmax * sizeof(double), "qeq:s" );
+  t = (double*) memory->smalloc( nmax * sizeof(double), "qeq:t" );
+
+  Hdia_inv = (double*) memory->smalloc(nmax * sizeof(double), "qeq:Hdia_inv");
+  b_s = (double*) memory->smalloc( nmax * sizeof(double), "qeq:b_s" );
+  b_t = (double*) memory->smalloc( nmax * sizeof(double), "qeq:b_t" );
+  b_prc = (double*) memory->smalloc( nmax * sizeof(double), "qeq:b_prc" );
+  b_prm = (double*) memory->smalloc( nmax * sizeof(double), "qeq:b_prm" );
+
+  // CG
+  p = (double*) memory->smalloc( nmax * sizeof(double), "qeq:p" );
+  q = (double*) memory->smalloc( nmax * sizeof(double), "qeq:q" );
+  r = (double*) memory->smalloc( nmax * sizeof(double), "qeq:r" );
+  d = (double*) memory->smalloc( nmax * sizeof(double), "qeq:d" );
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixQEqReax::deallocate_storage()
+{
+  memory->sfree(s);
+  memory->sfree(t);
+
+  memory->sfree( Hdia_inv );
+  memory->sfree( b_s );
+  memory->sfree( b_t );
+  memory->sfree( b_prc );
+  memory->sfree( b_prm );
+
+  memory->sfree( p );
+  memory->sfree( q );
+  memory->sfree( r );
+  memory->sfree( d );
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixQEqReax::reallocate_storage()
+{
+  deallocate_storage();
+  allocate_storage();
+  init_storage();
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixQEqReax::allocate_matrix()
+{
+  int i,ii;
+
+  n = atom->nlocal;
+  n_cap = MAX( (int)(n * SAFE_ZONE), MIN_CAP );
+
+  // determine the total space for the H matrix
+
+  int m = 0;
+  for( ii = 0; ii < list->inum; ii++ ) {
+    i = list->ilist[ii];
+    m += list->numneigh[i];
+  }
+  m_cap = MAX( (int)(m * SAFE_ZONE), MIN_CAP * MIN_NBRS );
+  
+  H.n = n_cap;
+  H.m = m_cap;
+  H.firstnbr = (int*) memory->smalloc( n_cap * sizeof(int), "qeq:H.firstnbr" );
+  H.numnbrs = (int*) memory->smalloc( n_cap * sizeof(int), "qeq:H.numnbrs" );
+  H.jlist = (int*)  memory->smalloc( m_cap * sizeof(int), "qeq:H.jlist" );
+  H.val = (double*) memory->smalloc( m_cap * sizeof(double), "qeq:H.val" );
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixQEqReax::deallocate_matrix()
+{
+  memory->sfree( H.firstnbr );
+  memory->sfree( H.numnbrs );
+  memory->sfree( H.jlist );
+  memory->sfree( H.val ); 
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixQEqReax::reallocate_matrix()
+{
+  deallocate_matrix();
+  allocate_matrix();
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixQEqReax::init()
+{
+  if (!atom->q_flag) error->all("Fix qeq/reax requires atom attribute q");
+	
+  // need a half neighbor list w/ Newton off
+  // built whenever re-neighboring occurs
+
+  int irequest = neighbor->request(this);
+  neighbor->requests[irequest]->pair = 0;
+  neighbor->requests[irequest]->fix = 1;
+  neighbor->requests[irequest]->newton = 2;
+
+  init_shielding();
+  init_taper();
+
+  if (strcmp(update->integrate_style,"respa") == 0)
+    nlevels_respa = ((Respa *) update->integrate)->nlevels;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixQEqReax::init_list(int id, NeighList *ptr)
+{
+  list = ptr;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixQEqReax::init_shielding()
+{
+  int i,j;
+  int ntypes;
+
+  ntypes = atom->ntypes;
+  shld = memory->create_2d_double_array(ntypes+1, ntypes+1, "qeq:shileding");
+  
+  for( i = 1; i <= ntypes; ++i )
+    for( j = 1; j <= ntypes; ++j )
+      shld[i][j] = pow( gamma[i] * gamma[j], -1.5 );
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixQEqReax::init_taper()
+{
+  double d7, swa2, swa3, swb2, swb3;
+
+  if (fabs(swa) > 0.01 && comm->me == 0)
+    error->warning("Fix qeq/reax has non-zero lower Taper radius cutoff");
+  if (swb < 0)
+    error->all( "Fix qeq/reax has negative upper Taper radius cutoff");
+  else if (swb < 5 && comm->me == 0)
+    error->warning("Fix qeq/reax has very low Taper radius cutoff");
+
+  d7 = pow( swb - swa, 7 );
+  swa2 = SQR( swa );
+  swa3 = CUBE( swa );
+  swb2 = SQR( swb );
+  swb3 = CUBE( swb );
+
+  Tap[7] =  20.0 / d7;
+  Tap[6] = -70.0 * (swa + swb) / d7;
+  Tap[5] =  84.0 * (swa2 + 3.0*swa*swb + swb2) / d7;
+  Tap[4] = -35.0 * (swa3 + 9.0*swa2*swb + 9.0*swa*swb2 + swb3 ) / d7;
+  Tap[3] = 140.0 * (swa3*swb + 3.0*swa2*swb2 + swa*swb3 ) / d7;
+  Tap[2] =-210.0 * (swa3*swb2 + swa2*swb3) / d7;
+  Tap[1] = 140.0 * swa3 * swb3 / d7;
+  Tap[0] = (-35.0*swa3*swb2*swb2 + 21.0*swa2*swb3*swb2 +
+	    7.0*swa*swb3*swb3 + swb3*swb3*swb ) / d7;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixQEqReax::setup_pre_force(int vflag)
+{
+  neighbor->build_one(list->index);
+  allocate_storage();
+  init_storage();
+  allocate_matrix();
+
+  pre_force(vflag);
+}  
+
+/* ---------------------------------------------------------------------- */
+
+void FixQEqReax::setup_pre_force_respa(int vflag, int ilevel)
+{
+  if (ilevel < nlevels_respa-1) return;
+  setup_pre_force(vflag);
+}  
+
+/* ---------------------------------------------------------------------- */
+
+void FixQEqReax::min_setup_pre_force(int vflag)
+{
+  setup_pre_force(vflag);
+}  
+
+/* ---------------------------------------------------------------------- */
+
+void FixQEqReax::init_storage()
+{
+  N = atom->nlocal + atom->nghost;
+  for( int i = 0; i < N; i++ ) {
+    Hdia_inv[i] = 1. / eta[atom->type[i]]; 
+    b_s[i] = -chi[atom->type[i]];
+    b_t[i] = -1.0;
+    b_prc[i] = 0;
+    b_prm[i] = 0;
+    s[i] = t[i] = 0;
+  }
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixQEqReax::pre_force(int vflag)
+{
+  double t_start, t_end;
+
+  if (update->ntimestep % nevery) return;
+  if( comm->me == 0 ) t_start = MPI_Wtime();
+
+  n = atom->nlocal;
+  N = atom->nlocal + atom->nghost;
+  // grow arrays if necessary
+  // need to be atom->nmax in length
+  if( atom->nmax > nmax ) reallocate_storage();
+  if( n > n_cap*DANGER_ZONE || m_fill > m_cap*DANGER_ZONE )
+    reallocate_matrix();
+  
+  init_matvec();
+  matvecs = CG(b_s, s);	// CG on s - parallel
+  matvecs += CG(b_t, t); // CG on t - parallel
+  calculate_Q();
+
+  if( comm->me == 0 ) {
+    t_end = MPI_Wtime();
+    qeq_time = t_end - t_start;
+  }
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixQEqReax::pre_force_respa(int vflag, int ilevel, int iloop)
+{
+  if (ilevel == nlevels_respa-1) pre_force(vflag);
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixQEqReax::min_pre_force(int vflag)
+{
+  pre_force(vflag);
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixQEqReax::init_matvec()
+{
+  /* fill-in H matrix */
+  compute_H();
+
+  for( int i = 0; i < n; ++i ) {
+    /* init pre-conditioner for H and init solution vectors */
+    Hdia_inv[i] = 1. / eta[ atom->type[i] ];
+    b_s[i]      = -chi[ atom->type[i] ];
+    b_t[i]      = -1.0;
+
+    /* linear extrapolation for s & t from previous solutions */
+    //s[i] = 2 * s_hist[i][0] - s_hist[i][1];
+    //t[i] = 2 * t_hist[i][0] - t_hist[i][1];
+
+    /* quadratic extrapolation for s & t from previous solutions */
+    //s[i] = s_hist[i][2] + 3 * ( s_hist[i][0] - s_hist[i][1] );        
+    t[i] = t_hist[i][2] + 3 * ( t_hist[i][0] - t_hist[i][1] );
+
+    /* cubic extrapolation for s & t from previous solutions */
+    s[i] = 4*(s_hist[i][0]+s_hist[i][2])-(6*s_hist[i][1]+s_hist[i][3]);
+    //t[i] = 4*(t_hist[i][0]+t_hist[i][2])-(6*t_hist[i][1]+t_hist[i][3]);
+  }
+
+  pack_flag = 2;
+  comm->forward_comm_fix(this); //Dist_vector( s );
+  pack_flag = 3;
+  comm->forward_comm_fix(this); //Dist_vector( t );
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixQEqReax::compute_H()
+{
+  int inum, jnum, *ilist, *jlist, *numneigh, **firstneigh;
+  int i, j, ii, jj, temp, newnbr;
+  int *type;
+  double **x;
+  double dx, dy, dz, r_sqr;
+
+  type = atom->type;
+  x = atom->x;
+
+  inum = list->inum;
+  ilist = list->ilist;
+  numneigh = list->numneigh;
+  firstneigh = list->firstneigh;
+
+  // fill in the H matrix
+  m_fill = 0;
+  r_sqr = 0;
+  for( ii = 0; ii < inum; ii++ ) {
+    i = ilist[ii];
+    jlist = firstneigh[i];
+    jnum = numneigh[i];
+    H.firstnbr[i] = m_fill;
+
+    for( jj = 0; jj < jnum; jj++ ) {
+      j = jlist[jj];
+
+      dx = x[i][0] - x[j][0];
+      dy = x[i][1] - x[j][1];
+      dz = x[i][2] - x[j][2];
+      r_sqr = SQR(dx) + SQR(dy) + SQR(dz);
+      
+      if( r_sqr <= SQR(swb) && (j < n || atom->tag[i] <= atom->tag[j]) ) {
+	H.jlist[m_fill] = j;
+	H.val[m_fill] = calculate_H( sqrt(r_sqr), shld[type[i]][type[j]] );
+	m_fill++;
+      }
+    }
+    
+    H.numnbrs[i] = m_fill - H.firstnbr[i];
+  }
+
+  if (m_fill >= H.m) {
+    char str[128];
+    sprintf(str,"H matrix size has been exceeded: m_fill=%d H.m=%d\n",
+	     m_fill, H.m );
+    error->warning(str);
+    error->all("Fix qeq/reax has insufficient QEq matrix size");
+  }
+}
+
+/* ---------------------------------------------------------------------- */
+
+double FixQEqReax::calculate_H( double r, double gamma )
+{
+  double Taper, denom;
+
+  Taper = Tap[7] * r + Tap[6];
+  Taper = Taper * r + Tap[5];
+  Taper = Taper * r + Tap[4];
+  Taper = Taper * r + Tap[3];
+  Taper = Taper * r + Tap[2];
+  Taper = Taper * r + Tap[1];
+  Taper = Taper * r + Tap[0];
+
+  denom = r * r * r + gamma;
+  denom = pow(denom,0.3333333333333);
+
+  return Taper * EV_TO_KCAL_PER_MOL / denom;
+}
+
+/* ---------------------------------------------------------------------- */
+
+int FixQEqReax::CG( double *b, double *x )
+{
+  int  i, j;
+  double tmp, alpha, beta, b_norm;
+  double sig_old, sig_new, sig0;
+
+  pack_flag = 1;
+  sparse_matvec( &H, x, q );
+  comm->reverse_comm_fix( this ); //Coll_Vector( q );
+
+  vector_sum( r , 1.,  b, -1., q, n );
+  for( j = 0; j < n; ++j )
+    d[j] = r[j] * Hdia_inv[j]; //pre-condition
+
+  b_norm = parallel_norm( b, n );
+  sig_new = parallel_dot( r, d, n );
+  sig0 = sig_new;
+
+  for( i = 1; i < 100 && sqrt(sig_new) / b_norm > tolerance; ++i ) {
+    comm->forward_comm_fix(this); //Dist_vector( d );
+    sparse_matvec( &H, d, q );
+    comm->reverse_comm_fix(this); //Coll_vector( q );
+    
+    tmp = parallel_dot( d, q, n );
+    alpha = sig_new / tmp;
+    //  comm->me, i, parallel_norm( d, n ), parallel_norm( q, n ), tmp );
+    
+    vector_add( x, alpha, d, n );
+    vector_add( r, -alpha, q, n );
+    
+    // pre-conditioning
+    for( j = 0; j < n; ++j )
+      p[j] = r[j] * Hdia_inv[j];
+    
+    sig_old = sig_new;
+    sig_new = parallel_dot( r, p, n );
+    
+
+    beta = sig_new / sig_old;
+    vector_sum( d, 1., p, beta, d, n );
+  }
+
+  if (i >= 100 && comm->me == 0)
+    error->warning("Fix qeq/reax CG convergence failed");
+
+  return i;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixQEqReax::sparse_matvec( sparse_matrix *A, double *x, double *b )
+{
+  int i, j, itr_j;
+
+  for( i = 0; i < n; ++i )
+    b[i] = eta[ atom->type[i] ] * x[i];
+  for( i = n; i < N; ++i )
+    b[i] = 0;
+  
+  for( i = 0; i < n; ++i ) {
+    for( itr_j=A->firstnbr[i]; itr_j<A->firstnbr[i]+A->numnbrs[i]; itr_j++) {
+      j = A->jlist[itr_j];
+      b[i] += A->val[itr_j] * x[j];
+      b[j] += A->val[itr_j] * x[i];
+    }
+  }
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixQEqReax::calculate_Q()
+{
+  int i, k;
+  double u, s_sum, t_sum;
+  double *q = atom->q;
+
+  s_sum = parallel_vector_acc( s, n );
+  t_sum = parallel_vector_acc( t, n);
+  u = s_sum / t_sum;
+  
+  for( i = 0; i < n; ++i ) {
+    q[i] = s[i] - u * t[i];
+  
+    /* backup s & t */
+    for( k = 4; k > 0; --k ) {
+      s_hist[i][k] = s_hist[i][k-1];
+      t_hist[i][k] = t_hist[i][k-1];
+    }
+    s_hist[i][0] = s[i];
+    t_hist[i][0] = t[i];
+  }
+
+  pack_flag = 4;
+  comm->forward_comm_fix( this ); //Dist_vector( atom->q );
+}
+
+/* ---------------------------------------------------------------------- */
+
+int FixQEqReax::pack_comm(int n, int *list, double *buf, 
+			  int pbc_flag, int *pbc)
+{
+  int m;
+
+  if( pack_flag == 1) 
+    for(m = 0; m < n; m++) buf[m] = d[list[m]];
+  else if( pack_flag == 2 )
+    for(m = 0; m < n; m++) buf[m] = s[list[m]];
+  else if( pack_flag == 3 )
+    for(m = 0; m < n; m++) buf[m] = t[list[m]];
+  else if( pack_flag == 4 )
+    for(m = 0; m < n; m++) buf[m] = atom->q[list[m]];
+
+  return 1;
+}
+ 
+/* ---------------------------------------------------------------------- */
+
+void FixQEqReax::unpack_comm(int n, int first, double *buf)
+{
+  int i, m;
+  
+  if( pack_flag == 1) 
+    for(m = 0, i = first; m < n; m++, i++) d[i] = buf[m];
+  else if( pack_flag == 2) 
+    for(m = 0, i = first; m < n; m++, i++) s[i] = buf[m];
+  else if( pack_flag == 3) 
+    for(m = 0, i = first; m < n; m++, i++) t[i] = buf[m];
+  else if( pack_flag == 4) 
+    for(m = 0, i = first; m < n; m++, i++) atom->q[i] = buf[m];
+}
+ 
+/* ---------------------------------------------------------------------- */
+
+int FixQEqReax::pack_reverse_comm(int n, int first, double *buf)
+{
+  int i, m;
+  for(m = 0, i = first; m < n; m++, i++) buf[m] = q[i];
+  return 1;
+}
+ 
+/* ---------------------------------------------------------------------- */
+
+void FixQEqReax::unpack_reverse_comm(int n, int *list, double *buf)
+{
+  for(int m = 0; m < n; m++) q[list[m]] += buf[m];
+}
+
+/* ----------------------------------------------------------------------
+   memory usage of local atom-based arrays
+------------------------------------------------------------------------- */
+
+double FixQEqReax::memory_usage()
+{
+  double bytes;
+
+  bytes = atom->nmax*nprev*2 * sizeof(double); // s_hist & t_hist
+  bytes += atom->nmax*11 * sizeof(double); // storage
+  bytes += n_cap*2 * sizeof(int); // matrix...
+  bytes += m_cap * sizeof(int);
+  bytes += m_cap * sizeof(double); 
+
+  return bytes;
+}
+
+/* ----------------------------------------------------------------------
+   allocate fictitious charge arrays
+------------------------------------------------------------------------- */
+
+void FixQEqReax::grow_arrays(int nmax)
+{
+  s_hist = memory->grow_2d_double_array(s_hist,nmax,nprev,"qeq:s_hist");
+  t_hist = memory->grow_2d_double_array(t_hist,nmax,nprev,"qeq:t_hist");
+}
+
+/* ----------------------------------------------------------------------
+   copy values within fictitious charge arrays
+------------------------------------------------------------------------- */
+
+void FixQEqReax::copy_arrays(int i, int j)
+{
+  for (int m = 0; m < nprev; m++) {
+    s_hist[j][m] = s_hist[i][m];
+    t_hist[j][m] = t_hist[i][m];
+  }
+}
+
+/* ----------------------------------------------------------------------
+   pack values in local atom-based array for exchange with another proc
+------------------------------------------------------------------------- */
+
+int FixQEqReax::pack_exchange(int i, double *buf)
+{
+  for (int m = 0; m < nprev; m++) buf[m] = s_hist[i][m];
+  for (int m = 0; m < nprev; m++) buf[nprev+m] = t_hist[i][m];
+  return nprev*2;
+}
+
+/* ----------------------------------------------------------------------
+   unpack values in local atom-based array from exchange with another proc
+------------------------------------------------------------------------- */
+
+int FixQEqReax::unpack_exchange(int nlocal, double *buf)
+{
+  for (int m = 0; m < nprev; m++) s_hist[nlocal][m] = buf[m];
+  for (int m = 0; m < nprev; m++) t_hist[nlocal][m] = buf[nprev+m];
+  return nprev*2;
+}
+
+/* ---------------------------------------------------------------------- */
+
+double FixQEqReax::parallel_norm( double *v, int n )
+{
+  int  i;
+  double my_sum, norm_sqr;
+
+  my_sum = 0;
+  for( i = 0; i < n; ++i )
+    my_sum += SQR( v[i] );
+
+  MPI_Allreduce( &my_sum, &norm_sqr, 1, MPI_DOUBLE, MPI_SUM, world );
+
+  return sqrt( norm_sqr );
+}
+
+/* ---------------------------------------------------------------------- */
+
+double FixQEqReax::parallel_dot( double *v1, double *v2, int n )
+{
+  int  i;
+  double my_dot, res;
+
+  my_dot = 0;
+  res = 0;
+  for( i = 0; i < n; ++i )
+    my_dot += v1[i] * v2[i];
+
+  MPI_Allreduce( &my_dot, &res, 1, MPI_DOUBLE, MPI_SUM, world );
+
+  return res;
+}
+
+/* ---------------------------------------------------------------------- */
+
+double FixQEqReax::parallel_vector_acc( double *v, int n )
+{
+  int  i;
+  double my_acc, res;
+
+  my_acc = 0;
+  for( i = 0; i < n; ++i )
+    my_acc += v[i];
+
+  MPI_Allreduce( &my_acc, &res, 1, MPI_DOUBLE, MPI_SUM, world );
+
+  return res;
+}
+
+/* ---------------------------------------------------------------------- */
+
+double FixQEqReax::norm( double* v1, int k )
+{
+  double ret = 0;
+  
+  for( --k; k>=0; --k )
+    ret +=  ( v1[k] * v1[k] );
+
+  return sqrt( ret );
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixQEqReax::vector_sum( double* dest, double c, double* v, 
+				double d, double* y, int k )
+{
+  for( --k; k>=0; --k )
+    dest[k] = c * v[k] + d * y[k];
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixQEqReax::vector_scale( double* dest, double c, double* v, int k )
+{
+  for( --k; k>=0; --k )
+    dest[k] = c * v[k];
+}
+
+/* ---------------------------------------------------------------------- */
+
+double FixQEqReax::dot( double* v1, double* v2, int k )
+{
+  double ret = 0;
+  
+  for( --k; k>=0; --k )
+    ret +=  v1[k] * v2[k];
+
+  return ret;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixQEqReax::vector_add( double* dest, double c, double* v, int k )
+{
+  for( --k; k>=0; --k )
+    dest[k] += c * v[k];
+}
diff --git a/src/USER-REAXC/fix_qeq_reax.h b/src/USER-REAXC/fix_qeq_reax.h
new file mode 100644
index 0000000000..ceb3814304
--- /dev/null
+++ b/src/USER-REAXC/fix_qeq_reax.h
@@ -0,0 +1,134 @@
+/* ----------------------------------------------------------------------
+   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(qeq/reax,FixQEqReax)
+
+#else
+
+#ifndef LMP_FIX_QEQ_REAX_H
+#define LMP_FIX_QEQ_REAX_H
+
+#include "fix.h"
+
+namespace LAMMPS_NS {
+
+class FixQEqReax : public Fix {
+ public:
+  FixQEqReax(class LAMMPS *, int, char **);
+  ~FixQEqReax();
+  int setmask();
+  void init();
+  void init_list(int,class NeighList *);
+  void init_storage();
+  void setup_pre_force(int);
+  void pre_force(int);
+
+  void setup_pre_force_respa(int, int);
+  void pre_force_respa(int, int, int);
+
+  void min_setup_pre_force(int);
+  void min_pre_force(int);
+
+  int matvecs;
+  double qeq_time;
+
+ private:
+  int nevery,reaxflag;
+  int n, N, m_fill;
+  int n_cap, nmax, m_cap;
+  int pack_flag;
+  int nlevels_respa;
+  class NeighList *list;
+
+  double swa, swb;      // lower/upper Taper cutoff radius
+  double Tap[8];        // Taper function
+  double tolerance;     // tolerance for the norm of the rel residual in CG
+
+  double *chi,*eta,*gamma;  // qeq parameters
+  double **shld;
+
+  // fictitious charges
+
+  double *s, *t;
+  double **s_hist, **t_hist;	
+  int nprev;
+
+  typedef struct{
+    int n, m;
+    int *firstnbr;
+    int *numnbrs;
+    int *jlist;
+    double *val;
+  } sparse_matrix;
+
+  sparse_matrix H;
+  double *Hdia_inv;
+  double *b_s, *b_t;
+  double *b_prc, *b_prm;
+
+  //CG storage
+  double *p, *q, *r, *d;
+
+  //GMRES storage
+  //double *g,*y;	  
+  //double **v;
+  //double **h;
+  //double *hc, *hs;
+  
+  void pertype_parameters(char*);
+  void init_shielding();
+  void init_taper();
+  void allocate_storage();
+  void deallocate_storage();
+  void reallocate_storage();
+  void allocate_matrix();
+  void deallocate_matrix();
+  void reallocate_matrix();
+  
+  void init_matvec();
+  void init_H();
+  void compute_H();
+  double calculate_H(double,double);
+  void calculate_Q();
+  
+  int CG(double*,double*);
+  //int GMRES(double*,double*);
+  void sparse_matvec(sparse_matrix*,double*,double*);
+  
+  int pack_comm(int, int *, double *, int, int *);
+  void unpack_comm(int, int, double *);
+  int pack_reverse_comm(int, int, double *);
+  void unpack_reverse_comm(int, int *, double *);
+  double memory_usage();
+  void grow_arrays(int);
+  void copy_arrays(int, int);
+  int pack_exchange(int, double *);
+  int unpack_exchange(int, double *);
+
+  double parallel_norm( double*, int );
+  double parallel_dot( double*, double*, int );
+  double parallel_vector_acc( double*, int );
+
+  double norm(double*,int);
+  void vector_sum(double*,double,double*,double,double*,int);
+  void vector_scale(double*,double,double*,int);
+  double dot(double*,double*,int);
+  void vector_add(double*, double, double*,int);
+};
+
+}
+
+#endif
+#endif
diff --git a/src/USER-REAXC/fix_reax_c.cpp b/src/USER-REAXC/fix_reax_c.cpp
new file mode 100644
index 0000000000..1e440dd765
--- /dev/null
+++ b/src/USER-REAXC/fix_reax_c.cpp
@@ -0,0 +1,156 @@
+/* ----------------------------------------------------------------------
+   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: Hasan Metin Aktulga, Purdue University
+------------------------------------------------------------------------- */
+
+#include "fix_reax_c.h"
+#include "atom.h"
+#include "pair.h"
+#include "comm.h"
+#include "memory.h"
+
+using namespace LAMMPS_NS;
+
+#define MAX_REAX_BONDS      30
+#define MIN_REAX_BONDS      15
+#define MIN_REAX_HBONDS     25
+
+/* ---------------------------------------------------------------------- */
+
+FixReaxC::FixReaxC(LAMMPS *lmp,int narg, char **arg) : 
+  Fix(lmp, narg, arg)
+{
+  // perform initial allocation of atom-based arrays
+  // register with atom class
+  
+  num_bonds = NULL;
+  num_hbonds = NULL;
+  grow_arrays(atom->nmax);
+  atom->add_callback(0);
+  
+  // initialize arrays to MIN so atom migration is OK the 1st time
+
+  int nlocal = atom->nlocal;
+  for (int i = 0; i < nlocal; i++)
+    num_bonds[i] = num_hbonds[i] = MIN_REAX_BONDS;
+
+  // set comm sizes needed by this fix
+
+  comm_forward = 1;
+}
+
+/* ---------------------------------------------------------------------- */
+
+FixReaxC::~FixReaxC()
+{
+  // unregister this fix so atom class doesn't invoke it any more
+
+  atom->delete_callback(id,0);
+
+  // delete locally stored arrays
+
+  memory->sfree(num_bonds);
+  memory->sfree(num_hbonds);
+}
+
+/* ---------------------------------------------------------------------- */
+
+int FixReaxC::setmask()
+{
+  int mask = 0;
+  return mask;
+}
+
+/* ----------------------------------------------------------------------
+   memory usage of local atom-based arrays
+------------------------------------------------------------------------- */
+
+double FixReaxC::memory_usage()
+{
+  int nmax = atom->nmax;
+  double bytes = nmax * 2 * sizeof(int);
+  return bytes;
+}
+
+/* ----------------------------------------------------------------------
+   allocate local atom-based arrays
+------------------------------------------------------------------------- */
+
+void FixReaxC::grow_arrays(int nmax)
+{
+  num_bonds = (int *) memory->srealloc(num_bonds,nmax*sizeof(int),
+				       "reaxc:num_bonds");
+  num_hbonds = (int *) memory->srealloc(num_hbonds,nmax*sizeof(int),
+					"reaxc:num_hbonds");
+}
+
+/* ----------------------------------------------------------------------
+   copy values within local atom-based arrays
+------------------------------------------------------------------------- */
+
+void FixReaxC::copy_arrays(int i, int j)
+{
+  num_bonds[j] = num_bonds[i];
+  num_hbonds[j] = num_hbonds[i];
+}
+
+/* ----------------------------------------------------------------------
+   pack values in local atom-based arrays for exchange with another proc
+------------------------------------------------------------------------- */
+
+int FixReaxC::pack_exchange(int i, double *buf)
+{
+  buf[0] = num_bonds[i];
+  buf[1] = num_hbonds[i];
+  return 2;
+}
+
+/* ----------------------------------------------------------------------
+   unpack values in local atom-based arrays from exchange with another proc
+------------------------------------------------------------------------- */
+
+int FixReaxC::unpack_exchange(int nlocal, double *buf)
+{
+  num_bonds[nlocal] = static_cast<int> (buf[0]);
+  num_hbonds[nlocal] = static_cast<int> (buf[1]);
+  return 2;
+}
+
+/* ---------------------------------------------------------------------- */
+
+int FixReaxC::pack_comm(int n, int *list, double *buf,
+			 int pbc_flag, int *pbc)
+{
+  int i,j,m;
+
+  m = 0;
+  for (i = 0; i < n; i++) {
+    j = list[i];
+    buf[m++] = num_bonds[j];
+  }
+  return 1;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void FixReaxC::unpack_comm(int n, int first, double *buf)
+{
+  int i,m,last;
+
+  m = 0;
+  last = first + n;
+  for (i = first; i < last; i++)
+    num_bonds[i] = buf[m++];
+}
diff --git a/src/USER-REAXC/fix_reax_c.h b/src/USER-REAXC/fix_reax_c.h
new file mode 100644
index 0000000000..8f663f7327
--- /dev/null
+++ b/src/USER-REAXC/fix_reax_c.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 FIX_CLASS
+
+FixStyle(REAXC,FixReaxC)
+
+#else
+
+#ifndef LMP_FIX_REAXC_H
+#define LMP_FIX_REAXC_H
+
+#include "fix.h"
+
+namespace LAMMPS_NS {
+
+class FixReaxC : public Fix {
+  friend class PairReaxC;
+  
+ public:
+  FixReaxC(class LAMMPS *,int, char **);
+  ~FixReaxC();
+  int setmask();
+
+  double memory_usage();
+  void grow_arrays(int);
+  void copy_arrays(int, int);
+  int pack_exchange(int, double *);
+  int unpack_exchange(int, double *);
+  int pack_comm(int, int *, double *, int, int *);
+  void unpack_comm(int, int, double *);
+
+ private:
+  int maxbonds;              // max # of bonds for any atom
+  int maxhbonds;             // max # of Hbonds for any atom
+  int *num_bonds;            // # of bonds for each atom
+  int *num_hbonds;           // # of Hbonds for each atom
+};
+
+}
+
+#endif
+#endif
diff --git a/src/USER-REAXC/pair_reax_c.cpp b/src/USER-REAXC/pair_reax_c.cpp
new file mode 100644
index 0000000000..2f7b393a65
--- /dev/null
+++ b/src/USER-REAXC/pair_reax_c.cpp
@@ -0,0 +1,664 @@
+/* ----------------------------------------------------------------------
+   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: Hasan Metin Aktulga, Purdue University
+------------------------------------------------------------------------- */
+
+#include "pair_reax_c.h"
+#include "atom.h"
+#include "update.h"
+#include "force.h"
+#include "comm.h"
+#include "neighbor.h"
+#include "neigh_list.h"
+#include "neigh_request.h"
+#include "modify.h"
+#include "fix.h"
+#include "fix_reax_c.h"
+#include "memory.h"
+#include "error.h"
+
+#include "reaxc_types.h"
+#include "reaxc_allocate.h"
+#include "reaxc_control.h"
+#include "reaxc_ffield.h"
+#include "reaxc_forces.h"
+#include "reaxc_init_md.h"
+#include "reaxc_io_tools.h"
+#include "reaxc_list.h"
+#include "reaxc_lookup.h"
+#include "reaxc_reset_tools.h"
+#include "reaxc_traj.h"
+#include "reaxc_vector.h"
+
+using namespace LAMMPS_NS;
+
+/* ---------------------------------------------------------------------- */
+
+PairReaxC::PairReaxC(LAMMPS *lmp) : Pair(lmp)
+{
+  system = (reax_system *) 
+    memory->smalloc( sizeof(reax_system), "reax:system" );
+  control = (control_params *) 
+    memory->smalloc( sizeof(control_params), "reax:control" );
+  data = (simulation_data *) 
+    memory->smalloc( sizeof(simulation_data), "reax:data" );
+  workspace = (storage *) 
+    memory->smalloc( sizeof(storage), "reax:storage" );
+  lists = (reax_list *) 
+    memory->smalloc( LIST_N * sizeof(reax_list), "reax:lists" );
+  out_control = (output_controls *) 
+    memory->smalloc( sizeof(output_controls), "reax:out_control" );
+  mpi_data = (mpi_datatypes *) 
+    memory->smalloc( sizeof(mpi_datatypes), "reax:mpi");
+
+  MPI_Comm_rank(world, &system->my_rank);
+
+  system->my_coords[0] = 0;
+  system->my_coords[1] = 0;
+  system->my_coords[2] = 0;
+  system->num_nbrs = 0;
+  system->n = 0; // my atoms
+  system->N = 0; // mine + ghosts
+  system->bigN = 0;  // all atoms in the system
+  system->local_cap = 0;
+  system->total_cap = 0;
+  system->gcell_cap = 0;
+  system->bndry_cuts.ghost_nonb = 0;
+  system->bndry_cuts.ghost_hbond = 0;
+  system->bndry_cuts.ghost_bond = 0;
+  system->bndry_cuts.ghost_cutoff = 0;
+  system->my_atoms = NULL;
+
+  fix_reax = NULL;
+}
+
+/* ---------------------------------------------------------------------- */
+
+PairReaxC::~PairReaxC()
+{
+  if (fix_reax) modify->delete_fix("REAXC");
+
+  Close_Output_Files( system, control, out_control, mpi_data );
+
+  // deallocate reax data-structures
+
+  if( control->tabulate ) Deallocate_Lookup_Tables( system );
+
+  if( control->hbond_cut > 0 )  Delete_List( lists+HBONDS, world );
+  Delete_List( lists+BONDS, world );
+  Delete_List( lists+THREE_BODIES, world );
+  Delete_List( lists+FAR_NBRS, world );
+  // fprintf( stderr, "3\n" );
+
+  DeAllocate_Workspace( control, workspace );
+  DeAllocate_System( system );
+  //fprintf( stderr, "4\n" );
+  
+  memory->sfree( system );
+  memory->sfree( control );
+  memory->sfree( data );
+  memory->sfree( workspace );
+  memory->sfree( lists );
+  memory->sfree( out_control );
+  memory->sfree( mpi_data );
+  //fprintf( stderr, "5\n" );
+
+  // deallocate interface storage
+  if( allocated ) {
+    memory->destroy_2d_int_array(setflag);
+    memory->destroy_2d_double_array(cutsq);
+    delete [] map;
+
+    delete [] chi;
+    delete [] eta;
+    delete [] gamma;
+  }
+  //fprintf( stderr, "6\n" );
+}
+
+/* ---------------------------------------------------------------------- */
+
+void PairReaxC::allocate( )
+{
+  allocated = 1;
+  int n = atom->ntypes;
+
+  setflag = memory->create_2d_int_array(n+1,n+1,"pair:setflag");
+  cutsq = memory->create_2d_double_array(n+1,n+1,"pair:cutsq");
+  map = new int[n+1];
+
+  chi = new double[n+1];
+  eta = new double[n+1];
+  gamma = new double[n+1];
+}
+
+/* ---------------------------------------------------------------------- */
+
+void PairReaxC::settings(int narg, char **arg)
+{
+  if (narg != 1) error->all("Illegal pair_style command");
+
+  if (strcmp(arg[0],"NULL") == 0) {
+    strcpy( control->sim_name, "simulate" );
+    control->ensemble = 0;
+    out_control->energy_update_freq = 0;
+    control->tabulate = 0;
+
+    control->reneighbor = 1;
+    control->vlist_cut = control->nonb_cut;
+    control->bond_cut = 5.;
+    control->hbond_cut = 7.50;
+    control->thb_cut = 0.001;
+   
+    out_control->write_steps = 0;
+    out_control->traj_method = 0;
+    strcpy( out_control->traj_title, "default_title" );
+    out_control->atom_info = 0;
+    out_control->bond_info = 0;
+    out_control->angle_info = 0;
+  } else Read_Control_File(arg[0], control, out_control);
+
+  // LAMMPS is responsible for generating nbrs
+
+  control->reneighbor = 1;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void PairReaxC::coeff( int nargs, char **args )
+{
+  if (!allocated) allocate();
+
+  if (nargs != 3 + atom->ntypes)
+    error->all("Incorrect args for pair coefficients");
+
+  // insure I,J args are * *
+
+  if (strcmp(args[0],"*") != 0 || strcmp(args[1],"*") != 0)
+    error->all("Incorrect args for pair coefficients");
+
+  // read ffield file
+
+  Read_Force_Field(args[2], &(system->reax_param), control);
+ 
+  // read args that map atom types to elements in potential file
+  // map[i] = which element the Ith atom type is, -1 if NULL
+
+  for (int i = 3; i < nargs; i++) {
+    if (strcmp(args[i],"NULL") == 0) {
+      map[i-2] = -1;
+      continue;
+    }
+    map[i-2] = atoi(args[i]) - 1;
+  }
+
+  int n = atom->ntypes;
+
+  int count = 0;
+  for (int i = 1; i <= n; i++)
+    for (int j = i; j <= n; j++) {
+      setflag[i][j] = 1;
+      count++;
+    }
+    
+  if (count == 0) error->all("Incorrect args for pair coefficients");
+}
+
+/* ---------------------------------------------------------------------- */
+
+void PairReaxC::init_style( )
+{
+  if (!atom->q_flag) error->all("Pair reax/c requires atom attribute q");
+
+  system->n = atom->nlocal;
+  system->N = atom->nlocal + atom->nghost;
+  system->bigN = static_cast<int> (atom->natoms);
+  system->wsize = comm->nprocs;
+
+  system->big_box.V = 0;
+  system->big_box.box_norms[0] = 0; 
+  system->big_box.box_norms[1] = 0; 
+  system->big_box.box_norms[2] = 0;
+
+  if (atom->tag_enable == 0)
+    error->all("Pair style reax/c requires atom IDs");
+  if (force->newton_pair == 0)
+    error->all("Pair style reax/c requires newton pair on");
+
+  // need a half neighbor list w/ Newton off
+  // built whenever re-neighboring occurs
+
+  int irequest = neighbor->request(this);
+  neighbor->requests[irequest]->newton = 2;
+
+  cutmax = MAX3(control->nonb_cut, control->hbond_cut, 2*control->bond_cut);
+
+  for( int i = 0; i < LIST_N; ++i )
+    lists[i].allocated = 0;
+
+  if (fix_reax == NULL) {
+    char **fixarg = new char*[3];
+    fixarg[0] = (char *) "REAXC";
+    fixarg[1] = (char *) "all";
+    fixarg[2] = (char *) "REAXC";
+    modify->add_fix(3,fixarg);
+    delete [] fixarg;
+    fix_reax = (FixReaxC *) modify->fix[modify->nfix-1];
+  }
+}
+
+/* ---------------------------------------------------------------------- */
+
+double PairReaxC::init_one(int i, int j)
+{
+  return cutmax;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void PairReaxC::compute(int eflag, int vflag)
+{
+  int k, oldN;
+  double evdwl,ecoul;
+  double t_start, t_end;
+
+  // communicate num_bonds once every reneighboring
+  // 2 num arrays stored by fix, grab ptr to them
+
+  if (neighbor->ago == 0) comm->forward_comm_fix(fix_reax);
+  int *num_bonds = fix_reax->num_bonds;
+  int *num_hbonds = fix_reax->num_hbonds;
+
+  evdwl = ecoul = 0.0;
+  if (eflag || vflag) ev_setup(eflag,vflag);
+  else evflag = vflag_fdotr = eflag_global = vflag_global = 0;
+
+  if (vflag_global) control->virial = 1;
+  else control->virial = 0;
+
+  system->n = atom->nlocal; // my atoms
+  oldN = system->N;
+  system->N = atom->nlocal + atom->nghost; // mine + ghosts
+  system->bigN = static_cast<int> (atom->natoms);  // all atoms in the system
+
+  system->big_box.V = 0;
+  system->big_box.box_norms[0] = 0; 
+  system->big_box.box_norms[1] = 0; 
+  system->big_box.box_norms[2] = 0;
+  if( comm->me == 0 ) t_start = MPI_Wtime();
+
+  if( update->ntimestep == 0 ) {
+    control->vlist_cut = neighbor->cutneighmax;
+
+    // determine the local and total capacity
+
+    system->local_cap = MAX( (int)(system->n * SAFE_ZONE), MIN_CAP );
+    system->total_cap = MAX( (int)(system->N * SAFE_ZONE), MIN_CAP );
+
+    // initialize my data structures
+
+    PreAllocate_Space( system, control, workspace, world );
+    write_reax_atoms();
+    
+    int num_nbrs = estimate_reax_lists();
+    if(!Make_List(system->total_cap, num_nbrs, TYP_FAR_NEIGHBOR, 
+		  lists+FAR_NBRS, world))
+      error->all("Pair reax/c problem in far neighbor list");
+    
+    write_reax_lists();
+    Initialize( system, control, data, workspace, &lists, out_control, 
+		mpi_data, world );
+    for( k = 0; k < system->N; ++k ) {
+      num_bonds[k] = system->my_atoms[k].num_bonds;
+      num_hbonds[k] = system->my_atoms[k].num_hbonds;
+    }
+
+    // locate the qeq/reax fix - for outputting log info
+    // if( comm->me == 0 ) {
+    //   int qeq_id = modify->find_fix( "qeq/reax" );
+    //   if (qeq_id < 0) fprintf(stderr, "WARNING: no qeq/reax fix applied\n");
+    //   else fix_qeq = (FixQEqReax *) modify->fix[qeq_id];
+    // }
+  } else {
+    // fill in reax datastructures
+    write_reax_atoms();
+
+    // reset the bond list info for new atoms
+    for( k = oldN; k < system->N; ++k )
+      Set_End_Index( k, Start_Index( k, lists+BONDS ), lists+BONDS );
+
+    // check if I need to shrink/extend my data-structs
+    ReAllocate( system, control, data, workspace, &lists, mpi_data );
+  }
+  
+  Reset( system, control, data, workspace, &lists, world );
+  workspace->realloc.num_far = write_reax_lists();
+  // timing for filling in the reax lists
+  if( comm->me == 0 ) {
+    t_end = MPI_Wtime();
+    data->timing.nbrs = t_end - t_start;
+  }
+
+  // forces
+
+  Compute_Forces(system,control,data,workspace,&lists,out_control,mpi_data);
+  read_reax_forces();
+
+  for( k = 0; k < system->N; ++k ) {
+    num_bonds[k] = system->my_atoms[k].num_bonds;
+    num_hbonds[k] = system->my_atoms[k].num_hbonds;
+  }
+
+  // energies and pressure
+
+  if (eflag_global) {
+    evdwl += data->my_en.e_bond;
+    evdwl += data->my_en.e_ov;
+    evdwl += data->my_en.e_un;
+    evdwl += data->my_en.e_lp;
+    evdwl += data->my_en.e_ang;
+    evdwl += data->my_en.e_pen;
+    evdwl += data->my_en.e_coa;
+    evdwl += data->my_en.e_hb;
+    evdwl += data->my_en.e_tor;
+    evdwl += data->my_en.e_con;
+    evdwl += data->my_en.e_vdW;
+
+    ecoul += data->my_en.e_ele;
+    ecoul += data->my_en.e_pol;
+
+    eng_vdwl += evdwl;
+    eng_coul += ecoul;
+  }
+
+  if (vflag_fdotr) virial_compute();
+
+// #if defined(LOG_PERFORMANCE)
+//   if( comm->me == 0 && fix_qeq != NULL ) {
+//     data->timing.s_matvecs += fix_qeq->matvecs;
+//     data->timing.qEq += fix_qeq->qeq_time;
+//   }
+// #endif
+
+  Output_Results( system, control, data, &lists, out_control, mpi_data );
+
+  ++data->step;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void PairReaxC::write_reax_atoms()
+{
+  int *num_bonds = fix_reax->num_bonds;
+  int *num_hbonds = fix_reax->num_hbonds;
+  
+  for( int i = 0; i < system->N; ++i ){
+    system->my_atoms[i].orig_id = atom->tag[i];
+    system->my_atoms[i].type = map[atom->type[i]];
+    system->my_atoms[i].x[0] = atom->x[i][0];
+    system->my_atoms[i].x[1] = atom->x[i][1];
+    system->my_atoms[i].x[2] = atom->x[i][2];
+    system->my_atoms[i].q = atom->q[i];
+    system->my_atoms[i].num_bonds = num_bonds[i];
+    system->my_atoms[i].num_hbonds = num_hbonds[i];
+  }
+}
+
+/* ---------------------------------------------------------------------- */
+
+void PairReaxC::get_distance( rvec xj, rvec xi, double *d_sqr, rvec *dvec )
+{
+  (*dvec)[0] = xj[0] - xi[0];
+  (*dvec)[1] = xj[1] - xi[1];
+  (*dvec)[2] = xj[2] - xi[2];
+  *d_sqr = SQR((*dvec)[0]) + SQR((*dvec)[1]) + SQR((*dvec)[2]);
+}
+
+/* ---------------------------------------------------------------------- */
+
+void PairReaxC::set_far_nbr( far_neighbor_data *fdest, 
+			      int j, double d, rvec dvec )
+{
+  fdest->nbr = j;
+  fdest->d = d;
+  rvec_Copy( fdest->dvec, dvec );
+  ivec_MakeZero( fdest->rel_box );
+}
+
+/* ---------------------------------------------------------------------- */
+
+int PairReaxC::estimate_reax_lists()
+{
+  int itr_i, itr_j, itr_g, i, j, g;
+  int nlocal, nghost, num_nbrs, num_marked;
+  int *ilist, *jlist, *numneigh, **firstneigh, *marked;
+  double d_sqr, g_d_sqr;
+  rvec dvec, g_dvec;
+  double *dist, **x;
+  reax_list *far_nbrs;
+  far_neighbor_data *far_list;
+
+  x = atom->x;
+  nlocal = atom->nlocal;
+  nghost = atom->nghost;
+  ilist = list->ilist;
+  numneigh = list->numneigh;
+  firstneigh = list->firstneigh;
+
+  far_nbrs = lists + FAR_NBRS;
+  far_list = far_nbrs->select.far_nbr_list;
+
+  num_nbrs = 0;
+  num_marked = 0;
+  marked = (int*) calloc( system->N, sizeof(int) );
+  dist = (double*) calloc( system->N, sizeof(double) );
+
+  for( itr_i = 0; itr_i < list->inum; ++itr_i ){
+    i = ilist[itr_i];
+    marked[i] = 1;
+    ++num_marked;
+    jlist = firstneigh[i];
+
+    for( itr_j = 0; itr_j < numneigh[i]; ++itr_j ){
+      j = jlist[itr_j];
+      get_distance( x[j], x[i], &d_sqr, &dvec );
+      dist[j] = sqrt(d_sqr);
+      
+      if( dist[j] <= control->nonb_cut )
+	++num_nbrs;
+    }
+
+    // compute the nbrs among ghost atoms
+    for( itr_j = 0; itr_j < numneigh[i]; ++itr_j ){
+      j = jlist[itr_j];
+      
+      if( j >= nlocal && !marked[j] && 
+	  dist[j] <= (control->vlist_cut - control->bond_cut) ){
+	marked[j] = 1;
+	++num_marked;
+
+	for( itr_g = 0; itr_g < numneigh[i]; ++itr_g ){
+	  g = jlist[itr_g];
+	  
+	  if( g >= nlocal && !marked[g] ){
+	    get_distance( x[g], x[j], &g_d_sqr, &g_dvec );
+	    //g_dvec[0] = x[g][0] - x[j][0];
+	    //g_dvec[1] = x[g][1] - x[j][1];
+	    //g_dvec[2] = x[g][2] - x[j][2];
+	    //g_d_sqr = SQR(g_dvec[0]) + SQR(g_dvec[1]) + SQR(g_dvec[2]);
+	    
+	    if( g_d_sqr <= SQR(control->bond_cut) )
+	      ++num_nbrs;
+	  }
+	}
+      }
+    }
+  }
+
+  for( i = 0; i < system->N; ++i )
+    if( !marked[i] ) {
+      marked[i] = 1;
+      ++num_marked;
+      
+      for( j = i+1; j < system->N; ++j )
+	if( !marked[j] ) {
+	  get_distance( x[j], x[i], &d_sqr, &dvec );
+	  if( d_sqr <= SQR(control->bond_cut) )
+	    ++num_nbrs;
+	}
+    }
+  
+  free( marked );
+  free( dist );
+
+  return static_cast<int> (MAX( num_nbrs*SAFE_ZONE, MIN_CAP*MIN_NBRS ));
+}
+
+/* ---------------------------------------------------------------------- */
+
+int PairReaxC::write_reax_lists()
+{
+  int itr_i, itr_j, itr_g, i, j, g;
+  int nlocal, nghost, num_nbrs;
+  int *ilist, *jlist, *numneigh, **firstneigh, *marked;
+  double d_sqr, g_d, g_d_sqr;
+  rvec dvec, g_dvec;
+  double *dist, **x;
+  reax_list *far_nbrs;
+  far_neighbor_data *far_list;
+
+  x = atom->x;
+  nlocal = atom->nlocal;
+  nghost = atom->nghost;
+  ilist = list->ilist;
+  numneigh = list->numneigh;
+  firstneigh = list->firstneigh;
+
+  far_nbrs = lists + FAR_NBRS;
+  far_list = far_nbrs->select.far_nbr_list;
+
+  num_nbrs = 0;  
+  marked = (int*) calloc( system->N, sizeof(int) );
+  dist = (double*) calloc( system->N, sizeof(double) );
+
+  for( itr_i = 0; itr_i < list->inum; ++itr_i ){
+    i = ilist[itr_i];
+    marked[i] = 1;
+    jlist = firstneigh[i];
+    Set_Start_Index( i, num_nbrs, far_nbrs );
+
+    for( itr_j = 0; itr_j < numneigh[i]; ++itr_j ){
+      j = jlist[itr_j];
+      get_distance( x[j], x[i], &d_sqr, &dvec );
+      dist[j] = sqrt( d_sqr );
+
+      if( dist[j] <= control->nonb_cut ){
+	set_far_nbr( &far_list[num_nbrs], j, dist[j], dvec );
+	++num_nbrs;
+      }
+    }
+    Set_End_Index( i, num_nbrs, far_nbrs );
+
+    // compute the nbrs among ghost atoms
+    for( itr_j = 0; itr_j < numneigh[i]; ++itr_j ){
+      j = jlist[itr_j];
+
+      if( j >= nlocal && !marked[j] && 
+	  dist[j] <= (control->vlist_cut - control->bond_cut) ){
+	marked[j] = 1;      
+     	Set_Start_Index( j, num_nbrs, far_nbrs );
+
+	for( itr_g = 0; itr_g < numneigh[i]; ++itr_g ){
+	  g = jlist[itr_g];
+	  
+	  if( g >= nlocal && !marked[g] ){
+	    get_distance( x[g], x[j], &g_d_sqr, &g_dvec );
+	    
+	    if( g_d_sqr <= SQR(control->bond_cut) ){
+	      g_d = sqrt( g_d_sqr );
+	      
+	      set_far_nbr( &far_list[num_nbrs], g, g_d, g_dvec );
+	      ++num_nbrs;
+	    }
+	  }
+	}
+	Set_End_Index( j, num_nbrs, far_nbrs );
+      }
+    }
+  }
+
+  for( i = 0; i < system->N; ++i )
+    if( !marked[i] ) {
+      marked[i] = 1;
+      Set_Start_Index( i, num_nbrs, far_nbrs );
+      
+      for( j = i+1; j < system->N; ++j )
+	if( !marked[j] ) {
+	  get_distance( x[j], x[i], &d_sqr, &dvec );
+	  if( d_sqr <= SQR(control->bond_cut) ) {
+	    set_far_nbr( &far_list[num_nbrs], j, sqrt(d_sqr), dvec );
+	    ++num_nbrs;
+	  }
+	}
+
+      Set_End_Index( i, num_nbrs, far_nbrs );
+    }
+  
+  free( marked );
+  free( dist );
+  
+  return num_nbrs;
+}
+  
+/* ---------------------------------------------------------------------- */
+  
+void PairReaxC::read_reax_forces()
+{
+  for( int i = 0; i < system->N; ++i ) {
+    system->my_atoms[i].f[0] = workspace->f[i][0];
+    system->my_atoms[i].f[1] = workspace->f[i][1];
+    system->my_atoms[i].f[2] = workspace->f[i][2];
+
+    atom->f[i][0] = -workspace->f[i][0];
+    atom->f[i][1] = -workspace->f[i][1];
+    atom->f[i][2] = -workspace->f[i][2];
+  }
+}
+
+/* ---------------------------------------------------------------------- */
+
+void *PairReaxC::extract(char *str, int &dim)
+{
+  dim = 1;
+  if (strcmp(str,"chi") == 0 && chi) {
+    for (int i = 1; i <= atom->ntypes; i++)
+      if (map[i] >= 0) chi[i] = system->reax_param.sbp[map[i]].chi;
+      else chi[i] = 0.0;
+    return (void *) chi;
+  }
+  if (strcmp(str,"eta") == 0 && eta) {
+    for (int i = 1; i <= atom->ntypes; i++)
+      if (map[i] >= 0) eta[i] = system->reax_param.sbp[map[i]].eta;
+      else eta[i] = 0.0;
+    return (void *) eta;
+  }
+  if (strcmp(str,"gamma") == 0 && gamma) {
+    for (int i = 1; i <= atom->ntypes; i++)
+      if (map[i] >= 0) gamma[i] = system->reax_param.sbp[map[i]].gamma;
+      else gamma[i] = 0.0;
+    return (void *) gamma;
+  }
+  return NULL;
+}
diff --git a/src/USER-REAXC/pair_reax_c.h b/src/USER-REAXC/pair_reax_c.h
new file mode 100644
index 0000000000..a556adf42f
--- /dev/null
+++ b/src/USER-REAXC/pair_reax_c.h
@@ -0,0 +1,66 @@
+/* ----------------------------------------------------------------------
+   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(reax/c,PairReaxC)
+
+#else
+
+#ifndef LMP_PAIR_REAXC_H
+#define LMP_PAIR_REAXC_H
+
+#include "pair.h"
+#include "reaxc_types.h"
+
+namespace LAMMPS_NS {
+
+class PairReaxC : public Pair {
+ public:
+  PairReaxC(class LAMMPS *);
+  ~PairReaxC();
+  void compute(int, int);
+  void settings(int, char **);
+  void coeff(int, char **);
+  void init_style();
+  double init_one(int, int);
+  void *extract(char *, int &);
+
+ private:
+  reax_system *system;
+  control_params *control;
+  simulation_data *data;
+  storage *workspace;
+  reax_list *lists;
+  output_controls *out_control;
+  mpi_datatypes *mpi_data;
+  
+  double cutmax;
+  int *map;
+  class FixReaxC *fix_reax;
+  
+  double *chi,*eta,*gamma;
+
+  void allocate();
+  void write_reax_atoms();
+  void get_distance(rvec, rvec, double *, rvec *);
+  void set_far_nbr(far_neighbor_data *, int, double, rvec);
+  int estimate_reax_lists();
+  int write_reax_lists();
+  void read_reax_forces();
+};
+  
+}
+
+#endif
+#endif
diff --git a/src/USER-REAXC/reaxc_allocate.cpp b/src/USER-REAXC/reaxc_allocate.cpp
new file mode 100644
index 0000000000..1851ac5bd9
--- /dev/null
+++ b/src/USER-REAXC/reaxc_allocate.cpp
@@ -0,0 +1,1011 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#include "reaxc_types.h"
+#if defined(PURE_REAX)
+#include "allocate.h"
+#include "list.h"
+#include "reset_tools.h"
+#include "tool_box.h"
+#include "vector.h"
+#elif defined(LAMMPS_REAX)
+#include "reaxc_allocate.h"
+#include "reaxc_list.h"
+#include "reaxc_reset_tools.h"
+#include "reaxc_tool_box.h"
+#include "reaxc_vector.h"
+#endif
+
+
+/* allocate space for my_atoms
+   important: we cannot know the exact number of atoms that will fall into a 
+   process's box throughout the whole simulation. therefore 
+   we need to make upper bound estimates for various data structures */
+int PreAllocate_Space( reax_system *system, control_params *control, 
+		       storage *workspace, MPI_Comm comm )
+{
+  int  i;
+
+  /* determine the local and total capacity */
+  system->local_cap = MAX( (int)(system->n * SAFE_ZONE), MIN_CAP );
+  system->total_cap = MAX( (int)(system->N * SAFE_ZONE), MIN_CAP );
+#if defined(DEBUG)
+  fprintf( stderr, "p%d: local_cap=%d total_cap=%d\n", 
+	   system->my_rank, system->local_cap, system->total_cap );
+#endif
+
+  system->my_atoms = (reax_atom*) 
+    scalloc( system->total_cap, sizeof(reax_atom), "my_atoms", comm );
+  
+  /* space for keeping restriction info, if any */
+  // not yet implemented in the parallel version!!!
+  // if( control->restrict_bonds ) {
+  //   workspace->restricted  = (int*) 
+  //     scalloc( system->local_cap, sizeof(int), "restricted_atoms", comm );
+    
+  //   workspace->restricted_list = (int**) 
+  //     scalloc( system->local_cap, sizeof(int*), "restricted_list", comm );
+    
+  //   for( i = 0; i < system->local_cap; ++i )
+  //     workspace->restricted_list[i] = (int*) 
+  // 	scalloc( MAX_RESTRICT, sizeof(int), "restricted_list[i]", comm );
+  // }
+  
+  return SUCCESS;
+}
+
+
+/*************       system        *************/
+inline void reax_atom_Copy( reax_atom *dest, reax_atom *src )
+{
+  dest->orig_id = src->orig_id;
+  dest->type = src->type;
+  strcpy( dest->name, src->name );
+  rvec_Copy( dest->x, src->x );
+  rvec_Copy( dest->v, src->v );
+  rvec_Copy( dest->f_old, src->f_old );
+  rvec_Copy( dest->s, src->s );
+  rvec_Copy( dest->t, src->t );
+  dest->Hindex = src->Hindex;
+  dest->num_bonds = src->num_bonds;
+  dest->num_hbonds = src->num_hbonds;
+}
+
+
+void Copy_Atom_List( reax_atom *dest, reax_atom *src, int n )
+{
+  int i;
+  
+  for( i = 0; i < n; ++i )
+    memcpy( dest+i, src+i, sizeof(reax_atom) );
+}
+
+
+int Allocate_System( reax_system *system, int local_cap, int total_cap, 
+		     char *msg )
+{
+  system->my_atoms = (reax_atom*) 
+    realloc( system->my_atoms, total_cap*sizeof(reax_atom) );
+
+  return SUCCESS;
+}
+
+
+void DeAllocate_System( reax_system *system )
+{
+  int i, j, k;
+  int ntypes;
+  reax_interaction *ff_params;
+
+  // dealloocate the atom list
+  sfree( system->my_atoms, "system->my_atoms" );
+  
+  // deallocate the ffield parameters storage
+  ff_params = &(system->reax_param);
+  ntypes = ff_params->num_atom_types;
+
+  sfree( ff_params->gp.l, "ff:globals" );
+
+  for( i = 0; i < ntypes; ++i ) {
+    for( j = 0; j < ntypes; ++j ) {
+      for( k = 0; k < ntypes; ++k ) {
+	sfree( ff_params->fbp[i][j][k], "ff:fbp[i,j,k]" );
+      }
+      sfree( ff_params->fbp[i][j], "ff:fbp[i,j]" );
+      sfree( ff_params->thbp[i][j], "ff:thbp[i,j]" );
+      sfree( ff_params->hbp[i][j], "ff:hbp[i,j]" );
+    }
+    sfree( ff_params->fbp[i], "ff:fbp[i]" );
+    sfree( ff_params->thbp[i], "ff:thbp[i]" );
+    sfree( ff_params->hbp[i], "ff:hbp[i]" );
+    sfree( ff_params->tbp[i], "ff:tbp[i]" );
+  }
+  sfree( ff_params->fbp, "ff:fbp" );
+  sfree( ff_params->thbp, "ff:thbp" );
+  sfree( ff_params->hbp, "ff:hbp" );
+  sfree( ff_params->tbp, "ff:tbp" );
+  sfree( ff_params->sbp, "ff:sbp" );
+}
+
+
+/*************       workspace        *************/
+void DeAllocate_Workspace( control_params *control, storage *workspace )
+{
+  int i;
+
+  if( !workspace->allocated )
+    return;
+  
+  workspace->allocated = 0;
+
+  /* communication storage */
+  for( i = 0; i < MAX_NBRS; ++i ) {
+    sfree( workspace->tmp_dbl[i], "tmp_dbl[i]" );
+    sfree( workspace->tmp_rvec[i], "tmp_rvec[i]" );
+    sfree( workspace->tmp_rvec2[i], "tmp_rvec2[i]" );
+  }
+
+  /* bond order storage */
+  sfree( workspace->within_bond_box, "skin" );
+  sfree( workspace->total_bond_order, "total_bo" );
+  sfree( workspace->Deltap, "Deltap" );
+  sfree( workspace->Deltap_boc, "Deltap_boc" );
+  sfree( workspace->dDeltap_self, "dDeltap_self" );
+  sfree( workspace->Delta, "Delta" );
+  sfree( workspace->Delta_lp, "Delta_lp" );
+  sfree( workspace->Delta_lp_temp, "Delta_lp_temp" );
+  sfree( workspace->dDelta_lp, "dDelta_lp" );
+  sfree( workspace->dDelta_lp_temp, "dDelta_lp_temp" );
+  sfree( workspace->Delta_e, "Delta_e" );
+  sfree( workspace->Delta_boc, "Delta_boc" );
+  sfree( workspace->nlp, "nlp" );
+  sfree( workspace->nlp_temp, "nlp_temp" );
+  sfree( workspace->Clp, "Clp" );
+  sfree( workspace->vlpex, "vlpex" );
+  sfree( workspace->bond_mark, "bond_mark" );
+  sfree( workspace->done_after, "done_after" );
+
+  /* QEq storage */
+  sfree( workspace->Hdia_inv, "Hdia_inv" );
+  sfree( workspace->b_s, "b_s" );
+  sfree( workspace->b_t, "b_t" );
+  sfree( workspace->b_prc, "b_prc" );
+  sfree( workspace->b_prm, "b_prm" );
+  sfree( workspace->s, "s" );
+  sfree( workspace->t, "t" );
+  sfree( workspace->droptol, "droptol" );
+  sfree( workspace->b, "b" );
+  sfree( workspace->x, "x" );
+
+  /* GMRES storage */
+  for( i = 0; i < RESTART+1; ++i ) {
+    sfree( workspace->h[i], "h[i]" );
+    sfree( workspace->v[i], "v[i]" );
+  }
+  sfree( workspace->h, "h" );
+  sfree( workspace->v, "v" );
+  sfree( workspace->y, "y" );
+  sfree( workspace->z, "z" );
+  sfree( workspace->g, "g" );
+  sfree( workspace->hs, "hs" );
+  sfree( workspace->hc, "hc" );
+  /* CG storage */
+  sfree( workspace->r, "r" );
+  sfree( workspace->d, "d" );
+  sfree( workspace->q, "q" );
+  sfree( workspace->p, "p" );
+  sfree( workspace->r2, "r2" );
+  sfree( workspace->d2, "d2" );
+  sfree( workspace->q2, "q2" );
+  sfree( workspace->p2, "p2" );
+
+  /* integrator */
+  // sfree( workspace->f_old );
+  sfree( workspace->v_const, "v_const" );
+
+  /*workspace->realloc.num_far = -1;
+    workspace->realloc.Htop = -1;
+    workspace->realloc.hbonds = -1;
+    workspace->realloc.bonds = -1;
+    workspace->realloc.num_3body = -1;
+    workspace->realloc.gcell_atoms = -1;*/
+
+  /* storage for analysis */
+  // if( control->molecular_analysis || control->diffusion_coef ) {
+  //   sfree( workspace->mark, "mark" );
+  //   sfree( workspace->old_mark, "old_mark" );
+  // }
+
+  // if( control->diffusion_coef )
+  //   sfree( workspace->x_old, "x_old" );
+
+  /* force related storage */
+  sfree( workspace->f, "f" );
+  sfree( workspace->CdDelta, "CdDelta" );
+#ifdef TEST_FORCES
+  sfree(workspace->dDelta, "dDelta" );
+  sfree( workspace->f_ele, "f_ele" );
+  sfree( workspace->f_vdw, "f_vdw" );
+  sfree( workspace->f_bo, "f_bo" );
+  sfree( workspace->f_be, "f_be" );
+  sfree( workspace->f_lp, "f_lp" );
+  sfree( workspace->f_ov, "f_ov" );
+  sfree( workspace->f_un, "f_un" );
+  sfree( workspace->f_ang, "f_ang" );
+  sfree( workspace->f_coa, "f_coa" );
+  sfree( workspace->f_pen, "f_pen" );
+  sfree( workspace->f_hb, "f_hb" );
+  sfree( workspace->f_tor, "f_tor" );
+  sfree( workspace->f_con, "f_con" );
+  sfree( workspace->f_tot, "f_tot" );
+
+  sfree( workspace->rcounts, "rcounts" );
+  sfree( workspace->displs, "displs" );
+  sfree( workspace->id_all, "id_all" );
+  sfree( workspace->f_all, "f_all" );
+#endif
+
+  /* hbond storage */
+  //sfree( workspace->Hindex, "Hindex" );
+  //sfree( workspace->num_bonds );
+  //sfree( workspace->num_hbonds );
+  //sfree( workspace->hash, "hash" );
+  //sfree( workspace->rev_hash, "rev_hash" );
+}
+
+
+int Allocate_Workspace( reax_system *system, control_params *control, 
+			storage *workspace, int local_cap, int total_cap, 
+			MPI_Comm comm, char *msg )
+{ 
+  int i, total_real, total_rvec, local_int, local_real, local_rvec;
+
+  workspace->allocated = 1;
+  total_real = total_cap * sizeof(real);
+  total_rvec = total_cap * sizeof(rvec);
+  local_int = local_cap * sizeof(int);
+  local_real = local_cap * sizeof(real);
+  local_rvec = local_cap * sizeof(rvec);
+
+  /* communication storage */  
+  for( i = 0; i < MAX_NBRS; ++i ) {
+    workspace->tmp_dbl[i] = (real*)
+      scalloc( total_cap, sizeof(real), "tmp_dbl", comm );
+    workspace->tmp_rvec[i] = (rvec*)
+      scalloc( total_cap, sizeof(rvec), "tmp_rvec", comm );
+    workspace->tmp_rvec2[i] = (rvec2*)
+      scalloc( total_cap, sizeof(rvec2), "tmp_rvec2", comm );
+  }
+
+  /* bond order related storage  */
+  workspace->within_bond_box = (int*) 
+    scalloc( total_cap, sizeof(int), "skin", comm );
+  workspace->total_bond_order = (real*) smalloc( total_real, "total_bo", comm );
+  workspace->Deltap = (real*) smalloc( total_real, "Deltap", comm );
+  workspace->Deltap_boc = (real*) smalloc( total_real, "Deltap_boc", comm );
+  workspace->dDeltap_self = (rvec*) smalloc( total_rvec, "dDeltap_self", comm );
+  workspace->Delta = (real*) smalloc( total_real, "Delta", comm );
+  workspace->Delta_lp = (real*) smalloc( total_real, "Delta_lp", comm );
+  workspace->Delta_lp_temp = (real*) 
+    smalloc( total_real, "Delta_lp_temp", comm );
+  workspace->dDelta_lp = (real*) smalloc( total_real, "dDelta_lp", comm );
+  workspace->dDelta_lp_temp = (real*) 
+    smalloc( total_real, "dDelta_lp_temp", comm );
+  workspace->Delta_e = (real*) smalloc( total_real, "Delta_e", comm );
+  workspace->Delta_boc = (real*) smalloc( total_real, "Delta_boc", comm );
+  workspace->nlp = (real*) smalloc( total_real, "nlp", comm );
+  workspace->nlp_temp = (real*) smalloc( total_real, "nlp_temp", comm );
+  workspace->Clp = (real*) smalloc( total_real, "Clp", comm );
+  workspace->vlpex = (real*) smalloc( total_real, "vlpex", comm );
+  workspace->bond_mark = (int*) 
+    scalloc( total_cap, sizeof(int), "bond_mark", comm );
+  workspace->done_after = (int*) 
+    scalloc( total_cap, sizeof(int), "done_after", comm );
+  // fprintf( stderr, "p%d: bond order storage\n", system->my_rank );
+
+  /* QEq storage */
+  workspace->Hdia_inv = (real*) 
+    scalloc( total_cap, sizeof(real), "Hdia_inv", comm );
+  workspace->b_s = (real*) scalloc( total_cap, sizeof(real), "b_s", comm );
+  workspace->b_t = (real*) scalloc( total_cap, sizeof(real), "b_t", comm );
+  workspace->b_prc = (real*) scalloc( total_cap, sizeof(real), "b_prc", comm );
+  workspace->b_prm = (real*) scalloc( total_cap, sizeof(real), "b_prm", comm );
+  workspace->s = (real*) scalloc( total_cap, sizeof(real), "s", comm );
+  workspace->t = (real*) scalloc( total_cap, sizeof(real), "t", comm );
+  workspace->droptol = (real*) 
+    scalloc( total_cap, sizeof(real), "droptol", comm );
+  workspace->b = (rvec2*) scalloc( total_cap, sizeof(rvec2), "b", comm );
+  workspace->x = (rvec2*) scalloc( total_cap, sizeof(rvec2), "x", comm );
+  
+  /* GMRES storage */
+  workspace->y = (real*) scalloc( RESTART+1, sizeof(real), "y", comm );
+  workspace->z = (real*) scalloc( RESTART+1, sizeof(real), "z", comm );
+  workspace->g = (real*) scalloc( RESTART+1, sizeof(real), "g", comm );
+  workspace->h = (real**) scalloc( RESTART+1, sizeof(real*), "h", comm );
+  workspace->hs = (real*) scalloc( RESTART+1, sizeof(real), "hs", comm );
+  workspace->hc = (real*) scalloc( RESTART+1, sizeof(real), "hc", comm );
+  workspace->v = (real**) scalloc( RESTART+1, sizeof(real*), "v", comm );
+  
+  for( i = 0; i < RESTART+1; ++i ) {
+    workspace->h[i] = (real*) scalloc( RESTART+1, sizeof(real), "h[i]", comm );
+    workspace->v[i] = (real*) scalloc( total_cap, sizeof(real), "v[i]", comm );
+  }
+
+  /* CG storage */
+  workspace->r = (real*) scalloc( total_cap, sizeof(real), "r", comm );
+  workspace->d = (real*) scalloc( total_cap, sizeof(real), "d", comm );
+  workspace->q = (real*) scalloc( total_cap, sizeof(real), "q", comm );
+  workspace->p = (real*) scalloc( total_cap, sizeof(real), "p", comm );
+  workspace->r2 = (rvec2*) scalloc( total_cap, sizeof(rvec2), "r2", comm );
+  workspace->d2 = (rvec2*) scalloc( total_cap, sizeof(rvec2), "d2", comm );
+  workspace->q2 = (rvec2*) scalloc( total_cap, sizeof(rvec2), "q2", comm );
+  workspace->p2 = (rvec2*) scalloc( total_cap, sizeof(rvec2), "p2", comm );
+
+  /* integrator storage */
+  workspace->v_const = (rvec*) smalloc( local_rvec, "v_const", comm );
+
+  /* storage for analysis */
+  // not yet implemented in the parallel version!!!
+  // if( control->molecular_analysis || control->diffusion_coef ) {
+  //   workspace->mark = (int*) scalloc( local_cap, sizeof(int), "mark", comm );
+  //   workspace->old_mark = (int*) 
+  //     scalloc( local_cap, sizeof(int), "old_mark", comm );
+  // }
+  // else 
+  //   workspace->mark = workspace->old_mark = NULL;
+
+  // if( control->diffusion_coef )
+  //   workspace->x_old = (rvec*) 
+  //     scalloc( local_cap, sizeof(rvec), "x_old", comm );
+  // else workspace->x_old = NULL;
+  
+  // /* force related storage */
+  workspace->f = (rvec*) scalloc( total_cap, sizeof(rvec), "f", comm );
+  workspace->CdDelta = (real*) 
+    scalloc( total_cap, sizeof(real), "CdDelta", comm );
+
+#ifdef TEST_FORCES
+  workspace->dDelta=(rvec*) smalloc( total_rvec, "dDelta", comm );
+  workspace->f_ele =(rvec*) smalloc( total_rvec, "f_ele", comm );
+  workspace->f_vdw =(rvec*) smalloc( total_rvec, "f_vdw", comm );
+  workspace->f_bo =(rvec*) smalloc( total_rvec, "f_bo", comm );
+  workspace->f_be =(rvec*) smalloc( total_rvec, "f_be", comm );
+  workspace->f_lp =(rvec*) smalloc( total_rvec, "f_lp", comm );
+  workspace->f_ov =(rvec*) smalloc( total_rvec, "f_ov", comm );
+  workspace->f_un =(rvec*) smalloc( total_rvec, "f_un", comm );
+  workspace->f_ang =(rvec*) smalloc( total_rvec, "f_ang", comm );
+  workspace->f_coa =(rvec*) smalloc( total_rvec, "f_coa", comm );
+  workspace->f_pen =(rvec*) smalloc( total_rvec, "f_pen", comm );
+  workspace->f_hb =(rvec*) smalloc( total_rvec, "f_hb", comm );
+  workspace->f_tor =(rvec*) smalloc( total_rvec, "f_tor", comm );
+  workspace->f_con =(rvec*) smalloc( total_rvec, "f_con", comm );
+  workspace->f_tot =(rvec*) smalloc( total_rvec, "f_tot", comm );
+
+  if( system->my_rank == MASTER_NODE ) {
+    workspace->rcounts = (int*) 
+      smalloc( system->wsize*sizeof(int), "rcount", comm );
+    workspace->displs = (int*) 
+      smalloc( system->wsize*sizeof(int), "displs", comm );
+    workspace->id_all = (int*) 
+      smalloc( system->bigN*sizeof(int), "id_all", comm );
+    workspace->f_all = (rvec*) 
+      smalloc( system->bigN*sizeof(rvec), "f_all", comm );
+  }
+  else{
+    workspace->rcounts = NULL;
+    workspace->displs = NULL;
+    workspace->id_all = NULL;
+    workspace->f_all = NULL;
+  }
+#endif
+
+  return SUCCESS;
+}
+
+
+void Reallocate_Neighbor_List( reax_list *far_nbrs, int n, int num_intrs,
+			       MPI_Comm comm )
+{
+  Delete_List( far_nbrs, comm );
+  if(!Make_List( n, num_intrs, TYP_FAR_NEIGHBOR, far_nbrs, comm )){
+    fprintf(stderr, "Problem in initializing far nbrs list. Terminating!\n");
+    MPI_Abort( comm, INSUFFICIENT_MEMORY );
+  }
+}
+
+
+int Allocate_Matrix( sparse_matrix **pH, int cap, int m, MPI_Comm comm )
+{
+  sparse_matrix *H;
+
+  *pH = (sparse_matrix*) 
+    smalloc( sizeof(sparse_matrix), "sparse_matrix", comm );
+  H = *pH;
+  H->cap = cap;
+  H->m = m;
+  H->start = (int*) smalloc( sizeof(int) * cap, "matrix_start", comm ); 
+  H->end = (int*) smalloc( sizeof(int) * cap, "matrix_end", comm );
+  H->entries = (sparse_matrix_entry*) 
+    smalloc( sizeof(sparse_matrix_entry)*m, "matrix_entries", comm );
+
+  return SUCCESS;
+}
+
+
+void Deallocate_Matrix( sparse_matrix *H )
+{
+  sfree(H->start, "H->start");
+  sfree(H->end, "H->end");
+  sfree(H->entries, "H->entries");
+  sfree(H, "H");
+}
+
+
+int Reallocate_Matrix( sparse_matrix **H, int n, int m, char *name, 
+		       MPI_Comm comm )
+{
+  Deallocate_Matrix( *H );
+  if( !Allocate_Matrix( H, n, m, comm ) ) {
+    fprintf(stderr, "not enough space for %s matrix. terminating!\n", name);
+    MPI_Abort( comm, INSUFFICIENT_MEMORY );
+  }
+
+#if defined(DEBUG_FOCUS)
+  fprintf( stderr, "reallocating %s matrix, n = %d, m = %d\n", name, n, m );
+  fprintf( stderr, "memory allocated: %s = %dMB\n", 
+	   name, (int)(m * sizeof(sparse_matrix_entry) / (1024*1024)) );
+#endif
+  return SUCCESS;
+}
+
+
+int Reallocate_HBonds_List( reax_system *system, reax_list *hbonds, 
+			    MPI_Comm comm )
+{
+  int i, id, total_hbonds;
+
+  total_hbonds = 0;
+  for( i = 0; i < system->n; ++i )
+    if( (id = system->my_atoms[i].Hindex) >= 0 ) {
+      // commented out - already updated in validate_lists in forces.c
+      // system->my_atoms[i].num_hbonds = MAX(Num_Entries(id,hbonds)*SAFER_ZONE,
+      //                                   MIN_HBONDS);
+      total_hbonds += system->my_atoms[i].num_hbonds;
+    } 
+  total_hbonds = (int)(MAX( total_hbonds*SAFER_ZONE, MIN_CAP*MIN_HBONDS ));
+  
+  Delete_List( hbonds, comm );
+  if( !Make_List( system->Hcap, total_hbonds, TYP_HBOND, hbonds, comm ) ) {
+    fprintf( stderr, "not enough space for hbonds list. terminating!\n" );
+    MPI_Abort( comm, INSUFFICIENT_MEMORY );
+  }
+
+  return total_hbonds;
+}
+
+
+int Reallocate_Bonds_List( reax_system *system, reax_list *bonds,
+			   int *total_bonds, int *est_3body, MPI_Comm comm )
+{
+  int i;
+
+  *total_bonds = 0;
+  *est_3body = 0;
+  for( i = 0; i < system->N; ++i ){
+    *est_3body += SQR( Num_Entries( i, bonds ) );
+    // commented out - already updated in validate_lists in forces.c
+    // system->my_atoms[i].num_bonds = MAX( Num_Entries(i,bonds)*2, MIN_BONDS );
+    *total_bonds += system->my_atoms[i].num_bonds;
+  }
+  *total_bonds = (int)(MAX( *total_bonds * SAFE_ZONE, MIN_CAP*MIN_BONDS ));
+  
+  Delete_List( bonds, comm );
+  if(!Make_List(system->total_cap, *total_bonds, TYP_BOND, bonds, comm)) {
+    fprintf( stderr, "not enough space for bonds list. terminating!\n" );
+    MPI_Abort( comm, INSUFFICIENT_MEMORY );
+  }
+
+  return SUCCESS;
+}
+
+
+/*************       grid        *************/
+int Estimate_GCell_Population( reax_system* system, MPI_Comm comm )
+{
+  int d, i, j, k, l, max_atoms, my_max, all_max;
+  ivec c;
+  grid *g;
+  grid_cell *gc;
+  simulation_box *big_box, *my_ext_box;
+  reax_atom *atoms;
+  
+  big_box    = &(system->big_box);
+  my_ext_box = &(system->my_ext_box);
+  g          = &(system->my_grid);
+  atoms      = system->my_atoms;
+  Reset_Grid( g );
+
+  for( l = 0; l < system->n; l++ ) {
+    for( d = 0; d < 3; ++d ) {
+      //if( atoms[l].x[d] < big_box->min[d] )
+      //  atoms[l].x[d] += big_box->box_norms[d];
+      //else if( atoms[l].x[d] >= big_box->max[d] )
+      //  atoms[l].x[d] -= big_box->box_norms[d];
+      
+      c[d] = (int)((atoms[l].x[d]-my_ext_box->min[d])*g->inv_len[d]);
+      
+      if( c[d] >= g->native_end[d] )
+	c[d] = g->native_end[d] - 1;
+      else if( c[d] < g->native_str[d] )
+	c[d] = g->native_str[d];
+    }
+#if defined(DEBUG)
+    fprintf( stderr, "p%d bin_my_atoms: l:%d - atom%d @ %.5f %.5f %.5f"	\
+	     "--> cell: %d %d %d\n",
+	     system->my_rank, l, atoms[l].orig_id, 
+	     atoms[l].x[0], atoms[l].x[1], atoms[l].x[2],
+	     c[0], c[1], c[2] );
+#endif
+    gc = &( g->cells[c[0]][c[1]][c[2]] );
+    gc->top++;
+  }
+ 
+  max_atoms = 0;
+  for( i = 0; i < g->ncells[0]; i++ )
+    for( j = 0; j < g->ncells[1]; j++ )
+      for( k = 0; k < g->ncells[2]; k++ ) {
+	gc = &(g->cells[i][j][k]);
+	if( max_atoms < gc->top )
+	  max_atoms = gc->top;
+#if defined(DEBUG)
+	fprintf( stderr, "p%d gc[%d,%d,%d]->top=%d\n", 
+		 system->my_rank, i, j, k, gc->top );
+#endif
+      }
+
+  my_max = (int)(MAX(max_atoms*SAFE_ZONE, MIN_GCELL_POPL)); 
+  MPI_Allreduce( &my_max, &all_max, 1, MPI_INT, MPI_MAX, comm );
+#if defined(DEBUG)
+  fprintf( stderr, "p%d max_atoms=%d, my_max=%d, all_max=%d\n", 
+	   system->my_rank, max_atoms, my_max, all_max );
+#endif
+
+  return all_max;
+}
+
+
+void Allocate_Grid( reax_system *system, MPI_Comm comm )
+{
+  int i, j, k, l;
+  grid *g;
+  grid_cell *gc;
+  
+  g = &( system->my_grid );
+
+  /* allocate gcell reordering space */
+  g->order = (ivec*) scalloc( g->total+1, sizeof(ivec), "g:order", comm );
+
+  /* allocate the gcells for the new grid */
+  g->max_nbrs = (2*g->vlist_span[0]+1)*(2*g->vlist_span[1]+1)*
+    (2*g->vlist_span[2]+1)+3; 
+
+  g->cells = (grid_cell***) 
+    scalloc( g->ncells[0], sizeof(grid_cell**), "gcells", comm );
+  for( i = 0; i < g->ncells[0]; i++ ) {
+    g->cells[i] = (grid_cell**) 
+      scalloc( g->ncells[1], sizeof(grid_cell*),"gcells[i]", comm );
+      
+    for( j = 0; j < g->ncells[1]; ++j )	{
+      g->cells[i][j] = (grid_cell*) 
+	scalloc( g->ncells[2], sizeof(grid_cell), "gcells[i][j]", comm );
+
+      for( k = 0; k < g->ncells[2]; k++ ) {
+	gc = &(g->cells[i][j][k]);
+	gc->top = gc->mark = gc->str = gc->end = 0;
+	gc->nbrs = (grid_cell**) 
+	  scalloc( g->max_nbrs, sizeof(grid_cell*), "g:nbrs", comm );
+	gc->nbrs_x = (ivec*) 
+	  scalloc( g->max_nbrs, sizeof(ivec), "g:nbrs_x", comm );
+	gc->nbrs_cp = (rvec*) 
+	  scalloc( g->max_nbrs, sizeof(rvec), "g:nbrs_cp", comm );
+	for( l = 0; l < g->max_nbrs; ++l )
+	  gc->nbrs[l] = NULL;
+      }
+    }
+  }
+
+  /* allocate atom id storage in gcells */
+  g->max_atoms = Estimate_GCell_Population( system, comm );
+  /* space for storing atom id's is required only for native cells */
+  for( i = g->native_str[0]; i < g->native_end[0]; ++i )
+    for( j = g->native_str[1]; j < g->native_end[1]; ++j )  
+      for( k = g->native_str[2]; k < g->native_end[2]; ++k )
+	g->cells[i][j][k].atoms = (int*) scalloc( g->max_atoms, sizeof(int), 
+						  "g:atoms", comm );
+#if defined(DEBUG_FOCUS)
+  fprintf( stderr, "p%d-allocated %dx%dx%d grid: nbrs=%d atoms=%d space=%dMB\n",
+	   system->my_rank, g->ncells[0], g->ncells[1], g->ncells[2],
+	   g->max_nbrs, g->max_atoms,
+	   (int)
+	   ((g->total*sizeof(grid_cell)+g->total*g->max_nbrs*sizeof(int*) +
+	     g->total*g->max_nbrs*sizeof(rvec) + 
+	     (g->native_end[0]-g->native_str[0])*
+	     (g->native_end[1]-g->native_str[1])*
+	     (g->native_end[2]-g->native_str[2])*g->max_atoms*sizeof(int))/
+	    (1024*1024)) );
+#endif
+}
+
+
+void Deallocate_Grid( grid *g )
+{
+  int i, j, k;
+  grid_cell *gc;
+
+  sfree( g->order, "g:order" );
+
+  /* deallocate the grid cells */
+  for( i = 0; i < g->ncells[0]; i++ ) {
+    for( j = 0; j < g->ncells[1]; j++ ) {
+      for( k = 0; k < g->ncells[2]; k++ ) {
+	gc = &(g->cells[i][j][k]);
+	sfree( gc->nbrs, "g:nbrs" );
+	sfree( gc->nbrs_x, "g:nbrs_x" );
+	sfree( gc->nbrs_cp, "g:nbrs_cp" );
+	if(gc->atoms != NULL )
+	  sfree( gc->atoms, "g:atoms" );
+      }
+      sfree( g->cells[i][j], "g:cells[i][j]" );
+    }
+    sfree( g->cells[i], "g:cells[i]" );
+  }
+  sfree( g->cells, "g:cells" );
+}
+
+
+/************ mpi buffers ********************/
+ /* make the allocations based on the largest need by the three comms:
+    1- transfer an atom who has moved into other proc's domain (mpi_atom)
+    2- exchange boundary atoms (boundary_atom)
+    3- update position info for boundary atoms (mpi_rvec)
+    
+    the largest space by far is required for the 2nd comm operation above.
+    buffers are void*, type cast to the correct pointer type to access 
+    the allocated buffers */
+int  Allocate_MPI_Buffers( mpi_datatypes *mpi_data, int est_recv, 
+			   neighbor_proc *my_nbrs, char *msg )
+{
+  int i;
+  mpi_out_data  *mpi_buf;
+  MPI_Comm comm;
+
+  comm = mpi_data->world;
+
+  /* in buffers */
+  mpi_data->in1_buffer = (void*) 
+    scalloc( est_recv, sizeof(boundary_atom), "in1_buffer", comm );
+  mpi_data->in2_buffer = (void*) 
+    scalloc( est_recv, sizeof(boundary_atom), "in2_buffer", comm );
+  
+  /* out buffers */
+  for( i = 0; i < MAX_NBRS; ++i ) {
+    mpi_buf = &( mpi_data->out_buffers[i] );
+    /* allocate storage for the neighbor processor i */
+    mpi_buf->index = (int*) 
+      scalloc( my_nbrs[i].est_send, sizeof(int), "mpibuf:index", comm );
+    mpi_buf->out_atoms = (void*) 
+      scalloc( my_nbrs[i].est_send, sizeof(boundary_atom), "mpibuf:out_atoms", 
+	       comm );
+  }
+  
+  return SUCCESS;
+}
+
+
+void Deallocate_MPI_Buffers( mpi_datatypes *mpi_data )
+{
+  int i;
+  mpi_out_data  *mpi_buf;
+
+  sfree( mpi_data->in1_buffer, "in1_buffer" );
+  sfree( mpi_data->in2_buffer, "in2_buffer" );
+
+  for( i = 0; i < MAX_NBRS; ++i ) {
+    mpi_buf = &( mpi_data->out_buffers[i] );
+    sfree( mpi_buf->index, "mpibuf:index" );
+    sfree( mpi_buf->out_atoms, "mpibuf:out_atoms" );
+  }
+}
+
+
+void ReAllocate( reax_system *system, control_params *control, 
+		 simulation_data *data, storage *workspace, reax_list **lists, 
+		 mpi_datatypes *mpi_data )
+{
+  int i, j, k, p;
+  int num_bonds, est_3body, nflag, Nflag, Hflag, mpi_flag, ret, total_send;
+  int renbr;
+  reallocate_data *realloc;
+  reax_list *far_nbrs;
+  sparse_matrix *H;
+  grid *g;
+  neighbor_proc *nbr_pr;
+  mpi_out_data *nbr_data;
+  MPI_Comm comm;
+  char msg[200];
+
+  realloc = &(workspace->realloc);
+  g = &(system->my_grid);
+  comm = mpi_data->world;
+
+#if defined(DEBUG)
+  fprintf( stderr, "p%d@reallocate: n: %d, N: %d, numH: %d\n",
+	   system->my_rank, system->n, system->N, system->numH );
+  fprintf( stderr, "p%d@reallocate: local_cap: %d, total_cap: %d, Hcap: %d\n",
+	   system->my_rank, system->local_cap, system->total_cap, 
+	   system->Hcap);
+  fprintf( stderr, "p%d: realloc.num_far: %d\n", 
+	   system->my_rank, realloc->num_far );
+  fprintf( stderr, "p%d: realloc.H: %d, realloc.Htop: %d\n", 
+	   system->my_rank, realloc->H, realloc->Htop );
+  fprintf( stderr, "p%d: realloc.Hbonds: %d, realloc.num_hbonds: %d\n", 
+	   system->my_rank, realloc->hbonds, realloc->num_hbonds );
+  fprintf( stderr, "p%d: realloc.bonds: %d, num_bonds: %d\n", 
+	   system->my_rank, realloc->bonds, realloc->num_bonds );
+  fprintf( stderr, "p%d: realloc.num_3body: %d\n", 
+	   system->my_rank, realloc->num_3body );
+#endif
+  
+  // IMPORTANT: LOOSE ZONES CHECKS ARE DISABLED FOR NOW BY &&'ing with 0!!!
+  nflag = 0;
+  if( system->n >= DANGER_ZONE * system->local_cap ||
+      (0 && system->n <= LOOSE_ZONE * system->local_cap) ) {
+    nflag = 1;
+    system->local_cap = (int)(system->n * SAFE_ZONE);
+  }
+
+  Nflag = 0;
+  if( system->N >= DANGER_ZONE * system->total_cap ||
+      (0 && system->N <= LOOSE_ZONE * system->total_cap) ) {
+    Nflag = 1;
+    system->total_cap = (int)(system->N * SAFE_ZONE);
+  }
+
+  if( Nflag ) {
+    /* system */
+#if defined(DEBUG_FOCUS)
+    fprintf( stderr, "p%d: reallocating system and workspace -"\
+	     "n=%d  N=%d  local_cap=%d  total_cap=%d\n",
+	     system->my_rank, system->n, system->N, 
+	     system->local_cap, system->total_cap );
+#endif
+    ret = Allocate_System( system, system->local_cap, system->total_cap, msg );
+    if( ret != SUCCESS ) {
+      fprintf( stderr, "not enough space for atom_list: total_cap=%d",
+	       system->total_cap );
+      fprintf( stderr, "terminating...\n" );
+      MPI_Abort( comm, INSUFFICIENT_MEMORY );
+    }
+    
+    /* workspace */
+    DeAllocate_Workspace( control, workspace );
+    ret = Allocate_Workspace( system, control, workspace, system->local_cap, 
+			      system->total_cap, comm, msg );
+    if( ret != SUCCESS ) {
+      fprintf( stderr, "no space for workspace: local_cap=%d total_cap=%d",
+	       system->local_cap, system->total_cap );
+      fprintf( stderr, "terminating...\n" );
+      MPI_Abort( comm, INSUFFICIENT_MEMORY );
+    }
+  }
+
+
+  renbr = (data->step - data->prev_steps) % control->reneighbor == 0;
+  /* far neighbors */
+  if( renbr ) {
+    far_nbrs = *lists + FAR_NBRS;
+
+    if( Nflag || realloc->num_far >= far_nbrs->num_intrs * DANGER_ZONE ) {
+      if( realloc->num_far > far_nbrs->num_intrs ) {
+	fprintf( stderr, "step%d-ran out of space on far_nbrs: top=%d, max=%d",
+		 data->step, realloc->num_far, far_nbrs->num_intrs );
+	MPI_Abort( comm, INSUFFICIENT_MEMORY );
+      }
+#if defined(DEBUG_FOCUS)
+      fprintf( stderr, "p%d: reallocating far_nbrs: num_fars=%d, space=%dMB\n", 
+	       system->my_rank, (int)(realloc->num_far*SAFE_ZONE), 
+	       (int)(realloc->num_far*SAFE_ZONE*sizeof(far_neighbor_data)/
+		     (1024*1024)) );
+#endif      
+      Reallocate_Neighbor_List( far_nbrs, system->total_cap, 
+				(int)(realloc->num_far*SAFE_ZONE), 
+				comm );
+      realloc->num_far = 0;
+    }
+  }
+
+#if defined(PURE_REAX)
+  /* qeq coef matrix */
+  H = workspace->H;
+  if( nflag || realloc->Htop >= H->m * DANGER_ZONE ) {
+    if( realloc->Htop > H->m ) {
+      fprintf( stderr, 
+	       "step%d - ran out of space on H matrix: Htop=%d, max = %d",
+	       data->step, realloc->Htop, H->m );
+      MPI_Abort( comm, INSUFFICIENT_MEMORY );
+    }
+#if defined(DEBUG_FOCUS)
+    fprintf( stderr, "p%d: reallocating H matrix: Htop=%d, space=%dMB\n", 
+	     system->my_rank, (int)(realloc->Htop*SAFE_ZONE), 
+	     (int)(realloc->Htop * SAFE_ZONE * sizeof(sparse_matrix_entry) / 
+		   (1024*1024)) );
+#endif
+    Reallocate_Matrix( &(workspace->H), system->local_cap, 
+		       realloc->Htop*SAFE_ZONE, "H", comm );
+    //Deallocate_Matrix( workspace->L );
+    //Deallocate_Matrix( workspace->U );
+    workspace->L = NULL;
+    workspace->U = NULL;
+    realloc->Htop = 0;
+  }
+#endif /*PURE_REAX*/
+
+  /* hydrogen bonds list */
+  if( control->hbond_cut > 0 ) { 
+    Hflag = 0;
+    if( system->numH >= DANGER_ZONE * system->Hcap || 
+	(0 && system->numH <= LOOSE_ZONE * system->Hcap) ) {
+      Hflag = 1;
+      system->Hcap = (int)(system->numH * SAFE_ZONE);
+    }
+
+    if( Hflag || realloc->hbonds ) {
+      ret = Reallocate_HBonds_List( system, (*lists)+HBONDS, comm );
+      realloc->hbonds = 0;
+#if defined(DEBUG_FOCUS)
+      fprintf(stderr, "p%d: reallocating hbonds: total_hbonds=%d space=%dMB\n",
+	      system->my_rank, ret, (int)(ret*sizeof(hbond_data)/(1024*1024)));
+#endif
+    }
+  }
+
+  /* bonds list */
+  num_bonds = est_3body = -1;
+  if( Nflag || realloc->bonds ){
+    Reallocate_Bonds_List( system, (*lists)+BONDS, &num_bonds, 
+			   &est_3body, comm );
+    realloc->bonds = 0;
+    realloc->num_3body = MAX( realloc->num_3body, est_3body );
+#if defined(DEBUG_FOCUS)
+    fprintf( stderr, "p%d: reallocating bonds: total_bonds=%d, space=%dMB\n", 
+	     system->my_rank, num_bonds, 
+	     (int)(num_bonds*sizeof(bond_data)/(1024*1024)) );
+#endif
+  }
+
+  /* 3-body list */
+  if( realloc->num_3body > 0 ) {
+#if defined(DEBUG_FOCUS)
+    fprintf( stderr, "p%d: reallocating 3body list: num_3body=%d, space=%dMB\n",
+	     system->my_rank, realloc->num_3body, 
+	     (int)(realloc->num_3body * sizeof(three_body_interaction_data) / 
+		   (1024*1024)) );
+#endif
+    Delete_List( (*lists)+THREE_BODIES, comm );
+    
+    if( num_bonds == -1 )
+      num_bonds = ((*lists)+BONDS)->num_intrs;
+
+    realloc->num_3body = (int)(MAX(realloc->num_3body*SAFE_ZONE, MIN_3BODIES));
+
+    if( !Make_List( num_bonds, realloc->num_3body, TYP_THREE_BODY, 
+		    (*lists)+THREE_BODIES, comm ) ) {
+      fprintf( stderr, "Problem in initializing angles list. Terminating!\n" );
+      MPI_Abort( comm, CANNOT_INITIALIZE );
+    }
+    realloc->num_3body = -1;
+  }
+
+#if defined(PURE_REAX)
+  /* grid */
+  if( renbr && realloc->gcell_atoms > -1 ) {
+#if defined(DEBUG_FOCUS)
+    fprintf(stderr, "reallocating gcell: g->max_atoms: %d\n", g->max_atoms);
+#endif
+    for( i = g->native_str[0]; i < g->native_end[0]; i++ )
+      for( j = g->native_str[1]; j < g->native_end[1]; j++ )
+	for( k = g->native_str[2]; k < g->native_end[2]; k++ ) {
+	  // reallocate g->atoms
+	  sfree( g->cells[i][j][k].atoms, "g:atoms" );  
+	  g->cells[i][j][k].atoms = (int*) 
+	    scalloc( realloc->gcell_atoms, sizeof(int), "g:atoms", comm);
+	}
+    realloc->gcell_atoms = -1;
+  }
+
+  /* mpi buffers */
+  // we have to be at a renbring step - 
+  // to ensure correct values at mpi_buffers for update_boundary_positions
+  if( !renbr )
+    mpi_flag = 0;
+  // check whether in_buffer capacity is enough
+  else if( system->max_recved >= system->est_recv * 0.90 ) 
+    mpi_flag = 1;
+  else {
+    // otherwise check individual outgoing buffers
+    mpi_flag = 0;
+    for( p = 0; p < MAX_NBRS; ++p ) {
+      nbr_pr   = &( system->my_nbrs[p] );
+      nbr_data = &( mpi_data->out_buffers[p] );
+      if( nbr_data->cnt >= nbr_pr->est_send * 0.90 ) {
+	mpi_flag = 1;
+	break;
+      }
+    }
+  }
+
+  if( mpi_flag ) {
+#if defined(DEBUG_FOCUS)
+    fprintf( stderr, "p%d: reallocating mpi_buf: old_recv=%d\n",
+	     system->my_rank, system->est_recv );
+    for( p = 0; p < MAX_NBRS; ++p ) 
+      fprintf( stderr, "p%d: nbr%d old_send=%d\n", 
+	       system->my_rank, p, system->my_nbrs[p].est_send );
+#endif
+    /* update mpi buffer estimates based on last comm */
+    system->est_recv = MAX( system->max_recved*SAFER_ZONE, MIN_SEND );
+    system->est_trans = 
+      (system->est_recv * sizeof(boundary_atom)) / sizeof(mpi_atom);
+    total_send = 0;
+    for( p = 0; p < MAX_NBRS; ++p ) {
+      nbr_pr   = &( system->my_nbrs[p] );
+      nbr_data = &( mpi_data->out_buffers[p] );
+      nbr_pr->est_send = MAX( nbr_data->cnt*SAFER_ZONE, MIN_SEND );
+      total_send += nbr_pr->est_send;
+    }
+#if defined(DEBUG_FOCUS)
+    fprintf( stderr, "p%d: reallocating mpi_buf: recv=%d send=%d total=%dMB\n",
+	     system->my_rank, system->est_recv, total_send,
+	     (int)((system->est_recv+total_send)*sizeof(boundary_atom)/
+		   (1024*1024)));
+    for( p = 0; p < MAX_NBRS; ++p ) 
+      fprintf( stderr, "p%d: nbr%d new_send=%d\n", 
+	       system->my_rank, p, system->my_nbrs[p].est_send );
+#endif
+
+    /* reallocate mpi buffers */
+    Deallocate_MPI_Buffers( mpi_data );
+    ret = Allocate_MPI_Buffers( mpi_data, system->est_recv, 
+				system->my_nbrs, msg );
+    if( ret != SUCCESS ) {
+      fprintf( stderr, "%s", msg );
+      fprintf( stderr, "terminating...\n" );
+      MPI_Abort( comm, INSUFFICIENT_MEMORY );
+    }
+  }
+#endif /*PURE_REAX*/
+
+#if defined(DEBUG_FOCUS) 
+  fprintf( stderr, "p%d @ step%d: reallocate done\n", 
+	   system->my_rank, data->step );
+  MPI_Barrier( comm );
+#endif
+}
diff --git a/src/USER-REAXC/reaxc_allocate.h b/src/USER-REAXC/reaxc_allocate.h
new file mode 100644
index 0000000000..04e24c67ec
--- /dev/null
+++ b/src/USER-REAXC/reaxc_allocate.h
@@ -0,0 +1,49 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#ifndef __ALLOCATE_H_
+#define __ALLOCATE_H_
+
+#include "reaxc_types.h"
+int PreAllocate_Space( reax_system*, control_params*, storage*, MPI_Comm );
+
+void reax_atom_Copy( reax_atom*, reax_atom* );
+int  Allocate_System( reax_system*, int, int, char* );
+void DeAllocate_System( reax_system* );
+
+int  Allocate_Workspace( reax_system*, control_params*, storage*, 
+			 int, int, MPI_Comm, char* );
+void DeAllocate_Workspace( control_params*, storage* );
+
+void Allocate_Grid( reax_system*, MPI_Comm );
+void Deallocate_Grid( grid* );
+
+int  Allocate_MPI_Buffers( mpi_datatypes*, int, neighbor_proc*, char* );
+
+int  Allocate_Matrix( sparse_matrix**, int, int, MPI_Comm );
+
+int  Allocate_HBond_List( int, int, int*, int*, reax_list* );
+
+int  Allocate_Bond_List( int, int*, reax_list* );
+
+void ReAllocate( reax_system*, control_params*, simulation_data*, storage*, 
+		 reax_list**, mpi_datatypes* );
+#endif
diff --git a/src/USER-REAXC/reaxc_basic_comm.cpp b/src/USER-REAXC/reaxc_basic_comm.cpp
new file mode 100644
index 0000000000..16a46a03d8
--- /dev/null
+++ b/src/USER-REAXC/reaxc_basic_comm.cpp
@@ -0,0 +1,312 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#include "reaxc_types.h"
+#if defined(PURE_REAX)
+#include "basic_comm.h"
+#include "vector.h"
+#elif defined(LAMMPS_REAX)
+#include "reaxc_basic_comm.h"
+#include "reaxc_vector.h"
+#endif
+
+#if defined(PURE_REAX)
+void real_packer( void *dummy, mpi_out_data *out_buf )
+{
+  int i;
+  real *buf = (real*) dummy;
+  real *out = (real*) out_buf->out_atoms;
+
+  for( i = 0; i < out_buf->cnt; ++i )
+    out[i] = buf[ out_buf->index[i] ];
+}
+
+
+void rvec_packer( void *dummy, mpi_out_data *out_buf )
+{
+  int i;
+  rvec *buf = (rvec*) dummy;
+  rvec *out = (rvec*)out_buf->out_atoms;
+
+  for( i = 0; i < out_buf->cnt; ++i )
+    memcpy( out[i], buf[ out_buf->index[i] ], sizeof(rvec) );
+}
+
+
+void rvec2_packer( void *dummy, mpi_out_data *out_buf )
+{
+  int i;
+  rvec2 *buf = (rvec2*) dummy;
+  rvec2 *out = (rvec2*) out_buf->out_atoms;
+
+  for( i = 0; i < out_buf->cnt; ++i )
+    memcpy( out[i], buf[ out_buf->index[i] ], sizeof(rvec2) );
+}
+
+
+void Dist( reax_system* system, mpi_datatypes *mpi_data, 
+	   void *buf, MPI_Datatype type, int scale, dist_packer pack )
+{
+  int d;
+  mpi_out_data *out_bufs;
+  MPI_Comm comm;
+  MPI_Request req1, req2;
+  MPI_Status stat1, stat2;
+  neighbor_proc *nbr1, *nbr2;
+
+#if defined(DEBUG)
+  fprintf( stderr, "p%d dist: entered\n", system->my_rank );
+#endif
+  comm = mpi_data->comm_mesh3D;
+  out_bufs = mpi_data->out_buffers;
+
+  for( d = 0; d < 3; ++d ) {
+    /* initiate recvs */
+    nbr1 = &(system->my_nbrs[2*d]);
+    if( nbr1->atoms_cnt )
+      MPI_Irecv( buf + nbr1->atoms_str*scale, nbr1->atoms_cnt, type, 
+		 nbr1->rank, 2*d+1,comm, &req1 );
+    
+    nbr2 = &(system->my_nbrs[2*d+1]);
+    if( nbr2->atoms_cnt )
+      MPI_Irecv( buf + nbr2->atoms_str*scale, nbr2->atoms_cnt, type, 
+		 nbr2->rank, 2*d, comm, &req2 );
+
+    /* send both messages in dimension d */
+    if( out_bufs[2*d].cnt ) {
+      pack( buf, out_bufs + (2*d) );
+      MPI_Send( out_bufs[2*d].out_atoms, out_bufs[2*d].cnt, type, 
+		nbr1->rank, 2*d, comm );
+    }
+    
+    if( out_bufs[2*d+1].cnt ) {
+      pack( buf, out_bufs + (2*d+1) );
+      MPI_Send( out_bufs[2*d+1].out_atoms, out_bufs[2*d+1].cnt, type, 
+		nbr2->rank, 2*d+1, comm );
+    }
+    
+    if( nbr1->atoms_cnt ) MPI_Wait( &req1, &stat1 );
+    if( nbr2->atoms_cnt ) MPI_Wait( &req2, &stat2 );
+  }
+
+#if defined(DEBUG)
+  fprintf( stderr, "p%d dist: done\n", system->my_rank );
+#endif
+}
+
+
+void real_unpacker( void *dummy_in, void *dummy_buf, mpi_out_data *out_buf )
+{
+  int i;
+  real *in = (real*) dummy_in;
+  real *buf = (real*) dummy_buf;
+  
+  for( i = 0; i < out_buf->cnt; ++i )
+    buf[ out_buf->index[i] ] += in[i];
+}
+
+
+void rvec_unpacker( void *dummy_in, void *dummy_buf, mpi_out_data *out_buf )
+{
+  int i;
+  rvec *in = (rvec*) dummy_in;
+  rvec *buf = (rvec*) dummy_buf;
+
+  for( i = 0; i < out_buf->cnt; ++i ) {
+    rvec_Add( buf[ out_buf->index[i] ], in[i] );
+#if defined(DEBUG)
+    fprintf( stderr, "rvec_unpacker: cnt=%d  i =%d  index[i]=%d\n", 
+	     out_buf->cnt, i, out_buf->index[i] );
+#endif
+  }
+}
+
+
+void rvec2_unpacker( void *dummy_in, void *dummy_buf, mpi_out_data *out_buf )
+{
+  int i;
+  rvec2 *in = (rvec2*) dummy_in;
+  rvec2 *buf = (rvec2*) dummy_buf;
+
+  for( i = 0; i < out_buf->cnt; ++i ) {
+    buf[ out_buf->index[i] ][0] += in[i][0];
+    buf[ out_buf->index[i] ][1] += in[i][1];
+  }
+}
+
+
+void Coll( reax_system* system, mpi_datatypes *mpi_data, 
+	   void *buf, MPI_Datatype type, int scale, coll_unpacker unpack )
+{
+  int d;
+  void *in1, *in2;
+  mpi_out_data *out_bufs;
+  MPI_Comm comm;
+  MPI_Request req1, req2;
+  MPI_Status stat1, stat2;
+  neighbor_proc *nbr1, *nbr2;
+
+#if defined(DEBUG)
+  fprintf( stderr, "p%d coll: entered\n", system->my_rank );
+#endif
+  comm = mpi_data->comm_mesh3D;
+  in1 = mpi_data->in1_buffer;
+  in2 = mpi_data->in2_buffer;
+  out_bufs = mpi_data->out_buffers;
+
+  for( d = 2; d >= 0; --d ) {
+    /* initiate recvs */
+    nbr1 = &(system->my_nbrs[2*d]);
+    if( out_bufs[2*d].cnt )
+      MPI_Irecv(in1, out_bufs[2*d].cnt, type, nbr1->rank, 2*d+1, comm, &req1);
+
+    nbr2 = &(system->my_nbrs[2*d+1]);
+    if( out_bufs[2*d+1].cnt )
+      MPI_Irecv(in2, out_bufs[2*d+1].cnt, type, nbr2->rank, 2*d, comm, &req2);
+
+    /* send both messages in dimension d */
+    if( nbr1->atoms_cnt )
+      MPI_Send( buf + nbr1->atoms_str*scale, nbr1->atoms_cnt, type, 
+		nbr1->rank, 2*d, comm );
+    
+    if( nbr2->atoms_cnt )
+      MPI_Send( buf + nbr2->atoms_str*scale, nbr2->atoms_cnt, type, 
+		nbr2->rank, 2*d+1, comm );
+
+#if defined(DEBUG)
+    fprintf( stderr, "p%d coll[%d] nbr1: str=%d cnt=%d recv=%d\n", 
+	     system->my_rank, d, nbr1->atoms_str, nbr1->atoms_cnt, 
+	     out_bufs[2*d].cnt );
+    fprintf( stderr, "p%d coll[%d] nbr2: str=%d cnt=%d recv=%d\n", 
+	     system->my_rank, d, nbr2->atoms_str, nbr2->atoms_cnt, 
+	     out_bufs[2*d+1].cnt );
+#endif
+
+    if( out_bufs[2*d].cnt ) {
+      MPI_Wait( &req1, &stat1 );
+      unpack( in1, buf, out_bufs + (2*d) );
+    }
+    
+    if( out_bufs[2*d+1].cnt ) {
+      MPI_Wait( &req2, &stat2 );
+      unpack( in2, buf, out_bufs + (2*d+1) );
+    }
+  }
+
+#if defined(DEBUG)
+  fprintf( stderr, "p%d coll: done\n", system->my_rank );
+#endif
+}
+#endif /*PURE_REAX*/
+
+/*****************************************************************************/
+real Parallel_Norm( real *v, int n, MPI_Comm comm )
+{
+  int  i;
+  real my_sum, norm_sqr;
+
+  my_sum = 0;
+  for( i = 0; i < n; ++i )
+    my_sum += SQR( v[i] );
+
+  MPI_Allreduce( &my_sum, &norm_sqr, 1, MPI_DOUBLE, MPI_SUM, comm );
+
+  return sqrt( norm_sqr );
+}
+
+
+
+real Parallel_Dot( real *v1, real *v2, int n, MPI_Comm comm )
+{
+  int  i;
+  real my_dot, res;
+
+  my_dot = 0;
+  for( i = 0; i < n; ++i )
+    my_dot += v1[i] * v2[i];
+
+  MPI_Allreduce( &my_dot, &res, 1, MPI_DOUBLE, MPI_SUM, comm );
+
+  return res;
+}
+
+
+
+real Parallel_Vector_Acc( real *v, int n, MPI_Comm comm )
+{
+  int  i;
+  real my_acc, res;
+
+  my_acc = 0;
+  for( i = 0; i < n; ++i )
+    my_acc += v[i];
+
+  MPI_Allreduce( &my_acc, &res, 1, MPI_DOUBLE, MPI_SUM, comm );
+
+  return res;
+}
+
+
+/*****************************************************************************/
+#if defined(TEST_FORCES)
+void Coll_ids_at_Master( reax_system *system, storage *workspace, 
+			 mpi_datatypes *mpi_data )
+{
+  int i;
+  int *id_list;
+
+  MPI_Gather( &system->n, 1, MPI_INT, workspace->rcounts, 1, MPI_INT, 
+	      MASTER_NODE, mpi_data->world ); 
+
+  if( system->my_rank == MASTER_NODE ){
+    workspace->displs[0] = 0;
+    for( i = 1; i < system->wsize; ++i )
+      workspace->displs[i] = workspace->displs[i-1] + workspace->rcounts[i-1];
+  }
+
+  id_list = (int*) malloc( system->n * sizeof(int) );
+  for( i = 0; i < system->n; ++i )
+    id_list[i] = system->my_atoms[i].orig_id;
+  
+  MPI_Gatherv( id_list, system->n, MPI_INT, 
+	       workspace->id_all, workspace->rcounts, workspace->displs, 
+	       MPI_INT, MASTER_NODE, mpi_data->world );
+
+  free( id_list );
+
+#if defined(DEBUG)
+  if( system->my_rank == MASTER_NODE ) {
+    for( i = 0 ; i < system->bigN; ++i )
+      fprintf( stderr, "id_all[%d]: %d\n", i, workspace->id_all[i] );
+  }
+#endif
+}
+
+
+void Coll_rvecs_at_Master( reax_system *system, storage *workspace, 
+			   mpi_datatypes *mpi_data, rvec* v )
+{
+  MPI_Gatherv( v, system->n, mpi_data->mpi_rvec, 
+	       workspace->f_all, workspace->rcounts, workspace->displs, 
+	       mpi_data->mpi_rvec, MASTER_NODE, mpi_data->world );
+}
+
+#endif
diff --git a/src/USER-REAXC/reaxc_basic_comm.h b/src/USER-REAXC/reaxc_basic_comm.h
new file mode 100644
index 0000000000..986f95a175
--- /dev/null
+++ b/src/USER-REAXC/reaxc_basic_comm.h
@@ -0,0 +1,47 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#ifndef __BASIC_COMM_H_
+#define __BASIC_COMM_H_
+
+#include "reaxc_types.h"
+
+void real_packer( void*, mpi_out_data* );
+void rvec_packer( void*, mpi_out_data* );
+void rvec2_packer( void*, mpi_out_data* );
+void Dist(reax_system*, mpi_datatypes*, void*, MPI_Datatype, int, dist_packer);
+
+void real_unpacker( void*, void*, mpi_out_data* );
+void rvec_unpacker( void*, void*, mpi_out_data* );
+void rvec2_unpacker( void*, void*, mpi_out_data* );
+void Coll( reax_system*, mpi_datatypes*, void*, MPI_Datatype, 
+	   int, coll_unpacker );
+
+real Parallel_Norm( real*, int, MPI_Comm );
+real Parallel_Dot( real*, real*, int, MPI_Comm );
+real Parallel_Vector_Acc( real*, int, MPI_Comm );
+
+#if defined(TEST_FORCES)
+void Coll_ids_at_Master( reax_system*, storage*, mpi_datatypes* );
+void Coll_rvecs_at_Master( reax_system*, storage*, mpi_datatypes*, rvec* );
+#endif
+
+#endif
diff --git a/src/USER-REAXC/reaxc_bond_orders.cpp b/src/USER-REAXC/reaxc_bond_orders.cpp
new file mode 100644
index 0000000000..02cee90d16
--- /dev/null
+++ b/src/USER-REAXC/reaxc_bond_orders.cpp
@@ -0,0 +1,1219 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#include "reaxc_types.h"
+#if defined(PURE_REAX)
+#include "bond_orders.h"
+#include "list.h"
+#include "vector.h"
+#include "io_tools.h"
+#elif defined(LAMMPS_REAX)
+#include "reaxc_bond_orders.h"
+#include "reaxc_list.h"
+#include "reaxc_vector.h"
+#endif
+
+#ifdef TEST_FORCES
+void Get_dBO( reax_system *system, reax_list **lists, 
+	      int i, int pj, real C, rvec *v )
+{
+  reax_list *bonds = (*lists) + BONDS;
+  reax_list *dBOs = (*lists) + DBOS;
+  int start_pj, end_pj, k;
+  
+  pj = bonds->select.bond_list[pj].dbond_index;
+  start_pj = Start_Index(pj, dBOs);
+  end_pj = End_Index(pj, dBOs);
+
+  for( k = start_pj; k < end_pj; ++k )
+    rvec_Scale( v[dBOs->select.dbo_list[k].wrt], 
+		C, dBOs->select.dbo_list[k].dBO );  
+}
+
+
+void Get_dBOpinpi2( reax_system *system, reax_list **lists, 
+		    int i, int pj, real Cpi, real Cpi2, rvec *vpi, rvec *vpi2 )
+{
+  reax_list *bonds = (*lists) + BONDS;
+  reax_list *dBOs = (*lists) + DBOS;
+  dbond_data *dbo_k;
+  int start_pj, end_pj, k;
+
+  pj = bonds->select.bond_list[pj].dbond_index;
+  start_pj = Start_Index(pj, dBOs);
+  end_pj = End_Index(pj, dBOs);
+
+  for( k = start_pj; k < end_pj; ++k )
+    {
+      dbo_k = &(dBOs->select.dbo_list[k]);
+      rvec_Scale( vpi[dbo_k->wrt], Cpi, dbo_k->dBOpi );
+      rvec_Scale( vpi2[dbo_k->wrt], Cpi2, dbo_k->dBOpi2 );
+    }
+}
+
+
+void Add_dBO( reax_system *system, reax_list **lists, 
+	      int i, int pj, real C, rvec *v )
+{
+  reax_list *bonds = (*lists) + BONDS;
+  reax_list *dBOs = (*lists) + DBOS;
+  int start_pj, end_pj, k;
+
+  pj = bonds->select.bond_list[pj].dbond_index;
+  start_pj = Start_Index(pj, dBOs);
+  end_pj = End_Index(pj, dBOs);
+  //fprintf( stderr, "i=%d j=%d start=%d end=%d\n", i, pj, start_pj, end_pj );
+
+  for( k = start_pj; k < end_pj; ++k )
+    rvec_ScaledAdd( v[dBOs->select.dbo_list[k].wrt], 
+		    C, dBOs->select.dbo_list[k].dBO );
+
+}
+
+
+void Add_dBOpinpi2( reax_system *system, reax_list **lists, 
+		    int i, int pj, real Cpi, real Cpi2, rvec *vpi, rvec *vpi2 )
+{
+  reax_list *bonds = (*lists) + BONDS;
+  reax_list *dBOs = (*lists) + DBOS;
+  dbond_data *dbo_k;
+  int start_pj, end_pj, k;
+
+  pj = bonds->select.bond_list[pj].dbond_index;
+  start_pj = Start_Index(pj, dBOs);
+  end_pj = End_Index(pj, dBOs);
+
+  for( k = start_pj; k < end_pj; ++k )
+    {
+      dbo_k = &(dBOs->select.dbo_list[k]);
+      rvec_ScaledAdd( vpi[dbo_k->wrt], Cpi, dbo_k->dBOpi );
+      rvec_ScaledAdd( vpi2[dbo_k->wrt], Cpi2, dbo_k->dBOpi2 );
+    }
+}
+
+
+void Add_dBO_to_Forces( reax_system *system, reax_list **lists, 
+			int i, int pj, real C )
+{
+  reax_list *bonds = (*lists) + BONDS;
+  reax_list *dBOs = (*lists) + DBOS;
+  int start_pj, end_pj, k;
+
+  pj = bonds->select.bond_list[pj].dbond_index;
+  start_pj = Start_Index(pj, dBOs);
+  end_pj = End_Index(pj, dBOs);
+
+  for( k = start_pj; k < end_pj; ++k )
+    rvec_ScaledAdd( system->my_atoms[dBOs->select.dbo_list[k].wrt].f, 
+		    C, dBOs->select.dbo_list[k].dBO );
+}
+
+
+void Add_dBOpinpi2_to_Forces( reax_system *system, reax_list **lists, 
+			      int i, int pj, real Cpi, real Cpi2 )
+{
+  reax_list *bonds = (*lists) + BONDS;
+  reax_list *dBOs = (*lists) + DBOS;
+  dbond_data *dbo_k;
+  int start_pj, end_pj, k;
+
+  pj = bonds->select.bond_list[pj].dbond_index;
+  start_pj = Start_Index(pj, dBOs);
+  end_pj = End_Index(pj, dBOs);
+
+  for( k = start_pj; k < end_pj; ++k )
+    {
+      dbo_k = &(dBOs->select.dbo_list[k]);
+      rvec_ScaledAdd( system->my_atoms[dbo_k->wrt].f, Cpi, dbo_k->dBOpi );
+      rvec_ScaledAdd( system->my_atoms[dbo_k->wrt].f, Cpi2, dbo_k->dBOpi2 );
+    }
+}
+
+
+void Add_dDelta( reax_system *system, reax_list **lists, int i, real C, rvec *v )
+{
+  reax_list *dDeltas = &((*lists)[DDELTAS]);
+  int start = Start_Index(i, dDeltas);
+  int end = End_Index(i, dDeltas);
+  int k;
+
+  for( k = start; k < end; ++k )
+    rvec_ScaledAdd( v[dDeltas->select.dDelta_list[k].wrt], 
+		    C, dDeltas->select.dDelta_list[k].dVal );
+}
+
+
+void Add_dDelta_to_Forces( reax_system *system, reax_list **lists, 
+			   int i, real C )
+{
+  reax_list *dDeltas = &((*lists)[DDELTAS]);
+  int start = Start_Index(i, dDeltas);
+  int end = End_Index(i, dDeltas);
+  int k;
+
+  for( k = start; k < end; ++k )
+    rvec_ScaledAdd( system->my_atoms[dDeltas->select.dDelta_list[k].wrt].f, 
+		    C, dDeltas->select.dDelta_list[k].dVal );
+}
+
+
+
+void Calculate_dBO( int i, int pj, 
+		    storage *workspace, reax_list **lists, int *top )
+{
+  /* Initializations */
+  reax_list *bonds, *dBOs;
+  int j, k, l, start_i, end_i, end_j;
+  bond_data *nbr_l, *nbr_k;
+  bond_order_data *bo_ij;
+  dbond_data *top_dbo;
+  
+  //  rvec due_j[1000], due_i[1000];
+  //  rvec due_j_pi[1000], due_i_pi[1000];
+
+  //  memset(due_j, 0, sizeof(rvec)*1000 );
+  //  memset(due_i, 0, sizeof(rvec)*1000 );
+  //  memset(due_j_pi, 0, sizeof(rvec)*1000 );
+  //  memset(due_i_pi, 0, sizeof(rvec)*1000 );
+
+  bonds = *lists + BONDS;
+  dBOs  = *lists + DBOS;
+
+  start_i = Start_Index(i, bonds);
+  end_i = End_Index(i, bonds);
+
+  j = bonds->select.bond_list[pj].nbr;
+  l = Start_Index(j, bonds);
+  end_j = End_Index(j, bonds);
+
+  bo_ij = &(bonds->select.bond_list[pj].bo_data);
+  top_dbo = &(dBOs->select.dbo_list[ (*top) ]);
+
+  for( k = start_i; k < end_i; ++k ) {
+    nbr_k = &(bonds->select.bond_list[k]);
+
+    for( ; l < end_j && bonds->select.bond_list[l].nbr < nbr_k->nbr; ++l ) {
+      /* These are the neighbors of j which are not in the nbr_list of i
+	 Note that they might also include i! */
+      nbr_l = &(bonds->select.bond_list[l]);
+      top_dbo->wrt = nbr_l->nbr;
+   
+      //rvec_ScaledAdd( due_j[top_dbo->wrt], 
+      //                -bo_ij->BO * bo_ij->A2_ji, nbr_l->bo_data.dBOp ); 
+	
+      /*3rd, dBO*/
+      rvec_Scale( top_dbo->dBO, -bo_ij->C3dbo, nbr_l->bo_data.dBOp );
+      /*4th, dBOpi*/
+      rvec_Scale( top_dbo->dBOpi, -bo_ij->C4dbopi, nbr_l->bo_data.dBOp );
+      /*4th, dBOpp*/
+      rvec_Scale( top_dbo->dBOpi2, -bo_ij->C4dbopi2, nbr_l->bo_data.dBOp );
+	  
+      if( nbr_l->nbr == i ) {
+	/* do the adjustments on i */       
+	//rvec_ScaledAdd( due_i[i], bo_ij->A0_ij+bo_ij->BO*bo_ij->A1_ij,
+	//                bo_ij->dBOp );  /*1st, dBO*/
+	//rvec_ScaledAdd( due_i[i], bo_ij->BO * bo_ij->A2_ij, 
+	//                workspace->dDeltap_self[i] ); /*2nd, dBO*/
+ 
+	/*1st, dBO*/
+	rvec_ScaledAdd( top_dbo->dBO, bo_ij->C1dbo, bo_ij->dBOp );
+	/*2nd, dBO*/
+	rvec_ScaledAdd( top_dbo->dBO, 
+			bo_ij->C2dbo, workspace->dDeltap_self[i] );
+
+	/*1st, dBOpi*/
+	rvec_ScaledAdd(top_dbo->dBOpi,bo_ij->C1dbopi,bo_ij->dln_BOp_pi );
+	/*2nd, dBOpi*/
+	rvec_ScaledAdd( top_dbo->dBOpi, bo_ij->C2dbopi, bo_ij->dBOp );
+	/*3rd, dBOpi*/
+	rvec_ScaledAdd( top_dbo->dBOpi, 
+			bo_ij->C3dbopi, workspace->dDeltap_self[i] );
+	      
+	/*1st, dBO_p*/
+	rvec_ScaledAdd( top_dbo->dBOpi2, 
+			bo_ij->C1dbopi2, bo_ij->dln_BOp_pi2 );
+	/*2nd, dBO_p*/
+	rvec_ScaledAdd( top_dbo->dBOpi2, bo_ij->C2dbopi2, bo_ij->dBOp );
+	/*3rd, dBO_p*/
+	rvec_ScaledAdd( top_dbo->dBOpi2, 
+			bo_ij->C3dbopi2, workspace->dDeltap_self[i] );
+      }
+
+      //rvec_Add( workspace->dDelta[nbr_l->nbr], top_dbo->dBO );
+      ++(*top), ++top_dbo;
+    }
+	  
+    /* Now we are processing neighbor k of i. */ 
+    top_dbo->wrt = nbr_k->nbr;
+      
+    //2nd, dBO
+    //rvec_ScaledAdd( due_i[top_dbo->wrt], 
+    //                -bo_ij->BO * bo_ij->A2_ij, nbr_k->bo_data.dBOp );
+      
+    /*2nd, dBO*/
+    rvec_Scale( top_dbo->dBO, -bo_ij->C2dbo, nbr_k->bo_data.dBOp );
+    /*3rd, dBOpi*/
+    rvec_Scale( top_dbo->dBOpi, -bo_ij->C3dbopi, nbr_k->bo_data.dBOp );
+    /*3rd, dBOpp*/
+    rvec_Scale( top_dbo->dBOpi2, -bo_ij->C3dbopi2, nbr_k->bo_data.dBOp );
+	  
+    if( l < end_j && bonds->select.bond_list[l].nbr == nbr_k->nbr ) {
+      /* This is a common neighbor of i and j. */
+      nbr_l = &(bonds->select.bond_list[l]);
+
+      /*3rd, dBO*/
+      //rvec_ScaledAdd( due_j[top_dbo->wrt], 
+      //                -bo_ij->BO * bo_ij->A2_ji, nbr_l->bo_data.dBOp );
+	  
+      /*3rd, dBO*/
+      rvec_ScaledAdd( top_dbo->dBO, -bo_ij->C3dbo, nbr_l->bo_data.dBOp );
+      /*4th, dBOpi*/
+      rvec_ScaledAdd(top_dbo->dBOpi, -bo_ij->C4dbopi, nbr_l->bo_data.dBOp);
+      /*4th, dBOpp*/
+      rvec_ScaledAdd(top_dbo->dBOpi2,-bo_ij->C4dbopi2,nbr_l->bo_data.dBOp);
+      ++l;
+    }
+    else if( k == pj ) {  
+      /* This negihbor is j. */
+      //rvec_ScaledAdd( due_j[j], -(bo_ij->A0_ij+bo_ij->BO*bo_ij->A1_ij), 
+      //                bo_ij->dBOp );  /*1st, dBO*/
+      //rvec_ScaledAdd( due_j[j], bo_ij->BO * bo_ij->A2_ji, 
+      //                workspace->dDeltap_self[j] );  /*3rd, dBO*/
+	  
+      /*1st, dBO*/
+      rvec_ScaledAdd( top_dbo->dBO, -bo_ij->C1dbo, bo_ij->dBOp );
+      /*3rd, dBO*/
+      rvec_ScaledAdd(top_dbo->dBO,bo_ij->C3dbo,workspace->dDeltap_self[j]);
+
+      /*1st, dBOpi*/
+      rvec_ScaledAdd( top_dbo->dBOpi, -bo_ij->C1dbopi, bo_ij->dln_BOp_pi );
+      /*2nd, dBOpi*/
+      rvec_ScaledAdd( top_dbo->dBOpi, -bo_ij->C2dbopi, bo_ij->dBOp );
+      /*4th, dBOpi*/
+      rvec_ScaledAdd( top_dbo->dBOpi, 
+		      bo_ij->C4dbopi, workspace->dDeltap_self[j] );
+
+      /*1st, dBOpi2*/
+      rvec_ScaledAdd(top_dbo->dBOpi2,-bo_ij->C1dbopi2,bo_ij->dln_BOp_pi2);
+      /*2nd, dBOpi2*/
+      rvec_ScaledAdd(top_dbo->dBOpi2,-bo_ij->C2dbopi2,bo_ij->dBOp );
+      /*4th, dBOpi2*/
+      rvec_ScaledAdd(top_dbo->dBOpi2, bo_ij->C4dbopi2, 
+		     workspace->dDeltap_self[j] );
+    }
+
+    // rvec_Add( workspace->dDelta[nbr_k->nbr], top_dbo->dBO );
+    ++(*top), ++top_dbo;
+  }
+
+  for( ; l < end_j; ++l ) {
+    /* These are the remaining neighbors of j which are not in the
+       neighbor_list of i. Note that they might also include i!*/
+    nbr_l = &(bonds->select.bond_list[l]);
+    top_dbo->wrt = nbr_l->nbr;
+
+    // fprintf( stdout, "\tl: %d nbr:%d\n", l, nbr_l->nbr+1 );
+      
+    // rvec_ScaledAdd( due_j[top_dbo->wrt], 
+    //                 -bo_ij->BO * bo_ij->A2_ji, nbr_l->bo_data.dBOp ); 
+      
+    /*3rd, dBO*/
+    rvec_Scale( top_dbo->dBO, -bo_ij->C3dbo, nbr_l->bo_data.dBOp );
+    /*4th, dBOpi*/
+    rvec_Scale( top_dbo->dBOpi, -bo_ij->C4dbopi, nbr_l->bo_data.dBOp );
+    /*4th, dBOpp*/
+    rvec_Scale( top_dbo->dBOpi2, -bo_ij->C4dbopi2, nbr_l->bo_data.dBOp );
+
+    if( nbr_l->nbr == i )
+      {
+	/* do the adjustments on i */	
+	//rvec_ScaledAdd( due_i[i], bo_ij->A0_ij + bo_ij->BO * bo_ij->A1_ij,
+	//                bo_ij->dBOp );  /*1st, dBO*/
+	//rvec_ScaledAdd( due_i[i], bo_ij->BO * bo_ij->A2_ij, 
+	//                workspace->dDeltap_self[i] ); /*2nd, dBO*/
+	  
+	/*1st, dBO*/
+	rvec_ScaledAdd( top_dbo->dBO, bo_ij->C1dbo, bo_ij->dBOp );
+	/*2nd, dBO*/
+	rvec_ScaledAdd(top_dbo->dBO,bo_ij->C2dbo,workspace->dDeltap_self[i]);
+
+	/*1st, dBO_p*/
+	rvec_ScaledAdd( top_dbo->dBOpi, bo_ij->C1dbopi, bo_ij->dln_BOp_pi );
+	/*2nd, dBOpi*/
+	rvec_ScaledAdd( top_dbo->dBOpi, bo_ij->C2dbopi, bo_ij->dBOp );
+	/*3rd,dBOpi*/
+	rvec_ScaledAdd( top_dbo->dBOpi, 
+			bo_ij->C3dbopi, workspace->dDeltap_self[i] );
+
+	/*1st, dBO_p*/
+	rvec_ScaledAdd(top_dbo->dBOpi2, bo_ij->C1dbopi2, bo_ij->dln_BOp_pi2);
+	/*2nd, dBO_p*/
+	rvec_ScaledAdd(top_dbo->dBOpi2, bo_ij->C2dbopi2, bo_ij->dBOp);
+	/*3rd,dBO_p*/
+	rvec_ScaledAdd(top_dbo->dBOpi2, 
+		       bo_ij->C3dbopi2, workspace->dDeltap_self[i]);
+      }
+
+    // rvec_Add( workspace->dDelta[nbr_l->nbr], top_dbo->dBO );
+    ++(*top), ++top_dbo;
+  }
+
+  //  for( k = 0; k < 21; ++k ){
+  //  fprintf( stderr, "%d %d %d, due_i:[%g %g %g]\n", 
+  //           i+1, j+1, k+1, due_i[k][0], due_i[k][1], due_i[k][2] );
+  //  fprintf( stderr, "%d %d %d, due_j:[%g %g %g]\n", 
+  //           i+1, j+1, k+1, due_j[k][0], due_j[k][1], due_j[k][2] );
+}
+#endif
+
+
+
+void Add_dBond_to_Forces_NPT( int i, int pj, simulation_data *data, 
+			      storage *workspace, reax_list **lists )
+{
+  reax_list *bonds = (*lists) + BONDS;
+  bond_data *nbr_j, *nbr_k;
+  bond_order_data *bo_ij, *bo_ji; 
+  dbond_coefficients coef;
+  rvec temp, ext_press;
+  ivec rel_box;
+  int pk, k, j;
+  
+  /* Initializations */
+  nbr_j = &(bonds->select.bond_list[pj]);
+  j = nbr_j->nbr;
+  bo_ij = &(nbr_j->bo_data);
+  bo_ji = &(bonds->select.bond_list[ nbr_j->sym_index ].bo_data);
+
+  coef.C1dbo = bo_ij->C1dbo * (bo_ij->Cdbo + bo_ji->Cdbo);
+  coef.C2dbo = bo_ij->C2dbo * (bo_ij->Cdbo + bo_ji->Cdbo);
+  coef.C3dbo = bo_ij->C3dbo * (bo_ij->Cdbo + bo_ji->Cdbo);
+
+  coef.C1dbopi = bo_ij->C1dbopi * (bo_ij->Cdbopi + bo_ji->Cdbopi);
+  coef.C2dbopi = bo_ij->C2dbopi * (bo_ij->Cdbopi + bo_ji->Cdbopi);
+  coef.C3dbopi = bo_ij->C3dbopi * (bo_ij->Cdbopi + bo_ji->Cdbopi);
+  coef.C4dbopi = bo_ij->C4dbopi * (bo_ij->Cdbopi + bo_ji->Cdbopi);
+
+  coef.C1dbopi2 = bo_ij->C1dbopi2 * (bo_ij->Cdbopi2 + bo_ji->Cdbopi2);
+  coef.C2dbopi2 = bo_ij->C2dbopi2 * (bo_ij->Cdbopi2 + bo_ji->Cdbopi2);
+  coef.C3dbopi2 = bo_ij->C3dbopi2 * (bo_ij->Cdbopi2 + bo_ji->Cdbopi2);
+  coef.C4dbopi2 = bo_ij->C4dbopi2 * (bo_ij->Cdbopi2 + bo_ji->Cdbopi2);
+
+  coef.C1dDelta = bo_ij->C1dbo * (workspace->CdDelta[i]+workspace->CdDelta[j]);
+  coef.C2dDelta = bo_ij->C2dbo * (workspace->CdDelta[i]+workspace->CdDelta[j]);
+  coef.C3dDelta = bo_ij->C3dbo * (workspace->CdDelta[i]+workspace->CdDelta[j]);
+ 
+  
+  /************************************
+   * forces related to atom i          *
+   * first neighbors of atom i         *
+   ************************************/
+  for( pk = Start_Index(i, bonds); pk < End_Index(i, bonds); ++pk ) {
+    nbr_k = &(bonds->select.bond_list[pk]);
+    k = nbr_k->nbr;
+
+    rvec_Scale(temp, -coef.C2dbo, nbr_k->bo_data.dBOp);       /*2nd, dBO*/
+    rvec_ScaledAdd(temp, -coef.C2dDelta, nbr_k->bo_data.dBOp);/*dDelta*/
+    rvec_ScaledAdd(temp, -coef.C3dbopi, nbr_k->bo_data.dBOp); /*3rd, dBOpi*/
+    rvec_ScaledAdd(temp, -coef.C3dbopi2, nbr_k->bo_data.dBOp);/*3rd, dBOpi2*/
+
+    /* force */
+    rvec_Add( workspace->f[k], temp );
+    /* pressure */
+    rvec_iMultiply( ext_press, nbr_k->rel_box, temp );
+    rvec_Add( data->my_ext_press, ext_press );
+
+    /* if( !ivec_isZero( nbr_k->rel_box ) )
+       fprintf( stderr, "%3d %3d %3d: dvec[%10.6f %10.6f %10.6f]"
+       "ext[%3d %3d %3d] f[%10.6f %10.6f %10.6f]\n",
+       i+1, system->my_atoms[i].x[0], 
+       system->my_atoms[i].x[1], system->my_atoms[i].x[2], 
+       j+1, k+1, system->my_atoms[k].x[0], 
+       system->my_atoms[k].x[1], system->my_atoms[k].x[2],
+       nbr_k->dvec[0], nbr_k->dvec[1], nbr_k->dvec[2],
+       nbr_k->rel_box[0], nbr_k->rel_box[1], nbr_k->rel_box[2],
+       temp[0], temp[1], temp[2] ); */
+  }
+
+  /* then atom i itself  */
+  rvec_Scale( temp, coef.C1dbo, bo_ij->dBOp );                      /*1st,dBO*/
+  rvec_ScaledAdd( temp, coef.C2dbo, workspace->dDeltap_self[i] );   /*2nd,dBO*/
+  rvec_ScaledAdd( temp, coef.C1dDelta, bo_ij->dBOp );               /*1st,dBO*/
+  rvec_ScaledAdd( temp, coef.C2dDelta, workspace->dDeltap_self[i] );/*2nd,dBO*/
+  rvec_ScaledAdd( temp, coef.C1dbopi, bo_ij->dln_BOp_pi );        /*1st,dBOpi*/
+  rvec_ScaledAdd( temp, coef.C2dbopi, bo_ij->dBOp );              /*2nd,dBOpi*/
+  rvec_ScaledAdd( temp, coef.C3dbopi, workspace->dDeltap_self[i]);/*3rd,dBOpi*/
+	      
+  rvec_ScaledAdd( temp, coef.C1dbopi2, bo_ij->dln_BOp_pi2 );  /*1st,dBO_pi2*/
+  rvec_ScaledAdd( temp, coef.C2dbopi2, bo_ij->dBOp );         /*2nd,dBO_pi2*/
+  rvec_ScaledAdd( temp, coef.C3dbopi2, workspace->dDeltap_self[i] );/*3rd*/
+  
+  /* force */
+  rvec_Add( workspace->f[i], temp );
+  /* ext pressure due to i is dropped, counting force on j will be enough */
+
+
+  /******************************************************
+   * forces and pressure related to atom j               * 
+   * first neighbors of atom j                           *
+   ******************************************************/
+  for( pk = Start_Index(j, bonds); pk < End_Index(j, bonds); ++pk ) {
+    nbr_k = &(bonds->select.bond_list[pk]);
+    k = nbr_k->nbr;
+      
+    rvec_Scale( temp, -coef.C3dbo, nbr_k->bo_data.dBOp );      /*3rd,dBO*/
+    rvec_ScaledAdd( temp, -coef.C3dDelta, nbr_k->bo_data.dBOp);/*dDelta*/ 
+    rvec_ScaledAdd( temp, -coef.C4dbopi, nbr_k->bo_data.dBOp); /*4th,dBOpi*/
+    rvec_ScaledAdd( temp, -coef.C4dbopi2, nbr_k->bo_data.dBOp);/*4th,dBOpi2*/
+
+    /* force */
+    rvec_Add( workspace->f[k], temp );
+    /* pressure */
+    if( k != i ) {
+      ivec_Sum( rel_box, nbr_k->rel_box, nbr_j->rel_box ); //rel_box(k, i)
+      rvec_iMultiply( ext_press, rel_box, temp );
+      rvec_Add( data->my_ext_press, ext_press );
+	  
+      /* if( !ivec_isZero( rel_box ) )
+	 fprintf( stderr, "%3d %3d %3d: dvec[%10.6f %10.6f %10.6f]"
+	 "ext[%3d %3d %3d] f[%10.6f %10.6f %10.6f]\n",
+	 i+1, j+1, system->my_atoms[j].x[0], 
+	 system->my_atoms[j].x[1], system->my_atoms[j].x[2], 
+	 k+1, system->my_atoms[k].x[0], 
+	 system->my_atoms[k].x[1], system->my_atoms[k].x[2],
+	 nbr_k->dvec[0], nbr_k->dvec[1], nbr_k->dvec[2],
+	 rel_box[0], rel_box[1], rel_box[2],
+	 temp[0], temp[1], temp[2] ); */
+    }
+  }
+  
+  /* then atom j itself */
+  rvec_Scale( temp, -coef.C1dbo, bo_ij->dBOp );                    /*1st, dBO*/
+  rvec_ScaledAdd( temp, coef.C3dbo, workspace->dDeltap_self[j] );  /*2nd, dBO*/
+  rvec_ScaledAdd( temp, -coef.C1dDelta, bo_ij->dBOp );             /*1st, dBO*/
+  rvec_ScaledAdd( temp, coef.C3dDelta, workspace->dDeltap_self[j]);/*2nd, dBO*/
+  
+  rvec_ScaledAdd( temp, -coef.C1dbopi, bo_ij->dln_BOp_pi );       /*1st,dBOpi*/
+  rvec_ScaledAdd( temp, -coef.C2dbopi, bo_ij->dBOp );             /*2nd,dBOpi*/
+  rvec_ScaledAdd( temp, coef.C4dbopi, workspace->dDeltap_self[j]);/*3rd,dBOpi*/
+	      
+  rvec_ScaledAdd( temp, -coef.C1dbopi2, bo_ij->dln_BOp_pi2 );    /*1st,dBOpi2*/
+  rvec_ScaledAdd( temp, -coef.C2dbopi2, bo_ij->dBOp );           /*2nd,dBOpi2*/
+  rvec_ScaledAdd( temp,coef.C4dbopi2,workspace->dDeltap_self[j]);/*3rd,dBOpi2*/
+
+  /* force */
+  rvec_Add( workspace->f[j], temp );
+  /* pressure */
+  rvec_iMultiply( ext_press, nbr_j->rel_box, temp );
+  rvec_Add( data->my_ext_press, ext_press );
+
+  /* if( !ivec_isZero( nbr_j->rel_box ) )
+     fprintf( stderr, "%3d %3d %3d: dvec[%10.6f %10.6f %10.6f]" 
+     "ext[%3d %3d %3d] f[%10.6f %10.6f %10.6f]\n",
+     i+1, system->my_atoms[i].x[0], system->my_atoms[i].x[1], 
+     system->my_atoms[i].x[2], 
+     j+1,system->my_atoms[j].x[0], system->my_atoms[j].x[1], 
+     system->my_atoms[j].x[2],
+     j+1, nbr_j->dvec[0], nbr_j->dvec[1], nbr_j->dvec[2],
+     nbr_j->rel_box[0], nbr_j->rel_box[1], nbr_j->rel_box[2],
+     temp[0], temp[1], temp[2] ); */
+}
+
+
+
+void Add_dBond_to_Forces( int i, int pj, 
+			  storage *workspace, reax_list **lists )
+{
+  reax_list *bonds = (*lists) + BONDS;
+  bond_data *nbr_j, *nbr_k;
+  bond_order_data *bo_ij, *bo_ji; 
+  dbond_coefficients coef;
+  int pk, k, j;
+
+  /* Initializations */ 
+  nbr_j = &(bonds->select.bond_list[pj]);
+  j = nbr_j->nbr;
+  bo_ij = &(nbr_j->bo_data);
+  bo_ji = &(bonds->select.bond_list[ nbr_j->sym_index ].bo_data);
+
+  coef.C1dbo = bo_ij->C1dbo * (bo_ij->Cdbo + bo_ji->Cdbo);
+  coef.C2dbo = bo_ij->C2dbo * (bo_ij->Cdbo + bo_ji->Cdbo);
+  coef.C3dbo = bo_ij->C3dbo * (bo_ij->Cdbo + bo_ji->Cdbo);
+
+  coef.C1dbopi = bo_ij->C1dbopi * (bo_ij->Cdbopi + bo_ji->Cdbopi);
+  coef.C2dbopi = bo_ij->C2dbopi * (bo_ij->Cdbopi + bo_ji->Cdbopi);
+  coef.C3dbopi = bo_ij->C3dbopi * (bo_ij->Cdbopi + bo_ji->Cdbopi);
+  coef.C4dbopi = bo_ij->C4dbopi * (bo_ij->Cdbopi + bo_ji->Cdbopi);
+
+  coef.C1dbopi2 = bo_ij->C1dbopi2 * (bo_ij->Cdbopi2 + bo_ji->Cdbopi2);
+  coef.C2dbopi2 = bo_ij->C2dbopi2 * (bo_ij->Cdbopi2 + bo_ji->Cdbopi2);
+  coef.C3dbopi2 = bo_ij->C3dbopi2 * (bo_ij->Cdbopi2 + bo_ji->Cdbopi2);
+  coef.C4dbopi2 = bo_ij->C4dbopi2 * (bo_ij->Cdbopi2 + bo_ji->Cdbopi2);
+
+  coef.C1dDelta = bo_ij->C1dbo * (workspace->CdDelta[i]+workspace->CdDelta[j]);
+  coef.C2dDelta = bo_ij->C2dbo * (workspace->CdDelta[i]+workspace->CdDelta[j]);
+  coef.C3dDelta = bo_ij->C3dbo * (workspace->CdDelta[i]+workspace->CdDelta[j]);
+ 
+  for( pk = Start_Index(i, bonds); pk < End_Index(i, bonds); ++pk ) {
+    nbr_k = &(bonds->select.bond_list[pk]);
+    k = nbr_k->nbr;
+
+    /*2nd,dBO*/
+    rvec_ScaledAdd( workspace->f[k], -coef.C2dbo, nbr_k->bo_data.dBOp ); 
+    /*dDelta*/
+    rvec_ScaledAdd( workspace->f[k], -coef.C2dDelta, nbr_k->bo_data.dBOp );
+    /*3rd, dBOpi*/
+    rvec_ScaledAdd( workspace->f[k], -coef.C3dbopi, nbr_k->bo_data.dBOp );
+    /*3rd, dBOpi2*/
+    rvec_ScaledAdd( workspace->f[k], -coef.C3dbopi2, nbr_k->bo_data.dBOp );
+  }
+ 
+  /*1st, dBO*/
+  rvec_ScaledAdd( workspace->f[i], coef.C1dbo, bo_ij->dBOp );
+  /*2nd, dBO*/
+  rvec_ScaledAdd( workspace->f[i], coef.C2dbo, workspace->dDeltap_self[i] );
+
+  /*1st, dBO*/
+  rvec_ScaledAdd( workspace->f[i], coef.C1dDelta, bo_ij->dBOp );
+  /*2nd, dBO*/
+  rvec_ScaledAdd( workspace->f[i], coef.C2dDelta, workspace->dDeltap_self[i] );
+  
+  /*1st, dBOpi*/
+  rvec_ScaledAdd( workspace->f[i], coef.C1dbopi, bo_ij->dln_BOp_pi );
+  /*2nd, dBOpi*/
+  rvec_ScaledAdd( workspace->f[i], coef.C2dbopi, bo_ij->dBOp );
+  /*3rd, dBOpi*/
+  rvec_ScaledAdd( workspace->f[i], coef.C3dbopi, workspace->dDeltap_self[i] );
+	      
+  /*1st, dBO_pi2*/
+  rvec_ScaledAdd( workspace->f[i], coef.C1dbopi2, bo_ij->dln_BOp_pi2 );
+  /*2nd, dBO_pi2*/
+  rvec_ScaledAdd( workspace->f[i], coef.C2dbopi2, bo_ij->dBOp );
+  /*3rd, dBO_pi2*/
+  rvec_ScaledAdd( workspace->f[i], coef.C3dbopi2, workspace->dDeltap_self[i] );
+
+  
+  for( pk = Start_Index(j, bonds); pk < End_Index(j, bonds); ++pk ) {
+    nbr_k = &(bonds->select.bond_list[pk]);
+    k = nbr_k->nbr;
+      
+    /*3rd, dBO*/
+    rvec_ScaledAdd( workspace->f[k], -coef.C3dbo, nbr_k->bo_data.dBOp );
+    /*dDelta*/ 
+    rvec_ScaledAdd( workspace->f[k], -coef.C3dDelta, nbr_k->bo_data.dBOp );
+    /*4th, dBOpi*/
+    rvec_ScaledAdd( workspace->f[k], -coef.C4dbopi, nbr_k->bo_data.dBOp );
+    /*4th, dBOpi2*/
+    rvec_ScaledAdd( workspace->f[k], -coef.C4dbopi2, nbr_k->bo_data.dBOp );
+  }
+  
+  /*1st,dBO*/
+  rvec_ScaledAdd( workspace->f[j], -coef.C1dbo, bo_ij->dBOp );
+  /*2nd,dBO*/
+  rvec_ScaledAdd( workspace->f[j], coef.C3dbo, workspace->dDeltap_self[j] );
+
+  /*1st, dBO*/						      
+  rvec_ScaledAdd( workspace->f[j], -coef.C1dDelta, bo_ij->dBOp );
+  /*2nd, dBO*/
+  rvec_ScaledAdd( workspace->f[j], coef.C3dDelta, workspace->dDeltap_self[j] );
+  
+  /*1st, dBOpi*/
+  rvec_ScaledAdd( workspace->f[j], -coef.C1dbopi, bo_ij->dln_BOp_pi );
+  /*2nd, dBOpi*/
+  rvec_ScaledAdd( workspace->f[j], -coef.C2dbopi, bo_ij->dBOp );
+  /*3rd, dBOpi*/
+  rvec_ScaledAdd( workspace->f[j], coef.C4dbopi, workspace->dDeltap_self[j] );
+	      
+  /*1st, dBOpi2*/
+  rvec_ScaledAdd( workspace->f[j], -coef.C1dbopi2, bo_ij->dln_BOp_pi2 );
+  /*2nd, dBOpi2*/
+  rvec_ScaledAdd( workspace->f[j], -coef.C2dbopi2, bo_ij->dBOp );
+  /*3rd, dBOpi2*/
+  rvec_ScaledAdd( workspace->f[j], coef.C4dbopi2, workspace->dDeltap_self[j] );
+}
+
+
+int BOp( storage *workspace, reax_list *bonds, real bo_cut, 
+	 int i, int btop_i, far_neighbor_data *nbr_pj,
+	 single_body_parameters *sbp_i, single_body_parameters *sbp_j,
+	 two_body_parameters *twbp ) {
+  int j, btop_j;
+  real r2, C12, C34, C56;
+  real Cln_BOp_s, Cln_BOp_pi, Cln_BOp_pi2;
+  real BO, BO_s, BO_pi, BO_pi2;
+  bond_data *ibond, *jbond;
+  bond_order_data *bo_ij, *bo_ji;
+
+  j = nbr_pj->nbr;
+  r2 = SQR(nbr_pj->d);
+	
+  if( sbp_i->r_s > 0.0 && sbp_j->r_s > 0.0 ) {
+    C12 = twbp->p_bo1 * pow( nbr_pj->d / twbp->r_s, twbp->p_bo2 );
+    BO_s = (1.0 + bo_cut) * exp( C12 );
+  }
+  else BO_s = C12 = 0.0;
+  
+  if( sbp_i->r_pi > 0.0 && sbp_j->r_pi > 0.0 ) {
+    C34 = twbp->p_bo3 * pow( nbr_pj->d / twbp->r_p, twbp->p_bo4 );
+    BO_pi = exp( C34 );
+  }
+  else BO_pi = C34 = 0.0;
+  
+  if( sbp_i->r_pi_pi > 0.0 && sbp_j->r_pi_pi > 0.0 ) {
+    C56 = twbp->p_bo5 * pow( nbr_pj->d / twbp->r_pp, twbp->p_bo6 );	
+    BO_pi2= exp( C56 );
+  }
+  else BO_pi2 = C56 = 0.0;
+  
+  /* Initially BO values are the uncorrected ones, page 1 */
+  BO = BO_s + BO_pi + BO_pi2;
+  
+  if( BO >= bo_cut ) {
+    /****** bonds i-j and j-i ******/
+    ibond = &( bonds->select.bond_list[btop_i] );
+    btop_j = End_Index( j, bonds );
+    jbond = &(bonds->select.bond_list[btop_j]);
+	    
+    ibond->nbr = j;
+    jbond->nbr = i;
+    ibond->d = nbr_pj->d;
+    jbond->d = nbr_pj->d;
+    rvec_Copy( ibond->dvec, nbr_pj->dvec );
+    rvec_Scale( jbond->dvec, -1, nbr_pj->dvec );
+    ivec_Copy( ibond->rel_box, nbr_pj->rel_box );
+    ivec_Scale( jbond->rel_box, -1, nbr_pj->rel_box );
+    ibond->dbond_index = btop_i;
+    jbond->dbond_index = btop_i;
+    ibond->sym_index = btop_j;
+    jbond->sym_index = btop_i;
+    Set_End_Index( j, btop_j+1, bonds );
+	     	  
+    bo_ij = &( ibond->bo_data );
+    bo_ji = &( jbond->bo_data );
+    bo_ji->BO = bo_ij->BO = BO;
+    bo_ji->BO_s = bo_ij->BO_s = BO_s;
+    bo_ji->BO_pi = bo_ij->BO_pi = BO_pi;
+    bo_ji->BO_pi2 = bo_ij->BO_pi2 = BO_pi2;
+  
+    /* Bond Order page2-3, derivative of total bond order prime */
+    Cln_BOp_s = twbp->p_bo2 * C12 / r2;
+    Cln_BOp_pi = twbp->p_bo4 * C34 / r2;
+    Cln_BOp_pi2 = twbp->p_bo6 * C56 / r2;
+  
+    /* Only dln_BOp_xx wrt. dr_i is stored here, note that 
+       dln_BOp_xx/dr_i = -dln_BOp_xx/dr_j and all others are 0 */
+    rvec_Scale(bo_ij->dln_BOp_s,-bo_ij->BO_s*Cln_BOp_s,ibond->dvec);
+    rvec_Scale(bo_ij->dln_BOp_pi,-bo_ij->BO_pi*Cln_BOp_pi,ibond->dvec);
+    rvec_Scale(bo_ij->dln_BOp_pi2,
+	       -bo_ij->BO_pi2*Cln_BOp_pi2,ibond->dvec);
+    rvec_Scale(bo_ji->dln_BOp_s, -1., bo_ij->dln_BOp_s);
+    rvec_Scale(bo_ji->dln_BOp_pi, -1., bo_ij->dln_BOp_pi );
+    rvec_Scale(bo_ji->dln_BOp_pi2, -1., bo_ij->dln_BOp_pi2 );
+    
+    /* Only dBOp wrt. dr_i is stored here, note that 
+       dBOp/dr_i = -dBOp/dr_j and all others are 0 */
+    rvec_Scale( bo_ij->dBOp, 
+		-(bo_ij->BO_s * Cln_BOp_s + 
+		  bo_ij->BO_pi * Cln_BOp_pi + 
+		  bo_ij->BO_pi2 * Cln_BOp_pi2), ibond->dvec );
+    rvec_Scale( bo_ji->dBOp, -1., bo_ij->dBOp );
+    
+    rvec_Add( workspace->dDeltap_self[i], bo_ij->dBOp );
+    rvec_Add( workspace->dDeltap_self[j], bo_ji->dBOp );
+    
+    bo_ij->BO_s -= bo_cut;
+    bo_ij->BO -= bo_cut;
+    bo_ji->BO_s -= bo_cut;
+    bo_ji->BO -= bo_cut;
+    workspace->total_bond_order[i] += bo_ij->BO; //currently total_BOp
+    workspace->total_bond_order[j] += bo_ji->BO; //currently total_BOp
+    bo_ij->Cdbo = bo_ij->Cdbopi = bo_ij->Cdbopi2 = 0.0;
+    bo_ji->Cdbo = bo_ji->Cdbopi = bo_ji->Cdbopi2 = 0.0;
+    
+    /*fprintf( stderr, "%d %d %g %g %g\n",
+      i+1, j+1, bo_ij->BO, bo_ij->BO_pi, bo_ij->BO_pi2 );*/
+	    
+    /*fprintf( stderr, "Cln_BOp_s: %f, pbo2: %f, C12:%f\n", 
+      Cln_BOp_s, twbp->p_bo2, C12 );
+      fprintf( stderr, "Cln_BOp_pi: %f, pbo4: %f, C34:%f\n", 
+      Cln_BOp_pi, twbp->p_bo4, C34 );
+      fprintf( stderr, "Cln_BOp_pi2: %f, pbo6: %f, C56:%f\n",
+      Cln_BOp_pi2, twbp->p_bo6, C56 );*/
+    /*fprintf(stderr, "pbo1: %f, pbo2:%f\n", twbp->p_bo1, twbp->p_bo2);
+      fprintf(stderr, "pbo3: %f, pbo4:%f\n", twbp->p_bo3, twbp->p_bo4);
+      fprintf(stderr, "pbo5: %f, pbo6:%f\n", twbp->p_bo5, twbp->p_bo6);
+      fprintf( stderr, "r_s: %f, r_p: %f, r_pp: %f\n", 
+      twbp->r_s, twbp->r_p, twbp->r_pp );
+      fprintf( stderr, "C12: %g, C34:%g, C56:%g\n", C12, C34, C56 );*/
+    
+    /*fprintf( stderr, "\tfactors: %g %g %g\n",
+      -(bo_ij->BO_s * Cln_BOp_s + bo_ij->BO_pi * Cln_BOp_pi + 
+      bo_ij->BO_pi2 * Cln_BOp_pp),
+      -bo_ij->BO_pi * Cln_BOp_pi, -bo_ij->BO_pi2 * Cln_BOp_pi2 );*/
+    /*fprintf( stderr, "dBOpi:\t[%g, %g, %g]\n", 
+      bo_ij->dBOp[0], bo_ij->dBOp[1], bo_ij->dBOp[2] );
+      fprintf( stderr, "dBOpi:\t[%g, %g, %g]\n", 
+      bo_ij->dln_BOp_pi[0], bo_ij->dln_BOp_pi[1], 
+      bo_ij->dln_BOp_pi[2] );
+      fprintf( stderr, "dBOpi2:\t[%g, %g, %g]\n\n",
+      bo_ij->dln_BOp_pi2[0], bo_ij->dln_BOp_pi2[1], 
+      bo_ij->dln_BOp_pi2[2] );*/
+
+    return 1;
+  }
+  
+  return 0;
+}
+  
+
+int compare_bonds( const void *p1, const void *p2 )
+{
+  return ((bond_data *)p1)->nbr - ((bond_data *)p2)->nbr;
+}
+
+  
+void BO( reax_system *system, control_params *control, simulation_data *data, 
+	 storage *workspace, reax_list **lists, output_controls *out_control )
+{
+  int i, j, pj, type_i, type_j;
+  int start_i, end_i, sym_index, num_bonds;
+  real val_i, Deltap_i, Deltap_boc_i;
+  real val_j, Deltap_j, Deltap_boc_j;
+  real f1, f2, f3, f4, f5, f4f5, exp_f4, exp_f5;
+  real exp_p1i,	exp_p2i, exp_p1j, exp_p2j;
+  real temp, u1_ij, u1_ji, Cf1A_ij, Cf1B_ij, Cf1_ij, Cf1_ji;
+  real Cf45_ij, Cf45_ji, p_lp1; //u_ij, u_ji
+  real A0_ij, A1_ij, A2_ij, A2_ji, A3_ij, A3_ji;
+  real explp1, p_boc1, p_boc2;
+  single_body_parameters *sbp_i, *sbp_j;
+  two_body_parameters *twbp;
+  bond_order_data *bo_ij, *bo_ji;
+  reax_list *bonds = (*lists) + BONDS;
+#ifdef TEST_FORCES
+  int  k, pk, start_j, end_j;
+  int  top_dbo, top_dDelta;
+  dbond_data *pdbo;
+  dDelta_data *ptop_dDelta;
+  reax_list *dDeltas, *dBOs;
+  top_dbo=0;
+  top_dDelta=0;
+  dDeltas = (*lists) + DDELTAS;
+  dBOs = (*lists) + DBOS;
+
+  //for( i = 0; i < system->N; ++i )
+  //  qsort( &(bonds->select.bond_list[Start_Index(i, bonds)]), 
+  //   Num_Entries(i, bonds), sizeof(bond_data), compare_bonds );
+#endif
+
+  num_bonds = 0;
+  p_boc1 = system->reax_param.gp.l[0];
+  p_boc2 = system->reax_param.gp.l[1];
+
+ /* Calculate Deltaprime, Deltaprime_boc values */
+  for( i = 0; i < system->N; ++i ) {
+    type_i = system->my_atoms[i].type;
+    sbp_i = &(system->reax_param.sbp[type_i]);
+    workspace->Deltap[i] = workspace->total_bond_order[i] - sbp_i->valency;
+    workspace->Deltap_boc[i] = 
+      workspace->total_bond_order[i] - sbp_i->valency_val;
+    
+    //fprintf( stdout, "%d(%d) %24.15f\n", 
+    //     i, workspace->bond_mark[i], workspace->total_bond_order[i] );
+    workspace->total_bond_order[i] = 0;
+  }
+  // fprintf( stderr, "done with uncorrected bond orders\n" );
+
+  /* Corrected Bond Order calculations */
+  for( i = 0; i < system->N; ++i ) {
+    type_i = system->my_atoms[i].type;
+    sbp_i = &(system->reax_param.sbp[type_i]);
+    val_i = sbp_i->valency;
+    Deltap_i = workspace->Deltap[i];
+    Deltap_boc_i = workspace->Deltap_boc[i];
+    start_i = Start_Index(i, bonds);
+    end_i = End_Index(i, bonds);
+    // fprintf( stderr, "i:%d Dp:%g Dbocp:%g s:%d e:%d\n",
+    //       i+1, Deltap_i, Deltap_boc_i, start_i, end_i );
+
+    for( pj = start_i; pj < end_i; ++pj ) {
+      j = bonds->select.bond_list[pj].nbr;
+      type_j = system->my_atoms[j].type;
+      bo_ij = &( bonds->select.bond_list[pj].bo_data );
+      // fprintf( stderr, "\tj:%d - ubo: %8.3f\n", j+1, bo_ij->BO );
+
+      if( i < j || workspace->bond_mark[j] > 3 ) {
+	twbp = &( system->reax_param.tbp[type_i][type_j] );
+#ifdef TEST_FORCES
+	Set_Start_Index( pj, top_dbo, dBOs );
+	/* fprintf( stderr, "%6d%6d%12.6f%12.6f%12.6f\n", 
+	   workspace->reverse_map[i], workspace->reverse_map[j],
+	   twbp->ovc, twbp->v13cor, bo_ij->BO ); */
+#endif
+
+	if( twbp->ovc < 0.001 && twbp->v13cor < 0.001 ) {
+	  /* There is no correction to bond orders nor to derivatives
+	     of bond order prime! So we leave bond orders unchanged and
+	     set derivative of bond order coefficients such that 
+	     dBO = dBOp & dBOxx = dBOxxp in Add_dBO_to_Forces */
+	  bo_ij->C1dbo = 1.000000;
+	  bo_ij->C2dbo = 0.000000;
+	  bo_ij->C3dbo = 0.000000; 
+
+	  bo_ij->C1dbopi = bo_ij->BO_pi;
+	  bo_ij->C2dbopi = 0.000000;
+	  bo_ij->C3dbopi = 0.000000;
+	  bo_ij->C4dbopi = 0.000000;
+
+	  bo_ij->C1dbopi2 = bo_ij->BO_pi2; 
+	  bo_ij->C2dbopi2 = 0.000000;
+	  bo_ij->C3dbopi2 = 0.000000;
+	  bo_ij->C4dbopi2 = 0.000000;
+
+#ifdef TEST_FORCES
+	  pdbo = &(dBOs->select.dbo_list[ top_dbo ]);
+		  
+	  // compute dBO_ij/dr_i
+	  pdbo->wrt = i;
+	  rvec_Copy( pdbo->dBO, bo_ij->dBOp );
+	  rvec_Scale( pdbo->dBOpi, bo_ij->BO_pi, bo_ij->dln_BOp_pi );
+	  rvec_Scale( pdbo->dBOpi2, bo_ij->BO_pi2, bo_ij->dln_BOp_pi2);
+
+	  // compute dBO_ij/dr_j
+	  pdbo++;
+	  pdbo->wrt = j;
+	  rvec_Scale( pdbo->dBO, -1.0, bo_ij->dBOp );
+	  rvec_Scale( pdbo->dBOpi, -bo_ij->BO_pi, bo_ij->dln_BOp_pi );
+	  rvec_Scale(pdbo->dBOpi2, -bo_ij->BO_pi2, bo_ij->dln_BOp_pi2);
+
+	  top_dbo += 2;
+#endif
+	}
+	else {
+	  val_j = system->reax_param.sbp[type_j].valency;
+	  Deltap_j = workspace->Deltap[j];
+	  Deltap_boc_j = workspace->Deltap_boc[j];
+	    
+	  /* on page 1 */
+	  if( twbp->ovc >= 0.001 ) {
+	    /* Correction for overcoordination */		
+	    exp_p1i = exp( -p_boc1 * Deltap_i );
+	    exp_p2i = exp( -p_boc2 * Deltap_i );
+	    exp_p1j = exp( -p_boc1 * Deltap_j );
+	    exp_p2j = exp( -p_boc2 * Deltap_j );
+		  
+	    f2 = exp_p1i + exp_p1j;			
+	    f3 = -1.0 / p_boc2 * log( 0.5 * ( exp_p2i  + exp_p2j ) );
+	    f1 = 0.5 * ( ( val_i + f2 )/( val_i + f2 + f3 ) + 
+			 ( val_j + f2 )/( val_j + f2 + f3 ) );
+		  
+	    /*fprintf( stderr,"%d %d\t%g %g   j:%g %g  p_boc:%g %g\n"
+	      "\tf:%g  %g  %g, exp:%g %g %g %g\n", 
+	      i+1, j+1, 
+	      val_i, Deltap_i, val_j, Deltap_j, p_boc1, p_boc2,
+	      f1, f2, f3, exp_p1i, exp_p2i, exp_p1j, exp_p2j );*/
+
+	    /* Now come the derivates */		
+	    /* Bond Order pages 5-7, derivative of f1 */
+	    temp = f2 + f3;
+	    u1_ij = val_i + temp;
+	    u1_ji = val_j + temp;
+	    Cf1A_ij = 0.5 * f3 * (1.0 / SQR( u1_ij ) + 
+				  1.0 / SQR( u1_ji ));
+	    Cf1B_ij = -0.5 * (( u1_ij - f3 ) / SQR( u1_ij ) + 
+			      ( u1_ji - f3 ) / SQR( u1_ji ));
+		    
+	    //Cf1_ij = -Cf1A_ij * p_boc1 * exp_p1i + 
+	    //          Cf1B_ij * exp_p2i / ( exp_p2i + exp_p2j );
+	    Cf1_ij = 0.50 * ( -p_boc1 * exp_p1i / u1_ij - 
+			      ((val_i+f2) / SQR(u1_ij)) * 
+			      ( -p_boc1 * exp_p1i +  
+				exp_p2i / ( exp_p2i + exp_p2j ) ) + 
+			      -p_boc1 * exp_p1i / u1_ji - 
+			      ((val_j+f2) / SQR(u1_ji)) * 
+			      ( -p_boc1 * exp_p1i +  
+				exp_p2i / ( exp_p2i + exp_p2j ) ));
+	       
+				      
+	    Cf1_ji = -Cf1A_ij * p_boc1 * exp_p1j + 
+	      Cf1B_ij * exp_p2j / ( exp_p2i + exp_p2j ); 
+
+	    //fprintf( stderr, "\tCf1:%g  %g\n", Cf1_ij, Cf1_ji );
+	  }
+	  else {
+	    /* No overcoordination correction! */
+	    f1 = 1.0;
+	    Cf1_ij = Cf1_ji = 0.0;		  
+	  }
+
+	  if( twbp->v13cor >= 0.001 ) {
+	    /* Correction for 1-3 bond orders */
+	    exp_f4 =exp(-(twbp->p_boc4 * SQR( bo_ij->BO ) -
+			  Deltap_boc_i) * twbp->p_boc3 + twbp->p_boc5);
+	    exp_f5 =exp(-(twbp->p_boc4 * SQR( bo_ij->BO ) -
+			  Deltap_boc_j) * twbp->p_boc3 + twbp->p_boc5);
+
+	    f4 = 1. / (1. + exp_f4);
+	    f5 = 1. / (1. + exp_f5);
+	    f4f5 = f4 * f5;
+	
+	    /* Bond Order pages 8-9, derivative of f4 and f5 */
+	    /*temp = twbp->p_boc5 - 
+	      twbp->p_boc3 * twbp->p_boc4 * SQR( bo_ij->BO );
+	      u_ij = temp + twbp->p_boc3 * Deltap_boc_i;
+	      u_ji = temp + twbp->p_boc3 * Deltap_boc_j;
+	      Cf45_ij = Cf45( u_ij, u_ji ) / f4f5;
+	      Cf45_ji = Cf45( u_ji, u_ij ) / f4f5;*/
+	    Cf45_ij = -f4 * exp_f4;
+	    Cf45_ji = -f5 * exp_f5;
+	  }
+	  else {
+	    f4 = f5 = f4f5 = 1.0;
+	    Cf45_ij = Cf45_ji = 0.0;
+	  }
+     		  
+	  /* Bond Order page 10, derivative of total bond order */
+	  A0_ij = f1 * f4f5;
+	  A1_ij = -2 * twbp->p_boc3 * twbp->p_boc4 * bo_ij->BO * 
+	    (Cf45_ij + Cf45_ji);
+	  A2_ij = Cf1_ij / f1 + twbp->p_boc3 * Cf45_ij;
+	  A2_ji = Cf1_ji / f1 + twbp->p_boc3 * Cf45_ji;
+	  A3_ij = A2_ij + Cf1_ij / f1;
+	  A3_ji = A2_ji + Cf1_ji / f1;
+      
+	  /*fprintf( stderr, "\tBO: %f, A0: %f, A1: %f" 
+	    "A2_ij: %f A2_ji: %f, A3_ij: %f, A3_ji: %f\n",
+	    bo_ij->BO, 
+	    A0_ij, A1_ij, A2_ij, A2_ji, A3_ij, A3_ji );*/
+	
+
+	  /* find corrected bond orders and their derivative coef */
+	  bo_ij->BO    = bo_ij->BO    * A0_ij;
+	  bo_ij->BO_pi = bo_ij->BO_pi * A0_ij *f1;
+	  bo_ij->BO_pi2= bo_ij->BO_pi2* A0_ij *f1;
+	  bo_ij->BO_s  = bo_ij->BO - ( bo_ij->BO_pi + bo_ij->BO_pi2 );
+
+	  bo_ij->C1dbo = A0_ij + bo_ij->BO * A1_ij;
+	  bo_ij->C2dbo = bo_ij->BO * A2_ij;
+	  bo_ij->C3dbo = bo_ij->BO * A2_ji; 
+
+	  bo_ij->C1dbopi = f1*f1*f4*f5;
+	  bo_ij->C2dbopi = bo_ij->BO_pi * A1_ij;
+	  bo_ij->C3dbopi = bo_ij->BO_pi * A3_ij;
+	  bo_ij->C4dbopi = bo_ij->BO_pi * A3_ji;
+
+	  bo_ij->C1dbopi2 = f1*f1*f4*f5;
+	  bo_ij->C2dbopi2 = bo_ij->BO_pi2 * A1_ij;
+	  bo_ij->C3dbopi2 = bo_ij->BO_pi2 * A3_ij;
+	  bo_ij->C4dbopi2 = bo_ij->BO_pi2 * A3_ji;
+
+#ifdef TEST_FORCES
+	  Calculate_dBO( i, pj, workspace, lists, &top_dbo );
+#endif
+	}
+
+	/* neglect bonds that are < 1e-10 */
+	if( bo_ij->BO < 1e-10 )
+	  bo_ij->BO = 0.0;
+	if( bo_ij->BO_s < 1e-10 )
+	  bo_ij->BO_s = 0.0;
+	if( bo_ij->BO_pi < 1e-10 )
+	  bo_ij->BO_pi = 0.0;
+	if( bo_ij->BO_pi2 < 1e-10 )
+	  bo_ij->BO_pi2 = 0.0;
+
+	workspace->total_bond_order[i] += bo_ij->BO; //now keeps total_BO
+
+
+	/* fprintf( stderr, "%d %d\t%g %g %g %g\n"
+	   "Cdbo:\t%g %g %g\n"
+	   "Cdbopi:\t%g %g %g %g\n"
+	   "Cdbopi2:%g %g %g %g\n\n", 
+	   i+1, j+1, 
+	   bonds->select.bond_list[ pj ].d, 
+	   bo_ij->BO,bo_ij->BO_pi, bo_ij->BO_pi2, 
+	   bo_ij->C1dbo, bo_ij->C2dbo, bo_ij->C3dbo,
+	   bo_ij->C1dbopi, bo_ij->C2dbopi, 
+	   bo_ij->C3dbopi, bo_ij->C4dbopi,
+	   bo_ij->C1dbopi2,bo_ij->C2dbopi2, 
+	   bo_ij->C3dbopi2, bo_ij->C4dbopi2 ); */
+
+	/* fprintf( stderr, "%d %d  BO:%f BO_s:%f BO_pi:%f BO_pi2:%f\n",
+	   i+1,j+1,bo_ij->BO,bo_ij->BO_s,bo_ij->BO_pi,bo_ij->BO_pi2 );*/
+
+#ifdef TEST_FORCES
+	Set_End_Index( pj, top_dbo, dBOs );
+	Add_dBO( system, lists, i, pj, 1.0, workspace->dDelta );
+#endif
+      }
+      else {
+	/* We only need to update bond orders from bo_ji
+	   everything else is set in uncorrected_bo calculations */
+	sym_index = bonds->select.bond_list[pj].sym_index;
+	bo_ji = &(bonds->select.bond_list[ sym_index ].bo_data);
+	bo_ij->BO = bo_ji->BO;
+	bo_ij->BO_s = bo_ji->BO_s;
+	bo_ij->BO_pi = bo_ji->BO_pi;
+	bo_ij->BO_pi2 = bo_ji->BO_pi2;
+
+	workspace->total_bond_order[i] += bo_ij->BO;// now keeps total_BO
+#ifdef TEST_FORCES
+	Add_dBO( system, lists, j, sym_index, 1.0, workspace->dDelta );
+#endif
+      }	  
+    }
+
+#ifdef TEST_FORCES 
+    // fprintf( stderr, "dDelta computations\nj:" );
+    Set_Start_Index( i, top_dDelta, dDeltas );
+    ptop_dDelta = &( dDeltas->select.dDelta_list[top_dDelta] );
+
+    for( pj = start_i; pj < end_i; ++pj ) {
+      j = bonds->select.bond_list[pj].nbr;
+      // fprintf( stderr, "%d  ", j );
+
+      if( !rvec_isZero( workspace->dDelta[j] ) ) {
+	ptop_dDelta->wrt = j;
+	rvec_Copy( ptop_dDelta->dVal, workspace->dDelta[j] );
+	rvec_MakeZero( workspace->dDelta[j] );
+	++top_dDelta, ++ptop_dDelta;
+      }
+	  
+      start_j = Start_Index(j, bonds);
+      end_j = End_Index(j, bonds);     
+      for( pk = start_j; pk < end_j; ++pk ) {
+	k = bonds->select.bond_list[pk].nbr;    
+	if( !rvec_isZero( workspace->dDelta[k] ) ) {
+	  ptop_dDelta->wrt = k;
+	  rvec_Copy( ptop_dDelta->dVal, workspace->dDelta[k] );
+	  rvec_MakeZero( workspace->dDelta[k] );
+	  ++top_dDelta, ++ptop_dDelta;
+	}
+      }
+    }
+
+    Set_End_Index( i, top_dDelta, dDeltas );
+
+    /*for(pj = Start_Index(i,dDeltas); pj < End_Index(i,dDeltas); ++pj)
+      fprintf( stdout, "dDel: %d %d [%g %g %g]\n",
+      i+1, dDeltas->select.dDelta_list[pj].wrt+1,
+      dDeltas->select.dDelta_list[pj].dVal[0], 
+      dDeltas->select.dDelta_list[pj].dVal[1], 
+      dDeltas->select.dDelta_list[pj].dVal[2] );*/
+#endif
+  }
+
+  /* fprintf( stderr, "\tCalculated actual bond orders ...\n" );
+     fprintf( stderr, "j\tDelta\tDelta_e\tDelta_boc\tnlp"
+     "\tDelta_lp\tClp\tdDelta_lp\n" );
+     fprintf( stderr, "Atom\tDelta\t\tDelta_e\t\tDelta_boc\tnlp"
+     "\t\tnlp_opt\t\tDelta_lp\tClp\t\tdDelta_lp\n" );*/
+
+  p_lp1 = system->reax_param.gp.l[15];
+  /* Calculate some helper variables that are  used at many places
+     throughout force calculations */
+  for( j = 0; j < system->N; ++j ){
+    type_j = system->my_atoms[j].type;
+    sbp_j = &(system->reax_param.sbp[ type_j ]);
+    
+    workspace->Delta[j] = workspace->total_bond_order[j] - sbp_j->valency;
+    workspace->Delta_e[j] = workspace->total_bond_order[j] - sbp_j->valency_e;
+    workspace->Delta_boc[j] = workspace->total_bond_order[j] -
+      sbp_j->valency_boc;
+
+    workspace->vlpex[j] = workspace->Delta_e[j] - 
+      2.0 * (int)(workspace->Delta_e[j]/2.0);    
+    explp1 = exp(-p_lp1 * SQR(2.0 + workspace->vlpex[j]));
+    workspace->nlp[j] = explp1 - (int)(workspace->Delta_e[j] / 2.0);
+    workspace->Delta_lp[j] = sbp_j->nlp_opt - workspace->nlp[j];
+    workspace->Clp[j] = 2.0 * p_lp1 * explp1 * (2.0 + workspace->vlpex[j]);
+    /* Adri uses different dDelta_lp values than the ones in notes... */
+    workspace->dDelta_lp[j] = workspace->Clp[j];
+    //workspace->dDelta_lp[j] = workspace->Clp[j] + (0.5-workspace->Clp[j]) *
+    //((fabs(workspace->Delta_e[j]/2.0 -
+    //       (int)(workspace->Delta_e[j]/2.0)) < 0.1) ? 1 : 0 );
+
+    if( sbp_j->mass > 21.0 ) {
+      workspace->nlp_temp[j] = 0.5 * (sbp_j->valency_e - sbp_j->valency);
+      workspace->Delta_lp_temp[j] = sbp_j->nlp_opt - workspace->nlp_temp[j];
+      workspace->dDelta_lp_temp[j] = 0.;
+    }
+    else {
+      workspace->nlp_temp[j] = workspace->nlp[j];
+      workspace->Delta_lp_temp[j] = sbp_j->nlp_opt - workspace->nlp_temp[j];
+      workspace->dDelta_lp_temp[j] = workspace->Clp[j];
+    }
+
+    //fprintf( stderr, "%d\t%lf\t%lf\t%lf\t%lf\t%lf\t%lf\t%lf\t%lf\n",
+    //j, workspace->Delta[j], workspace->Delta_e[j], workspace->Delta_boc[j],
+    //workspace->nlp[j], system->reaxprm.sbp[type_j].nlp_opt,
+    //workspace->Delta_lp[j], workspace->Clp[j], workspace->dDelta_lp[j] );
+
+    //fprintf( stdout, "%d(%d) %24.15f\n", 
+    //     j, workspace->bond_mark[j], workspace->total_bond_order[j] );
+  }
+
+  //Print_Bonds( system, bonds, "pbonds.out" );
+
+#if defined(TEST_ENERGIES) || defined(TEST_FORCES)
+  fprintf( stderr, "Number of bonds: %d\n", num_bonds );
+  Print_Bond_List( system, control, data, lists, out_control);
+#endif
+}
+
+
+#if defined(DEPRECATED)
+/* Locate j on i's list.
+   This function assumes that j is there for sure!
+   And this is the case given our method of neighbor generation*/
+int Locate_Symmetric_Bond( reax_list *bonds, int i, int j )
+{
+  int start = Start_Index(i, bonds);
+  int end = End_Index(i, bonds);
+  int mid = (start + end) / 2;
+  int mid_nbr;
+
+  while( (mid_nbr = bonds->select.bond_list[mid].nbr) != j ) {
+    /*fprintf( stderr, "\tstart: %d   end: %d   mid: %d\n", 
+      start, end, mid );*/
+    if( mid_nbr < j )
+      start = mid+1;
+    else end = mid - 1;
+      
+    mid = (start + end) / 2;
+  }
+  
+  return mid;
+}
+
+
+inline void Copy_Bond_Order_Data( bond_order_data *dest, bond_order_data *src )
+{
+  dest->BO = src->BO;
+  dest->BO_s = src->BO_s;
+  dest->BO_pi = src->BO_pi;
+  dest->BO_pi2 = src->BO_pi2;
+
+  rvec_Scale( dest->dBOp, -1.0, src->dBOp );
+  rvec_Scale( dest->dln_BOp_s, -1.0, src->dln_BOp_s );
+  rvec_Scale( dest->dln_BOp_pi, -1.0, src->dln_BOp_pi );
+  rvec_Scale( dest->dln_BOp_pi2, -1.0, src->dln_BOp_pi2 );
+}
+#endif
diff --git a/src/USER-REAXC/reaxc_bond_orders.h b/src/USER-REAXC/reaxc_bond_orders.h
new file mode 100644
index 0000000000..0ad8e3b836
--- /dev/null
+++ b/src/USER-REAXC/reaxc_bond_orders.h
@@ -0,0 +1,58 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#ifndef __BOND_ORDERS_H_
+#define __BOND_ORDERS_H_
+
+#include "reaxc_types.h"
+
+typedef struct{
+  real C1dbo, C2dbo, C3dbo;
+  real C1dbopi, C2dbopi, C3dbopi, C4dbopi;
+  real C1dbopi2, C2dbopi2, C3dbopi2, C4dbopi2;
+  real C1dDelta, C2dDelta, C3dDelta;
+}dbond_coefficients;
+
+#ifdef TEST_FORCES
+void Get_dBO( reax_system*, reax_list**, int, int, real, rvec* );
+void Get_dBOpinpi2( reax_system*, reax_list**, 
+		    int, int, real, real, rvec*, rvec* );
+
+void Add_dBO( reax_system*, reax_list**, int, int, real, rvec* );
+void Add_dBOpinpi2( reax_system*, reax_list**, 
+		    int, int, real, real, rvec*, rvec* );
+
+void Add_dBO_to_Forces( reax_system*, reax_list**, int, int, real );
+void Add_dBOpinpi2_to_Forces( reax_system*, reax_list**, 
+			      int, int, real, real );
+
+void Add_dDelta( reax_system*, reax_list**, int, real, rvec* );
+void Add_dDelta_to_Forces( reax_system *, reax_list**, int, real );
+#endif
+
+void Add_dBond_to_Forces( int, int, storage*, reax_list** );
+void Add_dBond_to_Forces_NPT( int, int, simulation_data*, 
+			      storage*, reax_list** );
+int BOp(storage*, reax_list*, real, int, int, far_neighbor_data*,
+	single_body_parameters*, single_body_parameters*, two_body_parameters*);
+void BO( reax_system*, control_params*, simulation_data*,
+	 storage*, reax_list**, output_controls* );
+#endif
diff --git a/src/USER-REAXC/reaxc_bonds.cpp b/src/USER-REAXC/reaxc_bonds.cpp
new file mode 100644
index 0000000000..70e0b644f2
--- /dev/null
+++ b/src/USER-REAXC/reaxc_bonds.cpp
@@ -0,0 +1,148 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#include "reaxc_types.h"
+#if defined(PURE_REAX)
+#include "bonds.h"
+#include "bond_orders.h"
+#include "list.h"
+#include "tool_box.h"
+#include "vector.h"
+#elif defined(LAMMPS_REAX)
+#include "reaxc_bonds.h"
+#include "reaxc_bond_orders.h"
+#include "reaxc_list.h"
+#include "reaxc_tool_box.h"
+#include "reaxc_vector.h"
+#endif
+
+
+void Bonds( reax_system *system, control_params *control, 
+	    simulation_data *data, storage *workspace, reax_list **lists, 
+	    output_controls *out_control )
+{
+  int i, j, pj, natoms;
+  int start_i, end_i;
+  int type_i, type_j;
+  real ebond, pow_BOs_be2, exp_be12, CEbo;
+  real gp3, gp4, gp7, gp10, gp37;
+  real exphu, exphua1, exphub1, exphuov, hulpov, estriph;
+  real decobdbo, decobdboua, decobdboub;
+  single_body_parameters *sbp_i, *sbp_j;
+  two_body_parameters *twbp;
+  bond_order_data *bo_ij;
+  reax_list *bonds;
+
+  bonds = (*lists) + BONDS;
+  gp3 = system->reax_param.gp.l[3];
+  gp4 = system->reax_param.gp.l[4];
+  gp7 = system->reax_param.gp.l[7];
+  gp10 = system->reax_param.gp.l[10];
+  gp37 = (int) system->reax_param.gp.l[37];
+  natoms = system->n;
+
+  for( i = 0; i < natoms; ++i ) {
+    start_i = Start_Index(i, bonds);
+    end_i = End_Index(i, bonds);
+
+    for( pj = start_i; pj < end_i; ++pj ) {
+      j = bonds->select.bond_list[pj].nbr;
+      
+      if( system->my_atoms[i].orig_id <= system->my_atoms[j].orig_id ) {
+	/* set the pointers */
+	type_i = system->my_atoms[i].type;
+	type_j = system->my_atoms[j].type;
+	sbp_i = &( system->reax_param.sbp[type_i] );
+	sbp_j = &( system->reax_param.sbp[type_j] );
+	twbp = &( system->reax_param.tbp[type_i][type_j] );
+	bo_ij = &( bonds->select.bond_list[pj].bo_data );
+	      
+	/* calculate the constants */
+	pow_BOs_be2 = pow( bo_ij->BO_s, twbp->p_be2 );
+	exp_be12 = exp( twbp->p_be1 * ( 1.0 - pow_BOs_be2 ) );
+	CEbo = -twbp->De_s * exp_be12 * 
+	  ( 1.0 - twbp->p_be1 * twbp->p_be2 * pow_BOs_be2 );
+	      
+	/* calculate the Bond Energy */
+	data->my_en.e_bond += ebond = 
+	  -twbp->De_s * bo_ij->BO_s * exp_be12 
+	  -twbp->De_p * bo_ij->BO_pi 
+	  -twbp->De_pp * bo_ij->BO_pi2;
+	      
+	/* calculate derivatives of Bond Orders */
+	bo_ij->Cdbo += CEbo;
+	bo_ij->Cdbopi -= (CEbo + twbp->De_p);
+	bo_ij->Cdbopi2 -= (CEbo + twbp->De_pp);
+	      
+#ifdef TEST_ENERGY
+	//fprintf( out_control->ebond, "%6d%6d%24.15e%24.15e%24.15e\n",
+	fprintf( out_control->ebond, "%6d%6d%12.4f%12.4f%12.4f\n",
+		 system->my_atoms[i].orig_id, 
+		 system->my_atoms[j].orig_id, 
+		 bo_ij->BO, ebond, data->my_en.e_bond );
+#endif
+#ifdef TEST_FORCES
+	Add_dBO( system, lists, i, pj, CEbo, workspace->f_be );
+	Add_dBOpinpi2( system, lists, i, pj, 
+		       -(CEbo + twbp->De_p), -(CEbo + twbp->De_pp), 
+		       workspace->f_be, workspace->f_be );
+#endif
+	/* Stabilisation terminal triple bond */
+	if( bo_ij->BO >= 1.00 ) {
+	  if( gp37 == 2 ||
+	      (sbp_i->mass == 12.0000 && sbp_j->mass == 15.9990) || 
+	      (sbp_j->mass == 12.0000 && sbp_i->mass == 15.9990) ) {
+	    exphu = exp( -gp7 * SQR(bo_ij->BO - 2.50) );
+	    exphua1 = exp(-gp3 * (workspace->total_bond_order[i]-bo_ij->BO));
+	    exphub1 = exp(-gp3 * (workspace->total_bond_order[j]-bo_ij->BO));
+	    exphuov = exp(gp4 * (workspace->Delta[i] + workspace->Delta[j]));
+	    hulpov = 1.0 / (1.0 + 25.0 * exphuov);
+	    
+	    estriph = gp10 * exphu * hulpov * (exphua1 + exphub1);
+	    data->my_en.e_bond += estriph;
+	    
+	    decobdbo = gp10 * exphu * hulpov * (exphua1 + exphub1) *
+	      ( gp3 - 2.0 * gp7 * (bo_ij->BO-2.50) );
+	    decobdboua = -gp10 * exphu * hulpov *
+	      (gp3*exphua1 + 25.0*gp4*exphuov*hulpov*(exphua1+exphub1));
+	    decobdboub = -gp10 * exphu * hulpov *
+	      (gp3*exphub1 + 25.0*gp4*exphuov*hulpov*(exphua1+exphub1));
+	    
+	    bo_ij->Cdbo += decobdbo;
+	    workspace->CdDelta[i] += decobdboua;
+	    workspace->CdDelta[j] += decobdboub;
+#ifdef TEST_ENERGY
+	    //fprintf( out_control->ebond, 
+	    //  "%6d%6d%24.15e%24.15e%24.15e%24.15e\n",
+	    //  system->my_atoms[i].orig_id, system->my_atoms[j].orig_id,
+	    //  estriph, decobdbo, decobdboua, decobdboub );
+#endif
+#ifdef TEST_FORCES
+	    Add_dBO( system, lists, i, pj, decobdbo, workspace->f_be );
+	    Add_dDelta( system, lists, i, decobdboua, workspace->f_be );
+	    Add_dDelta( system, lists, j, decobdboub, workspace->f_be );
+#endif
+	  }
+	}
+      }
+    }
+  }
+}
diff --git a/src/USER-REAXC/reaxc_bonds.h b/src/USER-REAXC/reaxc_bonds.h
new file mode 100644
index 0000000000..bf8c111775
--- /dev/null
+++ b/src/USER-REAXC/reaxc_bonds.h
@@ -0,0 +1,29 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#ifndef __BONDS_H_
+#define __BONDS_H_
+
+#include "reaxc_types.h"
+
+void Bonds( reax_system*, control_params*, simulation_data*, 
+	    storage*, reax_list**, output_controls* );
+#endif
diff --git a/src/USER-REAXC/reaxc_control.cpp b/src/USER-REAXC/reaxc_control.cpp
new file mode 100644
index 0000000000..7a72a1ee6f
--- /dev/null
+++ b/src/USER-REAXC/reaxc_control.cpp
@@ -0,0 +1,395 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#include "reaxc_types.h"
+#if defined(PURE_REAX)
+#include "control.h"
+#include "tool_box.h"
+#elif defined(LAMMPS_REAX)
+#include "reaxc_control.h"
+#include "reaxc_tool_box.h"
+#endif
+
+
+char Read_Control_File( char *control_file, control_params* control, 
+			output_controls *out_control )
+{
+  FILE *fp;
+  char *s, **tmp;
+  int   c,i,ival;
+  real  val;
+
+  /* open control file */
+  if ( (fp = fopen( control_file, "r" ) ) == NULL ) {
+    fprintf( stderr, "error opening the control file! terminating...\n" );
+    MPI_Abort( MPI_COMM_WORLD,  FILE_NOT_FOUND );
+  }
+
+  /* assign default values */
+  strcpy( control->sim_name, "simulate" );
+  control->ensemble        = NVE;
+  control->nsteps          = 0;
+  control->dt              = 0.25;
+  control->nprocs          = 1;
+  control->procs_by_dim[0] = 1;
+  control->procs_by_dim[1] = 1;
+  control->procs_by_dim[2] = 1;
+  control->geo_format = 1;
+
+  control->restart          = 0;
+  out_control->restart_format = WRITE_BINARY;
+  out_control->restart_freq = 0;
+  control->reposition_atoms = 0;
+  control->restrict_bonds   = 0;
+  control->remove_CoM_vel   = 25;
+  out_control->debug_level  = 0;
+  out_control->energy_update_freq = 0;
+
+  control->reneighbor = 1;
+  control->vlist_cut = control->nonb_cut;
+  control->bond_cut = 5.0;
+  control->bg_cut = 0.3;
+  control->thb_cut = 0.001;
+  control->hbond_cut = 0.0;
+
+  control->tabulate = 0;
+
+  control->qeq_freq = 1;
+  control->q_err = 1e-6;
+  control->refactor = 100;
+  control->droptol = 1e-2;;
+
+  control->T_init = 0.;
+  control->T_final = 300.;
+  control->Tau_T = 500.0;
+  control->T_mode = 0;
+  control->T_rate = 1.;
+  control->T_freq = 1.;
+
+  control->P[0] = control->P[1] = control->P[2] = 0.000101325;
+  control->Tau_P[0] = control->Tau_P[1] = control->Tau_P[2] = 500.0;
+  control->Tau_PT[0] = control->Tau_PT[1] = control->Tau_PT[2] = 500.0;
+  control->compressibility = 1.0;
+  control->press_mode = 0;
+  control->virial = 0;
+
+  out_control->write_steps = 0;
+  out_control->traj_compress = 0;
+  out_control->traj_method = REG_TRAJ;
+  strcpy( out_control->traj_title, "default_title" );
+  out_control->atom_info = 0;
+  out_control->bond_info = 0;
+  out_control->angle_info = 0;
+
+  control->molecular_analysis = 0;
+  control->dipole_anal = 0;
+  control->freq_dipole_anal = 0;
+  control->diffusion_coef = 0;
+  control->freq_diffusion_coef = 0;
+  control->restrict_type = 0;
+
+  /* memory allocations */
+  s = (char*) malloc(sizeof(char)*MAX_LINE);
+  tmp = (char**) malloc(sizeof(char*)*MAX_TOKENS);
+  for (i=0; i < MAX_TOKENS; i++)
+    tmp[i] = (char*) malloc(sizeof(char)*MAX_LINE);
+
+  /* read control parameters file */
+  while (!feof(fp)) {
+    fgets( s, MAX_LINE, fp );
+    c = Tokenize( s, &tmp );
+    //fprintf( stderr, "%s\n", s );
+
+    if( strcmp(tmp[0], "simulation_name") == 0 ) {
+      strcpy( control->sim_name, tmp[1] );
+    }
+    else if( strcmp(tmp[0], "ensemble_type") == 0 ) {
+      ival = atoi(tmp[1]);
+      control->ensemble = ival;
+      if( ival == iNPT || ival ==sNPT || ival == NPT )
+	control->virial = 1;
+    }
+    else if( strcmp(tmp[0], "nsteps") == 0 ) {
+      ival = atoi(tmp[1]);
+      control->nsteps = ival;
+    }
+    else if( strcmp(tmp[0], "dt") == 0) {
+      val = atof(tmp[1]);
+      control->dt = val * 1.e-3;  // convert dt from fs to ps!
+    }
+    else if( strcmp(tmp[0], "proc_by_dim") == 0 ) {
+      ival = atoi(tmp[1]);
+      control->procs_by_dim[0] = ival;
+      ival = atoi(tmp[2]);
+      control->procs_by_dim[1] = ival;
+      ival = atoi(tmp[3]);
+      control->procs_by_dim[2] = ival;
+
+      control->nprocs = control->procs_by_dim[0]*control->procs_by_dim[1]*
+	control->procs_by_dim[2];
+    }
+    //else if( strcmp(tmp[0], "restart") == 0 ) {
+    //  ival = atoi(tmp[1]);
+    //  control->restart = ival;
+    //}
+    //else if( strcmp(tmp[0], "restart_from") == 0 ) {
+    //  strcpy( control->restart_from, tmp[1] );
+    //}
+    else if( strcmp(tmp[0], "random_vel") == 0 ) {
+      ival = atoi(tmp[1]);
+      control->random_vel = ival;
+    }
+    else if( strcmp(tmp[0], "restart_format") == 0 ) {
+      ival = atoi(tmp[1]);
+      out_control->restart_format = ival;
+    }
+    else if( strcmp(tmp[0], "restart_freq") == 0 ) {
+      ival = atoi(tmp[1]);
+      out_control->restart_freq = ival;
+    }
+    else if( strcmp(tmp[0], "reposition_atoms") == 0 ) {
+      ival = atoi(tmp[1]);
+      control->reposition_atoms = ival;
+    }
+    else if( strcmp(tmp[0], "restrict_bonds") == 0 ) {
+      ival = atoi( tmp[1] );
+      control->restrict_bonds = ival;
+    }
+    else if( strcmp(tmp[0], "remove_CoM_vel") == 0 ) {
+      ival = atoi(tmp[1]);
+      control->remove_CoM_vel = ival;
+    }
+    else if( strcmp(tmp[0], "debug_level") == 0 ) {
+      ival = atoi(tmp[1]);
+      out_control->debug_level = ival;
+    }
+    else if( strcmp(tmp[0], "energy_update_freq") == 0 ) {
+      ival = atoi(tmp[1]);
+      out_control->energy_update_freq = ival;
+    }
+    else if( strcmp(tmp[0], "reneighbor") == 0 ) {
+      ival = atoi( tmp[1] );
+      control->reneighbor = ival;
+    }
+    else if( strcmp(tmp[0], "vlist_buffer") == 0 ) {
+      val = atof(tmp[1]);
+      control->vlist_cut= val + control->nonb_cut;
+    }
+    else if( strcmp(tmp[0], "nbrhood_cutoff") == 0 ) {
+      val = atof(tmp[1]);
+      control->bond_cut = val;
+    }
+    else if( strcmp(tmp[0], "bond_graph_cutoff") == 0 ) { 
+      val = atof(tmp[1]);
+      control->bg_cut = val;
+    }
+    else if( strcmp(tmp[0], "thb_cutoff") == 0 ) { 
+      val = atof(tmp[1]);
+      control->thb_cut = val;
+    }
+    else if( strcmp(tmp[0], "hbond_cutoff") == 0 ) {
+      val = atof( tmp[1] );
+      control->hbond_cut = val;
+    }
+    else if( strcmp(tmp[0], "ghost_cutoff") == 0 ) {
+      val = atof(tmp[1]);
+      control->user_ghost_cut = val;
+    }
+    else if( strcmp(tmp[0], "tabulate_long_range") == 0 ) {
+      ival = atoi( tmp[1] );
+      control->tabulate = ival;
+    }
+    else if( strcmp(tmp[0], "qeq_freq") == 0 ) {
+      ival = atoi( tmp[1] );
+      control->qeq_freq = ival;
+    }
+    else if( strcmp(tmp[0], "q_err") == 0 ) {
+      val = atof( tmp[1] );
+      control->q_err = val;
+    }
+    else if( strcmp(tmp[0], "ilu_refactor") == 0 ) {
+      ival = atoi( tmp[1] );
+      control->refactor = ival;
+    }
+    else if( strcmp(tmp[0], "ilu_droptol") == 0 ) {
+      val = atof( tmp[1] );
+      control->droptol = val;
+    }
+    else if( strcmp(tmp[0], "temp_init") == 0 ) {
+      val = atof(tmp[1]);
+      control->T_init = val;
+	
+      if( control->T_init < 0.1 )
+	control->T_init = 0.1;
+    }
+    else if( strcmp(tmp[0], "temp_final") == 0 ) {
+      val = atof(tmp[1]);
+      control->T_final = val;
+	
+      if( control->T_final < 0.1 )
+	control->T_final = 0.1;
+    }
+    else if( strcmp(tmp[0], "t_mass") == 0 ) {
+      val = atof(tmp[1]);
+      control->Tau_T = val * 1.e-3;    // convert t_mass from fs to ps
+    }
+    else if( strcmp(tmp[0], "t_mode") == 0 ) {
+      ival = atoi(tmp[1]);
+      control->T_mode = ival;
+    }
+    else if( strcmp(tmp[0], "t_rate") == 0 ) {
+      val = atof(tmp[1]);
+      control->T_rate = val;
+    }
+    else if( strcmp(tmp[0], "t_freq") == 0 ) {
+      val = atof(tmp[1]);
+      control->T_freq = val;
+    }
+    else if( strcmp(tmp[0], "pressure") == 0 ) {
+      if( control->ensemble == iNPT ) {
+	control->P[0] = control->P[1] = control->P[2] = atof(tmp[1]);
+      }
+      else if( control->ensemble == sNPT ) {
+	control->P[0] = atof(tmp[1]);
+	control->P[1] = atof(tmp[2]);
+	control->P[2] = atof(tmp[3]);
+      }
+    }
+    else if( strcmp(tmp[0], "p_mass") == 0 ) {
+      // convert p_mass from fs to ps
+      if( control->ensemble == iNPT ) {
+	control->Tau_P[0] = control->Tau_P[1] = control->Tau_P[2] = 
+	  atof(tmp[1]) * 1.e-3;
+      }
+      else if( control->ensemble == sNPT ) {
+	control->Tau_P[0] = atof(tmp[1]) * 1.e-3;
+	control->Tau_P[1] = atof(tmp[2]) * 1.e-3;
+	control->Tau_P[2] = atof(tmp[3]) * 1.e-3;
+      }
+    }
+    else if( strcmp(tmp[0], "pt_mass") == 0 ) {
+      val = atof(tmp[1]);
+      control->Tau_PT[0] = control->Tau_PT[1] = control->Tau_PT[2] = 
+	val * 1.e-3;  // convert pt_mass from fs to ps
+    }
+    else if( strcmp(tmp[0], "compress") == 0 ) {
+      val = atof(tmp[1]);
+      control->compressibility = val;
+    }
+    else if( strcmp(tmp[0], "press_mode") == 0 ) {
+      ival = atoi(tmp[1]);
+      control->press_mode = ival;
+    }      
+    else if( strcmp(tmp[0], "geo_format") == 0 ) {
+      ival = atoi( tmp[1] );
+      control->geo_format = ival;
+    }
+    else if( strcmp(tmp[0], "write_freq") == 0 ) {
+      ival = atoi(tmp[1]);
+      out_control->write_steps = ival;
+    }
+    else if( strcmp(tmp[0], "traj_compress") == 0 ) {
+      ival = atoi(tmp[1]);
+      out_control->traj_compress = ival;
+    }
+    else if( strcmp(tmp[0], "traj_method") == 0 ) {
+      ival = atoi(tmp[1]);
+      out_control->traj_method = ival;
+    }
+    else if( strcmp(tmp[0], "traj_title") == 0 ) {
+      strcpy( out_control->traj_title, tmp[1] );
+    }
+    else if( strcmp(tmp[0], "atom_info") == 0 ) {
+      ival = atoi(tmp[1]);
+      out_control->atom_info += ival * 4;
+    }
+    else if( strcmp(tmp[0], "atom_velocities") == 0 ) {
+      ival = atoi(tmp[1]);
+      out_control->atom_info += ival * 2;
+    }
+    else if( strcmp(tmp[0], "atom_forces") == 0 ) {
+      ival = atoi(tmp[1]);
+      out_control->atom_info += ival * 1;
+    }
+    else if( strcmp(tmp[0], "bond_info") == 0 ) {
+      ival = atoi(tmp[1]);
+      out_control->bond_info = ival;
+    }
+    else if( strcmp(tmp[0], "angle_info") == 0 ) {
+      ival = atoi(tmp[1]);
+      out_control->angle_info = ival;
+    }
+    else if( strcmp(tmp[0], "molecular_analysis") == 0 ) {
+      ival = atoi(tmp[1]);
+      control->molecular_analysis = ival;
+    }
+    else if( strcmp(tmp[0], "ignore") == 0 ) { 
+      control->num_ignored = atoi(tmp[1]);
+      for( i = 0; i < control->num_ignored; ++i )
+	control->ignore[atoi(tmp[i+2])] = 1;
+    }
+    else if( strcmp(tmp[0], "dipole_anal") == 0 ) {
+      ival = atoi(tmp[1]);
+      control->dipole_anal = ival;
+    }
+    else if( strcmp(tmp[0], "freq_dipole_anal") == 0 ) {
+      ival = atoi(tmp[1]);
+      control->freq_dipole_anal = ival;
+    }
+    else if( strcmp(tmp[0], "diffusion_coef") == 0 ) {
+      ival = atoi(tmp[1]);
+      control->diffusion_coef = ival;
+    }
+    else if( strcmp(tmp[0], "freq_diffusion_coef") == 0 ) {
+      ival = atoi(tmp[1]);
+      control->freq_diffusion_coef = ival;
+    }
+    else if( strcmp(tmp[0], "restrict_type") == 0 ) {
+      ival = atoi(tmp[1]);
+      control->restrict_type = ival;
+    }
+    else {
+      fprintf( stderr, "WARNING: unknown parameter %s\n", tmp[0] );
+      MPI_Abort( MPI_COMM_WORLD, 15 );
+    }
+  }
+
+  /* determine target T */
+  if( control->T_mode == 0 )
+    control->T = control->T_final;
+  else control->T = control->T_init;
+
+  /* free memory allocations at the top */
+  for( i = 0; i < MAX_TOKENS; i++ )
+    free( tmp[i] );
+  free( tmp );
+  free( s );
+
+  // fprintf( stderr,"%d %d %10.5f %d %10.5f %10.5f\n",
+  //   control->ensemble, control->nsteps, control->dt,
+  //   control->tabulate, control->T, control->P );
+
+#if defined(DEBUG_FOCUS)
+  fprintf( stderr, "control file read\n" );
+#endif
+
+  return SUCCESS;
+}
diff --git a/src/USER-REAXC/reaxc_control.h b/src/USER-REAXC/reaxc_control.h
new file mode 100644
index 0000000000..68fd33c95d
--- /dev/null
+++ b/src/USER-REAXC/reaxc_control.h
@@ -0,0 +1,29 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#ifndef __CONTROL_H_
+#define __CONTROL_H_
+
+#include "reaxc_types.h"
+
+char Read_Control_File( char*, control_params*, output_controls* );
+
+#endif
diff --git a/src/USER-REAXC/reaxc_defs.h b/src/USER-REAXC/reaxc_defs.h
new file mode 100644
index 0000000000..957816d38a
--- /dev/null
+++ b/src/USER-REAXC/reaxc_defs.h
@@ -0,0 +1,141 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#ifndef REAX_DEFS_H
+#define REAX_DEFS_H
+
+#if defined(__IBMC__)
+#define inline __inline__
+#endif /*IBMC*/
+
+#define SUCCESS  1
+#define FAILURE  0
+#define TRUE  1
+#define FALSE 0
+
+#define SQR(x)        ((x)*(x))
+#define CUBE(x)       ((x)*(x)*(x))
+#define DEG2RAD(a)    ((a)*constPI/180.0)
+#define RAD2DEG(a)    ((a)*180.0/constPI)
+#define MAX(x,y)      (((x) > (y)) ? (x) : (y))
+#define MIN(x,y)      (((x) < (y)) ? (x) : (y))
+#define MAX3(x,y,z)   MAX( MAX(x,y), z)
+
+#define constPI        3.14159265
+#define C_ele          332.06371
+//#define K_B         503.398008   // kcal/mol/K
+#define K_B             0.831687   // amu A^2 / ps^2 / K
+#define F_CONV          1e6 / 48.88821291 / 48.88821291   // --> amu A / ps^2
+#define E_CONV          0.002391   // amu A^2 / ps^2 --> kcal/mol
+#define EV_to_KCALpMOL 14.400000   // ElectronVolt --> KCAL per MOLe
+#define KCALpMOL_to_EV 23.02       // 23.060549 //KCAL per MOLe --> ElectronVolt
+#define ECxA_to_DEBYE   4.803204   // elem. charge * Ang -> debye
+#define CAL_to_JOULES   4.184000   // CALories --> JOULES
+#define JOULES_to_CAL   1/4.184000 // JOULES --> CALories
+#define AMU_to_GRAM     1.6605e-24
+#define ANG_to_CM       1e-8   
+#define AVOGNR          6.0221367e23
+#define P_CONV          1e-24 * AVOGNR * JOULES_to_CAL
+
+#define MAX_STR             1024
+#define MAX_LINE            1024
+#define MAX_TOKENS          1024
+#define MAX_TOKEN_LEN       1024
+
+#define MAX_ATOM_ID         100000
+#define MAX_RESTRICT        15
+#define MAX_MOLECULE_SIZE   20
+#define MAX_ATOM_TYPES      25
+
+#define NUM_INTRS      10
+#define ALMOST_ZERO    1e-10 
+#define NEG_INF       -1e10
+#define NO_BOND        1e-3  // 0.001
+#define HB_THRESHOLD   1e-2  // 0.01
+
+#define MIN_CAP        50
+#define MIN_NBRS       100
+#define MIN_HENTRIES   100
+#define MAX_BONDS      30
+#define MIN_BONDS      15
+#define MIN_HBONDS     25
+#define MIN_3BODIES    1000
+#define MIN_GCELL_POPL 50
+#define MIN_SEND       100
+#define SAFE_ZONE      1.2
+#define SAFER_ZONE     1.4
+#define DANGER_ZONE    0.90
+#define LOOSE_ZONE     0.75
+#define MAX_3BODY_PARAM     5
+#define MAX_4BODY_PARAM     5
+
+#define MAX_dV              1.01
+#define MIN_dV              0.99
+#define MAX_dT              4.00
+#define MIN_dT              0.00
+
+#define MASTER_NODE 0
+#define MAX_NBRS 6 //27
+#define MYSELF   13  // encoding of relative coordinate (0,0,0)
+
+#define MAX_ITR 10
+#define RESTART 30
+
+
+
+/******************* ENUMERATIONS *************************/
+enum geo_formats { CUSTOM, PDB, ASCII_RESTART, BINARY_RESTART, GF_N };
+
+enum restart_formats { WRITE_ASCII, WRITE_BINARY, RF_N };
+
+enum ensembles { NVE, bNVT, nhNVT, sNPT, iNPT, NPT, ens_N };
+
+enum lists { BONDS, OLD_BONDS, THREE_BODIES, 
+	     HBONDS, FAR_NBRS, DBOS, DDELTAS, LIST_N };
+
+enum interactions { TYP_VOID, TYP_BOND, TYP_THREE_BODY, 
+		    TYP_HBOND, TYP_FAR_NEIGHBOR, TYP_DBO, TYP_DDELTA, TYP_N };
+
+enum message_tags { INIT, UPDATE, BNDRY, UPDATE_BNDRY,
+		    EXC_VEC1, EXC_VEC2, DIST_RVEC2, COLL_RVEC2, 
+		    DIST_RVECS, COLL_RVECS, INIT_DESCS, ATOM_LINES, 
+		    BOND_LINES, ANGLE_LINES, RESTART_ATOMS, TAGS_N };
+
+enum errors { FILE_NOT_FOUND = -10, UNKNOWN_ATOM_TYPE = -11, 
+	      CANNOT_OPEN_FILE = -12, CANNOT_INITIALIZE = -13, 
+	      INSUFFICIENT_MEMORY = -14, UNKNOWN_OPTION = -15,
+	      INVALID_INPUT = -16, INVALID_GEO = -17 };
+
+enum exchanges { NONE, NEAR_EXCH, FULL_EXCH };
+
+enum gcell_types { NO_NBRS=0, NEAR_ONLY=1, HBOND_ONLY=2, FAR_ONLY=4, 
+		   NEAR_HBOND=3, NEAR_FAR=5, HBOND_FAR=6, FULL_NBRS=7, 
+		   NATIVE=8 };
+
+enum atoms { C_ATOM = 0, H_ATOM = 1, O_ATOM = 2, N_ATOM = 3, 
+	     S_ATOM = 4, SI_ATOM = 5, GE_ATOM = 6, X_ATOM = 7 };
+
+enum traj_methods { REG_TRAJ, MPI_TRAJ, TF_N };
+
+enum molecules { UNKNOWN, WATER };
+
+
+#endif
diff --git a/src/USER-REAXC/reaxc_ffield.cpp b/src/USER-REAXC/reaxc_ffield.cpp
new file mode 100644
index 0000000000..2d0f37123d
--- /dev/null
+++ b/src/USER-REAXC/reaxc_ffield.cpp
@@ -0,0 +1,715 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#include "reaxc_types.h"
+#if defined(PURE_REAX)
+#include "ffield.h"
+#include "tool_box.h"
+#elif defined(LAMMPS_REAX)
+#include "reaxc_ffield.h"
+#include "reaxc_tool_box.h"
+#endif
+
+
+char Read_Force_Field( char *ffield_file, reax_interaction *reax, 
+		       control_params *control )
+{
+  FILE    *fp;
+  char    *s;
+  char   **tmp;
+  char ****tor_flag;
+  int      c, i, j, k, l, m, n, o, p, cnt;
+  real     val;
+  MPI_Comm comm;
+
+  comm = MPI_COMM_WORLD;
+
+  /* open force field file */
+  if ( (fp = fopen( ffield_file, "r" ) ) == NULL ) {
+    fprintf( stderr, "error opening the force filed file! terminating...\n" );
+    MPI_Abort( comm, FILE_NOT_FOUND );
+  }
+  
+  s = (char*) malloc(sizeof(char)*MAX_LINE);
+  tmp = (char**) malloc(sizeof(char*)*MAX_TOKENS);
+  for (i=0; i < MAX_TOKENS; i++)
+    tmp[i] = (char*) malloc(sizeof(char)*MAX_TOKEN_LEN);
+
+
+  /* reading first header comment */
+  fgets( s, MAX_LINE, fp );
+
+  /* line 2 is number of global parameters */
+  fgets( s, MAX_LINE, fp );
+  c = Tokenize( s, &tmp );
+
+  /* reading the number of global parameters */
+  n = atoi(tmp[0]);
+  if (n < 1) {
+    fprintf( stderr, "WARNING: number of globals in ffield file is 0!\n" );
+    fclose(fp);
+    return 1;
+  }
+
+  reax->gp.n_global = n;
+  reax->gp.l = (real*) malloc(sizeof(real)*n);
+
+  /* see reax_types.h for mapping between l[i] and the lambdas used in ff */ 
+  for (i=0; i < n; i++) {
+    fgets(s,MAX_LINE,fp);
+    c = Tokenize(s,&tmp);
+    
+    val = (real) atof(tmp[0]);
+    reax->gp.l[i] = val;
+  }
+
+  control->bo_cut    = 0.01 * reax->gp.l[29];
+  control->nonb_low  = reax->gp.l[11];  
+  control->nonb_cut  = reax->gp.l[12];
+
+  /* next line is number of atom types and some comments */
+  fgets( s, MAX_LINE, fp );
+  c = Tokenize( s, &tmp );
+  reax->num_atom_types = atoi(tmp[0]);
+
+  /* 3 lines of comments */
+  fgets(s,MAX_LINE,fp);
+  fgets(s,MAX_LINE,fp);
+  fgets(s,MAX_LINE,fp);
+
+  /* Allocating structures in reax_interaction */
+  reax->sbp = (single_body_parameters*) 
+    scalloc( reax->num_atom_types, sizeof(single_body_parameters), "sbp", 
+	     comm );
+  reax->tbp = (two_body_parameters**)   
+    scalloc( reax->num_atom_types, sizeof(two_body_parameters*), "tbp", comm );
+  reax->thbp= (three_body_header***)    
+    scalloc( reax->num_atom_types, sizeof(three_body_header**), "thbp", comm );
+  reax->hbp = (hbond_parameters***)     
+    scalloc( reax->num_atom_types, sizeof(hbond_parameters**), "hbp", comm );
+  reax->fbp = (four_body_header****)    
+    scalloc( reax->num_atom_types, sizeof(four_body_header***), "fbp", comm );
+  tor_flag  = (char****)                
+    scalloc( reax->num_atom_types, sizeof(char***), "tor_flag", comm );
+  
+  for( i = 0; i < reax->num_atom_types; i++ ) {
+    reax->tbp[i] = (two_body_parameters*) 
+      scalloc( reax->num_atom_types, sizeof(two_body_parameters), "tbp[i]", 
+	       comm );
+    reax->thbp[i]= (three_body_header**)  
+      scalloc( reax->num_atom_types, sizeof(three_body_header*), "thbp[i]", 
+	       comm );
+    reax->hbp[i] = (hbond_parameters**)   
+      scalloc( reax->num_atom_types, sizeof(hbond_parameters*), "hbp[i]", 
+	       comm );
+    reax->fbp[i] = (four_body_header***)  
+      scalloc( reax->num_atom_types, sizeof(four_body_header**), "fbp[i]", 
+	       comm );
+    tor_flag[i]  = (char***)              
+      scalloc( reax->num_atom_types, sizeof(char**), "tor_flag[i]", comm );
+    
+    for( j = 0; j < reax->num_atom_types; j++ ) {
+      reax->thbp[i][j]= (three_body_header*) 
+	scalloc( reax->num_atom_types, sizeof(three_body_header), "thbp[i,j]", 
+		 comm );
+      reax->hbp[i][j] = (hbond_parameters*)  
+	scalloc( reax->num_atom_types, sizeof(hbond_parameters), "hbp[i,j]", 
+		 comm );
+      reax->fbp[i][j] = (four_body_header**) 
+	scalloc( reax->num_atom_types, sizeof(four_body_header*), "fbp[i,j]", 
+		 comm );
+      tor_flag[i][j]  = (char**)             
+	scalloc( reax->num_atom_types, sizeof(char*), "tor_flag[i,j]", comm );
+      
+      for (k=0; k < reax->num_atom_types; k++) {
+	reax->fbp[i][j][k] = (four_body_header*) 
+	  scalloc( reax->num_atom_types, sizeof(four_body_header), "fbp[i,j,k]",
+		   comm );
+	tor_flag[i][j][k]  = (char*)             
+	  scalloc( reax->num_atom_types, sizeof(char), "tor_flag[i,j,k]", 
+		   comm );
+      }
+    }
+  }
+
+  // vdWaals type: 1: Shielded Morse, no inner-wall 
+  //               2: inner wall, no shielding  
+  //               3: inner wall+shielding
+  reax->gp.vdw_type = 0;
+  
+  /* reading single atom parameters */
+  /* there are 4 lines of each single atom parameters in ff files. these
+     parameters later determine some of the pair and triplet parameters using 
+     combination rules. */
+  for( i = 0; i < reax->num_atom_types; i++ ) {
+    /* line one */
+    fgets( s, MAX_LINE, fp );
+    c = Tokenize( s, &tmp );
+    
+    for( j = 0; j < (int)(strlen(tmp[0])); ++j )
+      reax->sbp[i].name[j] = toupper( tmp[0][j] );
+    
+    val = atof(tmp[1]); reax->sbp[i].r_s        = val;
+    val = atof(tmp[2]); reax->sbp[i].valency    = val;
+    val = atof(tmp[3]); reax->sbp[i].mass       = val;
+    val = atof(tmp[4]); reax->sbp[i].r_vdw      = val;
+    val = atof(tmp[5]); reax->sbp[i].epsilon    = val;
+    val = atof(tmp[6]); reax->sbp[i].gamma      = val;
+    val = atof(tmp[7]); reax->sbp[i].r_pi       = val;
+    val = atof(tmp[8]); reax->sbp[i].valency_e  = val;
+    reax->sbp[i].nlp_opt = 0.5 * (reax->sbp[i].valency_e-reax->sbp[i].valency);
+
+    /* line two */
+    fgets( s, MAX_LINE, fp );
+    c = Tokenize( s, &tmp );
+    
+    val = atof(tmp[0]); reax->sbp[i].alpha      = val;
+    val = atof(tmp[1]); reax->sbp[i].gamma_w    = val;
+    val = atof(tmp[2]); reax->sbp[i].valency_boc= val;
+    val = atof(tmp[3]); reax->sbp[i].p_ovun5    = val;
+    val = atof(tmp[4]); 
+    val = atof(tmp[5]); reax->sbp[i].chi        = val;
+    val = atof(tmp[6]); reax->sbp[i].eta        = 2.0 * val;
+    val = atof(tmp[7]); reax->sbp[i].p_hbond = (int) val;
+    
+    /* line 3 */
+    fgets( s, MAX_LINE, fp );
+    c = Tokenize( s, &tmp );
+    
+    val = atof(tmp[0]); reax->sbp[i].r_pi_pi    = val;
+    val = atof(tmp[1]); reax->sbp[i].p_lp2      = val;
+    val = atof(tmp[2]); 
+    val = atof(tmp[3]); reax->sbp[i].b_o_131    = val;
+    val = atof(tmp[4]); reax->sbp[i].b_o_132    = val;
+    val = atof(tmp[5]); reax->sbp[i].b_o_133    = val;
+    val = atof(tmp[6]); 
+    val = atof(tmp[7]); 
+    
+    /* line 4  */
+    fgets( s, MAX_LINE, fp );
+    c = Tokenize( s, &tmp );
+    
+    val = atof(tmp[0]); reax->sbp[i].p_ovun2    = val;
+    val = atof(tmp[1]); reax->sbp[i].p_val3     = val;
+    val = atof(tmp[2]); 
+    val = atof(tmp[3]); reax->sbp[i].valency_val= val;
+    val = atof(tmp[4]); reax->sbp[i].p_val5     = val;
+    val = atof(tmp[5]); reax->sbp[i].rcore2     = val;
+    val = atof(tmp[6]); reax->sbp[i].ecore2     = val;
+    val = atof(tmp[7]); reax->sbp[i].acore2     = val;
+   
+
+    if( reax->sbp[i].rcore2>0.01 && reax->sbp[i].acore2>0.01 ){ // Inner-wall
+      if( reax->sbp[i].gamma_w>0.5 ){ // Shielding vdWaals
+	if( reax->gp.vdw_type != 0 && reax->gp.vdw_type != 3 )
+	  fprintf( stderr, "Warning: inconsistent vdWaals-parameters\n"	\
+		   "Force field parameters for element %s\n"		\
+		   "indicate inner wall+shielding, but earlier\n"	\
+		   "atoms indicate different vdWaals-method.\n"		\
+		   "This may cause division-by-zero errors.\n"		\
+		   "Keeping vdWaals-setting for earlier atoms.\n", 
+		   reax->sbp[i].name );
+	else{
+	  reax->gp.vdw_type = 3;
+#if defined(DEBUG)
+	  fprintf( stderr, "vdWaals type for element %s: Shielding+inner-wall",
+		   reax->sbp[i].name );
+#endif
+	}
+      }
+      else {  // No shielding vdWaals parameters present
+	if( reax->gp.vdw_type != 0 && reax->gp.vdw_type != 2 )
+	  fprintf( stderr, "Warning: inconsistent vdWaals-parameters\n"	\
+		   "Force field parameters for element %s\n"		\
+		   "indicate inner wall without shielding, but earlier\n" \
+		   "atoms indicate different vdWaals-method.\n"		\
+		   "This may cause division-by-zero errors.\n"		\
+		   "Keeping vdWaals-setting for earlier atoms.\n", 
+		   reax->sbp[i].name );
+	else{
+	  reax->gp.vdw_type = 2;
+#if defined(DEBUG)
+	  fprintf( stderr,"vdWaals type for element%s: No Shielding,inner-wall",
+		   reax->sbp[i].name );
+#endif
+	}
+      }
+    }
+    else{ // No Inner wall parameters present
+      if( reax->sbp[i].gamma_w>0.5 ){ // Shielding vdWaals
+	if( reax->gp.vdw_type != 0 && reax->gp.vdw_type != 1 )
+	  fprintf( stderr, "Warning: inconsistent vdWaals-parameters\n"	\
+		   "Force field parameters for element %s\n"		\
+		   "indicate  shielding without inner wall, but earlier\n" \
+		   "atoms indicate different vdWaals-method.\n"		\
+		   "This may cause division-by-zero errors.\n"		\
+		   "Keeping vdWaals-setting for earlier atoms.\n", 
+		   reax->sbp[i].name );
+	else{
+	  reax->gp.vdw_type = 1;
+#if defined(DEBUG)
+	  fprintf( stderr,"vdWaals type for element%s: Shielding,no inner-wall",
+		   reax->sbp[i].name );
+#endif
+	}
+      }
+      else{
+	fprintf( stderr, "Error: inconsistent vdWaals-parameters\n"\
+		 "No shielding or inner-wall set for element %s\n",
+		 reax->sbp[i].name );
+	MPI_Abort( comm, INVALID_INPUT );
+      }
+    } 
+  }
+
+#if defined(DEBUG)
+  fprintf( stderr, "vdWaals type: %d\n", reax->gp.vdw_type );
+#endif
+
+  /* Equate vval3 to valf for first-row elements (25/10/2004) */
+  for( i = 0; i < reax->num_atom_types; i++ )
+    if( reax->sbp[i].mass < 21 &&
+	reax->sbp[i].valency_val != reax->sbp[i].valency_boc ){
+      fprintf( stderr, "Warning: changed valency_val to valency_boc for %s\n",
+	       reax->sbp[i].name );
+      reax->sbp[i].valency_val = reax->sbp[i].valency_boc;
+    }
+
+
+  /* next line is number of two body combination and some comments */
+  fgets(s,MAX_LINE,fp);
+  c=Tokenize(s,&tmp);
+  l = atoi(tmp[0]);
+
+  /* a line of comments */
+  fgets(s,MAX_LINE,fp);
+  
+  for (i=0; i < l; i++) {
+    /* line 1 */
+    fgets(s,MAX_LINE,fp);
+    c=Tokenize(s,&tmp);
+      
+    j = atoi(tmp[0]) - 1;
+    k = atoi(tmp[1]) - 1;
+
+    if (j < reax->num_atom_types && k < reax->num_atom_types) {
+
+      val = atof(tmp[2]); reax->tbp[j][k].De_s      = val;
+      reax->tbp[k][j].De_s      = val;
+      val = atof(tmp[3]); reax->tbp[j][k].De_p      = val;
+      reax->tbp[k][j].De_p      = val;
+      val = atof(tmp[4]); reax->tbp[j][k].De_pp     = val;
+      reax->tbp[k][j].De_pp     = val;
+      val = atof(tmp[5]); reax->tbp[j][k].p_be1     = val;
+      reax->tbp[k][j].p_be1     = val;
+      val = atof(tmp[6]); reax->tbp[j][k].p_bo5     = val;
+      reax->tbp[k][j].p_bo5     = val;
+      val = atof(tmp[7]); reax->tbp[j][k].v13cor    = val;
+      reax->tbp[k][j].v13cor    = val;
+                          
+      val = atof(tmp[8]); reax->tbp[j][k].p_bo6     = val;
+      reax->tbp[k][j].p_bo6     = val;
+      val = atof(tmp[9]); reax->tbp[j][k].p_ovun1 = val;
+      reax->tbp[k][j].p_ovun1 = val;
+
+      /* line 2 */
+      fgets(s,MAX_LINE,fp);
+      c=Tokenize(s,&tmp);
+
+      val = atof(tmp[0]); reax->tbp[j][k].p_be2     = val;
+      reax->tbp[k][j].p_be2     = val;
+      val = atof(tmp[1]); reax->tbp[j][k].p_bo3     = val;
+      reax->tbp[k][j].p_bo3     = val;
+      val = atof(tmp[2]); reax->tbp[j][k].p_bo4     = val;
+      reax->tbp[k][j].p_bo4     = val;
+      val = atof(tmp[3]); 
+                          
+      val = atof(tmp[4]); reax->tbp[j][k].p_bo1     = val;
+      reax->tbp[k][j].p_bo1     = val;
+      val = atof(tmp[5]); reax->tbp[j][k].p_bo2     = val;
+      reax->tbp[k][j].p_bo2     = val;
+      val = atof(tmp[6]); reax->tbp[j][k].ovc       = val;
+      reax->tbp[k][j].ovc       = val;
+                          
+      val = atof(tmp[7]); 
+    }
+  }
+
+  /* calculating combination rules and filling up remaining fields. */
+  
+  for (i=0; i < reax->num_atom_types; i++)
+    for (j=i; j < reax->num_atom_types; j++) {
+      reax->tbp[i][j].r_s = 0.5 *
+	(reax->sbp[i].r_s + reax->sbp[j].r_s);
+      reax->tbp[j][i].r_s = 0.5 *
+	(reax->sbp[j].r_s + reax->sbp[i].r_s);
+
+      reax->tbp[i][j].r_p = 0.5 *
+	(reax->sbp[i].r_pi + reax->sbp[j].r_pi);
+      reax->tbp[j][i].r_p = 0.5 *
+	(reax->sbp[j].r_pi + reax->sbp[i].r_pi);
+
+      reax->tbp[i][j].r_pp = 0.5 *
+	(reax->sbp[i].r_pi_pi + reax->sbp[j].r_pi_pi);
+      reax->tbp[j][i].r_pp = 0.5 *
+	(reax->sbp[j].r_pi_pi + reax->sbp[i].r_pi_pi);
+
+
+      reax->tbp[i][j].p_boc3 = 
+	sqrt(reax->sbp[i].b_o_132 *
+	     reax->sbp[j].b_o_132);
+      reax->tbp[j][i].p_boc3 = 
+	sqrt(reax->sbp[j].b_o_132 *
+	     reax->sbp[i].b_o_132);
+
+      reax->tbp[i][j].p_boc4 = 
+	sqrt(reax->sbp[i].b_o_131 *
+	     reax->sbp[j].b_o_131);
+      reax->tbp[j][i].p_boc4 = 
+	sqrt(reax->sbp[j].b_o_131 *
+	     reax->sbp[i].b_o_131);
+
+      reax->tbp[i][j].p_boc5 = 
+	sqrt(reax->sbp[i].b_o_133 *
+	     reax->sbp[j].b_o_133);
+      reax->tbp[j][i].p_boc5 = 
+	sqrt(reax->sbp[j].b_o_133 *
+	     reax->sbp[i].b_o_133);
+
+	
+      reax->tbp[i][j].D = 
+	sqrt(reax->sbp[i].epsilon *
+	     reax->sbp[j].epsilon);
+
+      reax->tbp[j][i].D = 
+	sqrt(reax->sbp[j].epsilon *
+	     reax->sbp[i].epsilon);
+
+      reax->tbp[i][j].alpha = 
+	sqrt(reax->sbp[i].alpha *
+	     reax->sbp[j].alpha);
+
+      reax->tbp[j][i].alpha = 
+	sqrt(reax->sbp[j].alpha *
+	     reax->sbp[i].alpha);
+
+      reax->tbp[i][j].r_vdW = 
+	2.0 * sqrt(reax->sbp[i].r_vdw * reax->sbp[j].r_vdw);
+
+      reax->tbp[j][i].r_vdW =
+	2.0 * sqrt(reax->sbp[j].r_vdw * reax->sbp[i].r_vdw);
+
+      reax->tbp[i][j].gamma_w =
+	sqrt(reax->sbp[i].gamma_w *
+	     reax->sbp[j].gamma_w);
+
+      reax->tbp[j][i].gamma_w =
+	sqrt(reax->sbp[j].gamma_w *
+	     reax->sbp[i].gamma_w);
+
+      reax->tbp[i][j].gamma =
+	pow(reax->sbp[i].gamma *
+	    reax->sbp[j].gamma,-1.5);
+
+      reax->tbp[j][i].gamma =
+	pow(reax->sbp[j].gamma *
+	    reax->sbp[i].gamma,-1.5);
+
+      // additions for additional vdWaals interaction types - inner core
+      reax->tbp[i][j].rcore = reax->tbp[j][i].rcore =
+	sqrt( reax->sbp[i].rcore2 * reax->sbp[j].rcore2 );
+
+      reax->tbp[i][j].ecore = reax->tbp[j][i].ecore =
+	sqrt( reax->sbp[i].ecore2 * reax->sbp[j].ecore2 );
+
+      reax->tbp[i][j].acore = reax->tbp[j][i].acore =
+	sqrt( reax->sbp[i].acore2 * reax->sbp[j].acore2 );
+    }
+
+
+  /* next line is number of two body offdiagonal combinations and comments */
+  /* these are two body offdiagonal terms that are different from the
+     combination rules defined above */
+  fgets(s,MAX_LINE,fp);
+  c=Tokenize(s,&tmp);
+  l = atoi(tmp[0]);
+  
+  for (i=0; i < l; i++) {
+    fgets(s,MAX_LINE,fp);
+    c=Tokenize(s,&tmp);
+      
+    j = atoi(tmp[0]) - 1;
+    k = atoi(tmp[1]) - 1;
+
+    if (j < reax->num_atom_types && k < reax->num_atom_types)	{
+      val = atof(tmp[2]); 
+      if (val > 0.0) {
+	reax->tbp[j][k].D = val;
+	reax->tbp[k][j].D = val;
+      }
+
+      val = atof(tmp[3]); 
+      if (val > 0.0) {
+	reax->tbp[j][k].r_vdW = 2 * val;
+	reax->tbp[k][j].r_vdW = 2 * val;
+      }
+
+      val = atof(tmp[4]); 
+      if (val > 0.0) {
+	reax->tbp[j][k].alpha = val;
+	reax->tbp[k][j].alpha = val;
+      }
+
+      val = atof(tmp[5]); 
+      if (val > 0.0) {
+	reax->tbp[j][k].r_s = val;
+	reax->tbp[k][j].r_s = val;
+      }
+
+      val = atof(tmp[6]); 
+      if (val > 0.0) {
+	reax->tbp[j][k].r_p = val;
+	reax->tbp[k][j].r_p = val;
+      }
+
+      val = atof(tmp[7]); 
+      if (val > 0.0) {
+	reax->tbp[j][k].r_pp = val;
+	reax->tbp[k][j].r_pp = val;
+      }
+    }
+  }
+  
+
+  /* 3-body parameters - 
+     supports multi-well potentials (upto MAX_3BODY_PARAM in mytypes.h) */
+  /* clear entries first */
+  for( i = 0; i < reax->num_atom_types; ++i )
+    for( j = 0; j < reax->num_atom_types; ++j )
+      for( k = 0; k < reax->num_atom_types; ++k )
+	reax->thbp[i][j][k].cnt = 0;
+
+  /* next line is number of 3-body params and some comments */	
+  fgets( s, MAX_LINE, fp );
+  c = Tokenize( s, &tmp );
+  l = atoi( tmp[0] );
+  
+  for( i = 0; i < l; i++ ) {
+    fgets(s,MAX_LINE,fp);
+    c=Tokenize(s,&tmp);
+      
+    j = atoi(tmp[0]) - 1;
+    k = atoi(tmp[1]) - 1;
+    m = atoi(tmp[2]) - 1;
+
+    if (j < reax->num_atom_types && k < reax->num_atom_types && 
+	m < reax->num_atom_types) {
+      cnt = reax->thbp[j][k][m].cnt;
+      reax->thbp[j][k][m].cnt++;
+      reax->thbp[m][k][j].cnt++;
+
+      val = atof(tmp[3]); 
+      reax->thbp[j][k][m].prm[cnt].theta_00 = val;
+      reax->thbp[m][k][j].prm[cnt].theta_00 = val;
+
+      val = atof(tmp[4]); 
+      reax->thbp[j][k][m].prm[cnt].p_val1 = val;
+      reax->thbp[m][k][j].prm[cnt].p_val1 = val;
+
+      val = atof(tmp[5]); 
+      reax->thbp[j][k][m].prm[cnt].p_val2 = val;
+      reax->thbp[m][k][j].prm[cnt].p_val2 = val;
+
+      val = atof(tmp[6]); 
+      reax->thbp[j][k][m].prm[cnt].p_coa1 = val;
+      reax->thbp[m][k][j].prm[cnt].p_coa1 = val;
+
+      val = atof(tmp[7]); 
+      reax->thbp[j][k][m].prm[cnt].p_val7 = val;
+      reax->thbp[m][k][j].prm[cnt].p_val7 = val;
+
+      val = atof(tmp[8]); 
+      reax->thbp[j][k][m].prm[cnt].p_pen1 = val;
+      reax->thbp[m][k][j].prm[cnt].p_pen1 = val;
+
+      val = atof(tmp[9]); 
+      reax->thbp[j][k][m].prm[cnt].p_val4 = val;
+      reax->thbp[m][k][j].prm[cnt].p_val4 = val;	  
+    }
+  }
+
+
+  /* 4-body parameters are entered in compact form. i.e. 0-X-Y-0
+     correspond to any type of pair of atoms in 1 and 4
+     position. However, explicit X-Y-Z-W takes precedence over the
+     default description.
+     supports multi-well potentials (upto MAX_4BODY_PARAM in mytypes.h)
+     IMPORTANT: for now, directions on how to read multi-entries from ffield 
+     is not clear */
+  
+  /* clear all entries first */
+  for( i = 0; i < reax->num_atom_types; ++i )
+    for( j = 0; j < reax->num_atom_types; ++j )
+      for( k = 0; k < reax->num_atom_types; ++k )
+	for( m = 0; m < reax->num_atom_types; ++m ) {
+	  reax->fbp[i][j][k][m].cnt = 0;
+	  tor_flag[i][j][k][m] = 0;
+	}
+
+  /* next line is number of 4-body params and some comments */
+  fgets( s, MAX_LINE, fp );
+  c = Tokenize( s, &tmp );
+  l = atoi( tmp[0] );
+
+  for( i = 0; i < l; i++ ) {
+    fgets( s, MAX_LINE, fp );
+    c = Tokenize( s, &tmp );
+        
+    j = atoi(tmp[0]) - 1;
+    k = atoi(tmp[1]) - 1;
+    m = atoi(tmp[2]) - 1;
+    n = atoi(tmp[3]) - 1;
+      
+    if (j >= 0 && n >= 0) { // this means the entry is not in compact form
+      if (j < reax->num_atom_types && k < reax->num_atom_types && 
+	  m < reax->num_atom_types && n < reax->num_atom_types) {
+	/* these flags ensure that this entry take precedence
+	   over the compact form entries */
+	tor_flag[j][k][m][n] = 1;
+	tor_flag[n][m][k][j] = 1;
+
+	reax->fbp[j][k][m][n].cnt = 1;
+	reax->fbp[n][m][k][j].cnt = 1;
+	/* cnt = reax->fbp[j][k][m][n].cnt;
+	   reax->fbp[j][k][m][n].cnt++;
+	   reax->fbp[n][m][k][j].cnt++; */
+
+	val = atof(tmp[4]); 
+	reax->fbp[j][k][m][n].prm[0].V1 = val;
+	reax->fbp[n][m][k][j].prm[0].V1 = val;
+
+	val = atof(tmp[5]); 
+	reax->fbp[j][k][m][n].prm[0].V2 = val;
+	reax->fbp[n][m][k][j].prm[0].V2 = val;
+
+	val = atof(tmp[6]); 
+	reax->fbp[j][k][m][n].prm[0].V3 = val;
+	reax->fbp[n][m][k][j].prm[0].V3 = val;
+
+	val = atof(tmp[7]); 
+	reax->fbp[j][k][m][n].prm[0].p_tor1 = val;
+	reax->fbp[n][m][k][j].prm[0].p_tor1 = val;
+
+	val = atof(tmp[8]); 
+	reax->fbp[j][k][m][n].prm[0].p_cot1 = val;
+	reax->fbp[n][m][k][j].prm[0].p_cot1 = val;	      
+      }
+    }      
+    else { /* This means the entry is of the form 0-X-Y-0 */
+      if( k < reax->num_atom_types && m < reax->num_atom_types )
+	for( p = 0; p < reax->num_atom_types; p++ )
+	  for( o = 0; o < reax->num_atom_types; o++ ) {
+	    reax->fbp[p][k][m][o].cnt = 1;
+	    reax->fbp[o][m][k][p].cnt = 1;
+	    /* cnt = reax->fbp[p][k][m][o].cnt;
+	       reax->fbp[p][k][m][o].cnt++;
+	       reax->fbp[o][m][k][p].cnt++; */
+
+	    if (tor_flag[p][k][m][o] == 0) {
+	      reax->fbp[p][k][m][o].prm[0].V1 = atof(tmp[4]);
+	      reax->fbp[p][k][m][o].prm[0].V2 = atof(tmp[5]);
+	      reax->fbp[p][k][m][o].prm[0].V3 = atof(tmp[6]);
+	      reax->fbp[p][k][m][o].prm[0].p_tor1 = atof(tmp[7]);
+	      reax->fbp[p][k][m][o].prm[0].p_cot1 = atof(tmp[8]);
+	    }
+		  
+	    if (tor_flag[o][m][k][p] == 0) {
+	      reax->fbp[o][m][k][p].prm[0].V1 = atof(tmp[4]);
+	      reax->fbp[o][m][k][p].prm[0].V2 = atof(tmp[5]);
+	      reax->fbp[o][m][k][p].prm[0].V3 = atof(tmp[6]);
+	      reax->fbp[o][m][k][p].prm[0].p_tor1 = atof(tmp[7]);
+	      reax->fbp[o][m][k][p].prm[0].p_cot1 = atof(tmp[8]);
+	    }		
+	  }
+    }
+  }
+
+
+
+  /* next line is number of hydrogen bond params and some comments */
+  fgets( s, MAX_LINE, fp );
+  c = Tokenize( s, &tmp );
+  l = atoi( tmp[0] );
+
+  for( i = 0; i < l; i++ ) {
+    fgets( s, MAX_LINE, fp );
+    c = Tokenize( s, &tmp );
+      
+    j = atoi(tmp[0]) - 1;
+    k = atoi(tmp[1]) - 1;
+    m = atoi(tmp[2]) - 1;
+
+
+    if( j < reax->num_atom_types && m < reax->num_atom_types ) {
+      val = atof(tmp[3]); 
+      reax->hbp[j][k][m].r0_hb = val;
+
+      val = atof(tmp[4]); 
+      reax->hbp[j][k][m].p_hb1 = val;
+
+      val = atof(tmp[5]); 
+      reax->hbp[j][k][m].p_hb2 = val;
+
+      val = atof(tmp[6]); 
+      reax->hbp[j][k][m].p_hb3 = val;
+    }
+  }
+
+  
+  /* deallocate helper storage */
+  for( i = 0; i < MAX_TOKENS; i++ )
+    free( tmp[i] );
+  free( tmp );
+  free( s );
+
+
+  /* deallocate tor_flag */
+  for( i = 0; i < reax->num_atom_types; i++ ) {
+    for( j = 0; j < reax->num_atom_types; j++ ) {
+      for( k = 0; k < reax->num_atom_types; k++ ) {
+	free( tor_flag[i][j][k] );
+      }
+      free( tor_flag[i][j] );
+    }
+    free( tor_flag[i] );
+  }
+  free( tor_flag );
+
+  // close file
+
+  fclose(fp);
+
+#if defined(DEBUG_FOCUS)
+  fprintf( stderr, "force field read\n" );
+#endif
+  
+  return SUCCESS;
+}
diff --git a/src/USER-REAXC/reaxc_ffield.h b/src/USER-REAXC/reaxc_ffield.h
new file mode 100644
index 0000000000..22a580f7f8
--- /dev/null
+++ b/src/USER-REAXC/reaxc_ffield.h
@@ -0,0 +1,29 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#ifndef __FFIELD_H_
+#define __FFIELD_H_
+
+#include "reaxc_types.h"
+
+char Read_Force_Field( char*, reax_interaction*, control_params* );
+
+#endif
diff --git a/src/USER-REAXC/reaxc_forces.cpp b/src/USER-REAXC/reaxc_forces.cpp
new file mode 100644
index 0000000000..b1d5874683
--- /dev/null
+++ b/src/USER-REAXC/reaxc_forces.cpp
@@ -0,0 +1,929 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#include "reaxc_types.h"
+#if defined(PURE_REAX)
+#include "forces.h"
+#include "bond_orders.h"
+#include "bonds.h"
+#include "basic_comm.h"
+#include "hydrogen_bonds.h"
+#include "io_tools.h"
+#include "list.h"
+#include "lookup.h"
+#include "multi_body.h"
+#include "nonbonded.h"
+#include "qEq.h"
+#include "tool_box.h"
+#include "torsion_angles.h"
+#include "valence_angles.h"
+#include "vector.h"
+#elif defined(LAMMPS_REAX)
+#include "reaxc_forces.h"
+#include "reaxc_bond_orders.h"
+#include "reaxc_bonds.h"
+#include "reaxc_basic_comm.h"
+#include "reaxc_hydrogen_bonds.h"
+#include "reaxc_io_tools.h"
+#include "reaxc_list.h"
+#include "reaxc_lookup.h"
+#include "reaxc_multi_body.h"
+#include "reaxc_nonbonded.h"
+#include "reaxc_tool_box.h"
+#include "reaxc_torsion_angles.h"
+#include "reaxc_valence_angles.h"
+#include "reaxc_vector.h"
+#endif
+
+interaction_function Interaction_Functions[NUM_INTRS];
+
+void Dummy_Interaction( reax_system *system, control_params *control, 
+			simulation_data *data, storage *workspace, 
+			reax_list **lists, output_controls *out_control )
+{
+}
+
+
+void Init_Force_Functions( control_params *control )
+{ 
+  Interaction_Functions[0] = BO;
+  Interaction_Functions[1] = Bonds; //Dummy_Interaction;
+  Interaction_Functions[2] = Atom_Energy; //Dummy_Interaction;
+  Interaction_Functions[3] = Valence_Angles; //Dummy_Interaction;
+  Interaction_Functions[4] = Torsion_Angles; //Dummy_Interaction;
+  if( control->hbond_cut > 0 )
+    Interaction_Functions[5] = Hydrogen_Bonds;
+  else Interaction_Functions[5] = Dummy_Interaction;
+  Interaction_Functions[6] = Dummy_Interaction; //empty
+  Interaction_Functions[7] = Dummy_Interaction; //empty
+  Interaction_Functions[8] = Dummy_Interaction; //empty
+  Interaction_Functions[9] = Dummy_Interaction; //empty
+}
+
+
+void Compute_Bonded_Forces( reax_system *system, control_params *control, 
+			    simulation_data *data, storage *workspace, 
+			    reax_list **lists, output_controls *out_control,
+			    MPI_Comm comm )
+{
+  int i;
+
+  /* Mark beginning of a new timestep in bonded energy files */
+#if defined(TEST_ENERGY)
+  Debug_Marker_Bonded( out_control, data->step );
+#endif 
+
+  /* Implement all force calls as function pointers */
+  for( i = 0; i < NUM_INTRS; i++ ) {
+#if defined(DEBUG)
+    fprintf( stderr, "p%d: starting f%d\n", system->my_rank, i );
+    MPI_Barrier( comm );
+#endif
+    (Interaction_Functions[i])( system, control, data, workspace, 
+				lists, out_control );
+#if defined(DEBUG)
+    fprintf( stderr, "p%d: f%d done\n", system->my_rank, i );
+    MPI_Barrier( comm );
+#endif
+  }
+}
+
+
+void Compute_NonBonded_Forces( reax_system *system, control_params *control, 
+			       simulation_data *data, storage *workspace, 
+			       reax_list **lists, output_controls *out_control,
+			       MPI_Comm comm )
+{
+  /* Mark beginning of a new timestep in nonbonded energy files */
+#if defined(TEST_ENERGY)
+  Debug_Marker_Nonbonded( out_control, data->step );
+#endif
+
+  /* van der Waals and Coulomb interactions */
+  if( control->tabulate == 0 )
+    vdW_Coulomb_Energy( system, control, data, workspace, 
+			lists, out_control );
+  else
+    Tabulated_vdW_Coulomb_Energy( system, control, data, workspace, 
+				  lists, out_control );
+  
+#if defined(DEBUG)
+  fprintf( stderr, "p%d: nonbonded forces done\n", system->my_rank );
+  MPI_Barrier( comm );
+#endif
+}
+
+
+
+/* this version of Compute_Total_Force computes forces from 
+   coefficients accumulated by all interaction functions. 
+   Saves enormous time & space! */
+void Compute_Total_Force( reax_system *system, control_params *control, 
+			  simulation_data *data, storage *workspace, 
+			  reax_list **lists, mpi_datatypes *mpi_data )
+{
+  int i, pj;
+  reax_list *bonds = (*lists) + BONDS;
+
+  for( i = 0; i < system->N; ++i )
+    for( pj = Start_Index(i, bonds); pj < End_Index(i, bonds); ++pj )
+      if( i < bonds->select.bond_list[pj].nbr ) {
+	if( control->virial == 0 )
+	  Add_dBond_to_Forces( i, pj, workspace, lists );
+	else 
+	  Add_dBond_to_Forces_NPT( i, pj, data, workspace, lists );
+      }
+
+  //Print_Total_Force( system, data, workspace );
+#if defined(PURE_REAX)
+  /* now all forces are computed to their partially-final values 
+     based on the neighbors information each processor has had. 
+     final values of force on each atom needs to be computed by adding up
+     all partially-final pieces */
+  Coll( system, mpi_data, workspace->f, mpi_data->mpi_rvec, 
+	sizeof(rvec)/sizeof(void), rvec_unpacker );
+  for( i = 0; i < system->n; ++i )
+    rvec_Copy( system->my_atoms[i].f, workspace->f[i] );
+
+#if defined(TEST_FORCES)
+  Coll( system, mpi_data, workspace->f_ele, mpi_data->mpi_rvec, rvec_unpacker);
+  Coll( system, mpi_data, workspace->f_vdw, mpi_data->mpi_rvec, rvec_unpacker);
+  Coll( system, mpi_data, workspace->f_be, mpi_data->mpi_rvec, rvec_unpacker );
+  Coll( system, mpi_data, workspace->f_lp, mpi_data->mpi_rvec, rvec_unpacker );
+  Coll( system, mpi_data, workspace->f_ov, mpi_data->mpi_rvec, rvec_unpacker );
+  Coll( system, mpi_data, workspace->f_un, mpi_data->mpi_rvec, rvec_unpacker );
+  Coll( system, mpi_data, workspace->f_ang, mpi_data->mpi_rvec, rvec_unpacker);
+  Coll( system, mpi_data, workspace->f_coa, mpi_data->mpi_rvec, rvec_unpacker);
+  Coll( system, mpi_data, workspace->f_pen, mpi_data->mpi_rvec, rvec_unpacker);
+  Coll( system, mpi_data, workspace->f_hb, mpi_data->mpi_rvec, rvec_unpacker );
+  Coll( system, mpi_data, workspace->f_tor, mpi_data->mpi_rvec, rvec_unpacker);
+  Coll( system, mpi_data, workspace->f_con, mpi_data->mpi_rvec, rvec_unpacker);
+#endif
+
+#endif
+}
+
+void Validate_Lists( reax_system *system, storage *workspace, reax_list **lists,
+		     int step, int n, int N, int numH, MPI_Comm comm )
+{
+  int i, comp, Hindex;
+  reax_list *bonds, *hbonds;
+  reallocate_data *realloc;
+  realloc = &(workspace->realloc);
+
+  /* bond list */
+  if( N > 0 ) {
+    bonds = *lists + BONDS;
+    
+    for( i = 0; i < N; ++i ) {
+      // if( i < n ) - we need to update ghost estimates for delayed nbrings
+      system->my_atoms[i].num_bonds = MAX(Num_Entries(i,bonds)*2, MIN_BONDS);
+     
+      //if( End_Index(i, bonds) >= Start_Index(i+1, bonds)-2 )
+      //workspace->realloc.bonds = 1;
+      
+      if( i < N-1 )
+	comp = Start_Index(i+1, bonds);
+      else comp = bonds->num_intrs;
+      
+      if( End_Index(i, bonds) > comp ) {
+	fprintf( stderr, "step%d-bondchk failed: i=%d end(i)=%d str(i+1)=%d\n",
+		 step, i, End_Index(i,bonds), comp );
+	MPI_Abort( comm, INSUFFICIENT_MEMORY );
+      }
+    }
+  }
+
+
+  /* hbonds list */
+  if( numH > 0 ) {
+    hbonds = *lists + HBONDS;
+    
+    for( i = 0; i < n; ++i ) {
+      Hindex = system->my_atoms[i].Hindex;
+      if( Hindex > -1 ) {
+	system->my_atoms[i].num_hbonds = 
+	  (int)(MAX( Num_Entries(Hindex, hbonds)*SAFER_ZONE, MIN_HBONDS ));
+	
+	//if( Num_Entries(i, hbonds) >= 
+	//(Start_Index(i+1,hbonds)-Start_Index(i,hbonds))*0.90/*DANGER_ZONE*/){
+	//  workspace->realloc.hbonds = 1;
+	
+	if( Hindex < numH-1 )
+	  comp = Start_Index(Hindex+1, hbonds);
+	else comp = hbonds->num_intrs;
+	
+	if( End_Index(Hindex, hbonds) > comp ) {
+	  fprintf(stderr,"step%d-hbondchk failed: H=%d end(H)=%d str(H+1)=%d\n",
+		  step, Hindex, End_Index(Hindex,hbonds), comp );
+	  MPI_Abort( comm, INSUFFICIENT_MEMORY );
+	}
+      }
+    }
+  }
+}
+
+
+real Compute_H( real r, real gamma, real *ctap )
+{
+  real taper, dr3gamij_1, dr3gamij_3;
+
+  taper = ctap[7] * r + ctap[6];
+  taper = taper * r + ctap[5];
+  taper = taper * r + ctap[4];
+  taper = taper * r + ctap[3];
+  taper = taper * r + ctap[2];
+  taper = taper * r + ctap[1];
+  taper = taper * r + ctap[0];	      
+  
+  dr3gamij_1 = ( r*r*r + gamma );
+  dr3gamij_3 = pow( dr3gamij_1 , 0.33333333333333 );
+  return taper * EV_to_KCALpMOL / dr3gamij_3;
+}
+
+
+real Compute_tabH( real r_ij, int ti, int tj )
+{
+  int r, tmin, tmax;
+  real val, dif, base;
+  LR_lookup_table *t;
+
+  tmin  = MIN( ti, tj );
+  tmax  = MAX( ti, tj );
+  t = &( LR[tmin][tmax] );	  
+
+  /* cubic spline interpolation */
+  r = (int)(r_ij * t->inv_dx);
+  if( r == 0 )  ++r;
+  base = (real)(r+1) * t->dx;
+  dif = r_ij - base;
+  val = ((t->ele[r].d*dif + t->ele[r].c)*dif + t->ele[r].b)*dif + 
+    t->ele[r].a;
+  val *= EV_to_KCALpMOL / C_ele;
+  
+  return val;
+}
+
+
+void Init_Forces( reax_system *system, control_params *control, 
+		  simulation_data *data, storage *workspace, reax_list **lists,
+		  output_controls *out_control, MPI_Comm comm ) {
+  int i, j, pj;
+  int start_i, end_i;
+  int type_i, type_j;
+  int Htop, btop_i, btop_j, num_bonds, num_hbonds;
+  int ihb, jhb, ihb_top, jhb_top;
+  int local, flag, renbr;
+  real r_ij, cutoff;
+  sparse_matrix *H;
+  reax_list *far_nbrs, *bonds, *hbonds;
+  single_body_parameters *sbp_i, *sbp_j;
+  two_body_parameters *twbp;
+  far_neighbor_data *nbr_pj;
+  reax_atom *atom_i, *atom_j;
+
+  far_nbrs = *lists + FAR_NBRS;
+  bonds = *lists + BONDS;
+  hbonds = *lists + HBONDS;
+
+  for( i = 0; i < system->n; ++i )
+    workspace->bond_mark[i] = 0;
+  for( i = system->n; i < system->N; ++i ) {
+    workspace->bond_mark[i] = 1000; // put ghost atoms to an infinite distance
+    //workspace->done_after[i] = Start_Index( i, far_nbrs );
+  }
+
+  H = workspace->H;
+  H->n = system->n;
+  Htop = 0;
+  num_bonds = 0;
+  num_hbonds = 0;
+  btop_i = btop_j = 0;
+  renbr = (data->step-data->prev_steps) % control->reneighbor == 0;
+  
+  for( i = 0; i < system->N; ++i ) {
+    atom_i = &(system->my_atoms[i]);
+    type_i  = atom_i->type;
+    start_i = Start_Index(i, far_nbrs);
+    end_i   = End_Index(i, far_nbrs);
+    btop_i = End_Index( i, bonds );
+    sbp_i = &(system->reax_param.sbp[type_i]);
+    
+    if( i < system->n ) {
+      local = 1;
+      cutoff = control->nonb_cut;
+    }
+    else {
+      local = 0;
+      cutoff = control->bond_cut;
+    }
+
+    ihb = -1;
+    ihb_top = -1;
+    if( local ) {
+      H->start[i] = Htop;
+      H->entries[Htop].j = i;
+      H->entries[Htop].val = sbp_i->eta;
+      ++Htop;
+
+      if( control->hbond_cut > 0 ) {
+	ihb = sbp_i->p_hbond;
+	if( ihb == 1 )
+	  ihb_top = End_Index( atom_i->Hindex, hbonds );
+	else ihb_top = -1;
+      }
+    } 
+
+    /* update i-j distance - check if j is within cutoff */
+    for( pj = start_i; pj < end_i; ++pj ) {
+      nbr_pj = &( far_nbrs->select.far_nbr_list[pj] );
+      j = nbr_pj->nbr;
+      atom_j = &(system->my_atoms[j]);
+      //fprintf( stderr, "%d%d i=%d x_i: %f %f %f,j=%d x_j: %f %f %f, d=%f\n",
+      //	 MIN(atom_i->orig_id, atom_j->orig_id), 
+      //	 MAX(atom_i->orig_id, atom_j->orig_id),
+      //	 i, atom_i->x[0], atom_i->x[1], atom_i->x[2], 
+      //	 j, atom_j->x[0], atom_j->x[1], atom_j->x[2], nbr_pj->d );
+      if( renbr ) { 
+	if(nbr_pj->d <= cutoff)
+	  flag = 1;
+	else flag = 0;
+      }
+      else{
+	nbr_pj->dvec[0] = atom_j->x[0] - atom_i->x[0];
+	nbr_pj->dvec[1] = atom_j->x[1] - atom_i->x[1];
+	nbr_pj->dvec[2] = atom_j->x[2] - atom_i->x[2];
+	nbr_pj->d = rvec_Norm_Sqr( nbr_pj->dvec );
+	if( nbr_pj->d <= SQR(cutoff) ) {
+	  nbr_pj->d = sqrt(nbr_pj->d);
+	  flag = 1;
+	}
+	else {
+	  flag = 0;
+	}
+      }
+      
+      if( flag ){	
+	type_j = atom_j->type;
+	r_ij = nbr_pj->d;
+	sbp_j = &(system->reax_param.sbp[type_j]);
+	twbp = &(system->reax_param.tbp[type_i][type_j]);
+	
+	if( local ) {
+	  /* H matrix entry */
+	  if( j < system->n || atom_i->orig_id < atom_j->orig_id ) {//tryQEq||1
+	    H->entries[Htop].j = j;
+	    //fprintf( stdout, "%d%d %d %d\n", 
+	    //     MIN(atom_i->orig_id, atom_j->orig_id), 
+	    //     MAX(atom_i->orig_id, atom_j->orig_id), 
+	    //     MIN(atom_i->orig_id, atom_j->orig_id), 
+	    //     MAX(atom_i->orig_id, atom_j->orig_id) ); 
+	    if( control->tabulate == 0 )
+	      H->entries[Htop].val = Compute_H(r_ij,twbp->gamma,workspace->Tap);
+	    else H->entries[Htop].val = Compute_tabH(r_ij, type_i, type_j);
+	    ++Htop;
+	  }
+	
+	  /* hydrogen bond lists */ 
+	  if( control->hbond_cut > 0 && (ihb==1 || ihb==2) && 
+	      nbr_pj->d <= control->hbond_cut ) {
+	    // fprintf( stderr, "%d %d\n", atom1, atom2 );
+	    jhb = sbp_j->p_hbond;
+	    if( ihb == 1 && jhb == 2 ) {
+	      hbonds->select.hbond_list[ihb_top].nbr = j;
+	      hbonds->select.hbond_list[ihb_top].scl = 1;
+	      hbonds->select.hbond_list[ihb_top].ptr = nbr_pj;
+	      ++ihb_top;
+	      ++num_hbonds;
+	    }
+	    else if( j < system->n && ihb == 2 && jhb == 1 ) {
+	      jhb_top = End_Index( atom_j->Hindex, hbonds );
+	      hbonds->select.hbond_list[jhb_top].nbr = i;
+	      hbonds->select.hbond_list[jhb_top].scl = -1;
+	      hbonds->select.hbond_list[jhb_top].ptr = nbr_pj;
+	      Set_End_Index( atom_j->Hindex, jhb_top+1, hbonds );
+	      ++num_hbonds;
+	    }
+	  }
+	}
+	    
+	/* uncorrected bond orders */
+	if( //(workspace->bond_mark[i] < 3 || workspace->bond_mark[j] < 3) &&
+	    nbr_pj->d <= control->bond_cut &&
+	    BOp( workspace, bonds, control->bo_cut, 
+		 i , btop_i, nbr_pj, sbp_i, sbp_j, twbp ) ) {
+	  num_bonds += 2;
+	  ++btop_i;
+
+	  if( workspace->bond_mark[j] > workspace->bond_mark[i] + 1 )
+	    workspace->bond_mark[j] = workspace->bond_mark[i] + 1;
+	  else if( workspace->bond_mark[i] > workspace->bond_mark[j] + 1 ) {
+	    workspace->bond_mark[i] = workspace->bond_mark[j] + 1;
+	    //if( workspace->bond_mark[i] == 1000 )
+	    //  workspace->done_after[i] = pj;
+	  }
+	  //fprintf( stdout, "%d%d - %d(%d) %d(%d)\n", 
+	  //   i , j, i, workspace->bond_mark[i], j, workspace->bond_mark[j] );
+	}
+      }
+    }
+
+    Set_End_Index( i, btop_i, bonds );
+    if( local ) {
+      H->end[i] = Htop;
+      if( ihb == 1 )
+	Set_End_Index( atom_i->Hindex, ihb_top, hbonds );
+    }
+  }
+
+  //fprintf( stderr, "after the first init loop\n" );
+  /*for( i = system->n; i < system->N; ++i ) 
+    if( workspace->bond_mark[i] > 3 ) {
+      start_i = Start_Index(i, bonds);
+      end_i = End_Index(i, bonds);
+      num_bonds -= (end_i - start_i);
+      Set_End_Index(i, start_i, bonds ); 
+      }*/
+
+  /*for( i = system->n; i < system->N; ++i ) {
+    start_i = Start_Index(i, far_nbrs);
+    end_i = workspace->done_after[i];
+    
+    if( workspace->bond_mark[i] >= 2 && start_i < end_i ) {
+      atom_i = &(system->my_atoms[i]);
+      type_i = atom_i->type;
+      btop_i = End_Index( i, bonds );
+      sbp_i = &(system->reax_param.sbp[type_i]);
+      
+      for( pj = start_i; pj < end_i; ++pj ) {
+	nbr_pj = &( far_nbrs->select.far_nbr_list[pj] );
+	j = nbr_pj->nbr;
+	
+	if( workspace->bond_mark[j] >= 2 && nbr_pj->d <= control->bond_cut ) {
+	  atom_j = &(system->my_atoms[j]);
+	  type_j = atom_j->type;
+	  sbp_j = &(system->reax_param.sbp[type_j]);
+	  twbp = &(system->reax_param.tbp[type_i][type_j]);
+	  
+	  if( BOp( workspace, bonds, control->bo_cut, 
+		   i , btop_i, nbr_pj, sbp_i, sbp_j, twbp ) ) {
+	    num_bonds += 2;
+	    ++btop_i;
+
+	    if( workspace->bond_mark[j] > workspace->bond_mark[i] + 1 )
+	      workspace->bond_mark[j] = workspace->bond_mark[i] + 1;
+	    else if( workspace->bond_mark[i] > workspace->bond_mark[j] + 1 )
+	      workspace->bond_mark[i] = workspace->bond_mark[j] + 1;
+
+	    //fprintf( stdout, "%d%d - %d(%d) %d(%d) new\n", 
+	    // i , j, i, workspace->bond_mark[i], j, workspace->bond_mark[j] );
+	  }
+	}
+      }
+      Set_End_Index( i, btop_i, bonds );
+    }
+    }*/
+  
+  workspace->realloc.Htop = Htop;
+  workspace->realloc.num_bonds = num_bonds;
+  workspace->realloc.num_hbonds = num_hbonds;
+
+#if defined(DEBUG_FOCUS)
+  fprintf( stderr, "p%d @ step%d: Htop = %d num_bonds = %d num_hbonds = %d\n", 
+	   system->my_rank, data->step, Htop, num_bonds, num_hbonds );
+  MPI_Barrier( comm );
+#endif
+#if defined( DEBUG )
+  Print_Bonds( system, bonds, "debugbonds.out" );  
+  Print_Bond_List2( system, bonds, "pbonds.out" );  
+  Print_Sparse_Matrix( system, H );
+  for( i = 0; i < H->n; ++i )
+    for( j = H->start[i]; j < H->end[i]; ++j )
+      fprintf( stderr, "%d %d %.15e\n", 
+	       MIN(system->my_atoms[i].orig_id, 
+		   system->my_atoms[H->entries[j].j].orig_id),
+	       MAX(system->my_atoms[i].orig_id, 
+		   system->my_atoms[H->entries[j].j].orig_id),
+	       H->entries[j].val );
+#endif
+
+  Validate_Lists( system, workspace, lists, data->step, 
+		  system->n, system->N, system->numH, comm );
+}
+
+
+void Init_Forces_noQEq( reax_system *system, control_params *control, 
+			simulation_data *data, storage *workspace, 
+			reax_list **lists, output_controls *out_control, 
+			MPI_Comm comm ) {
+  int i, j, pj;
+  int start_i, end_i;
+  int type_i, type_j;
+  int btop_i, btop_j, num_bonds, num_hbonds;
+  int ihb, jhb, ihb_top, jhb_top;
+  int local, flag, renbr;
+  real r_ij, cutoff;
+  reax_list *far_nbrs, *bonds, *hbonds;
+  single_body_parameters *sbp_i, *sbp_j;
+  two_body_parameters *twbp;
+  far_neighbor_data *nbr_pj;
+  reax_atom *atom_i, *atom_j;
+
+  far_nbrs = *lists + FAR_NBRS;
+  bonds = *lists + BONDS;
+  hbonds = *lists + HBONDS;
+
+  for( i = 0; i < system->n; ++i )
+    workspace->bond_mark[i] = 0;
+  for( i = system->n; i < system->N; ++i ) {
+    workspace->bond_mark[i] = 1000; // put ghost atoms to an infinite distance
+    //workspace->done_after[i] = Start_Index( i, far_nbrs );
+  }
+
+  num_bonds = 0;
+  num_hbonds = 0;
+  btop_i = btop_j = 0;
+  renbr = (data->step-data->prev_steps) % control->reneighbor == 0;
+  
+  for( i = 0; i < system->N; ++i ) {
+    atom_i = &(system->my_atoms[i]);
+    type_i  = atom_i->type;
+    start_i = Start_Index(i, far_nbrs);
+    end_i   = End_Index(i, far_nbrs);
+    btop_i = End_Index( i, bonds );
+    sbp_i = &(system->reax_param.sbp[type_i]);
+    
+    if( i < system->n ) {
+      local = 1;
+      cutoff = MAX( control->hbond_cut, control->bond_cut );
+    }
+    else {
+      local = 0;
+      cutoff = control->bond_cut;
+    }
+
+    ihb = -1;
+    ihb_top = -1;
+    if( local && control->hbond_cut > 0 ) {
+      ihb = sbp_i->p_hbond;
+      if( ihb == 1 )
+	ihb_top = End_Index( atom_i->Hindex, hbonds );
+      else ihb_top = -1;
+    }
+
+    /* update i-j distance - check if j is within cutoff */
+    for( pj = start_i; pj < end_i; ++pj ) {
+      nbr_pj = &( far_nbrs->select.far_nbr_list[pj] );
+      j = nbr_pj->nbr;
+      atom_j = &(system->my_atoms[j]);
+      
+      if( renbr ) { 
+	if( nbr_pj->d <= cutoff )
+	  flag = 1;
+	else flag = 0;
+      }
+      else{
+	nbr_pj->dvec[0] = atom_j->x[0] - atom_i->x[0];
+	nbr_pj->dvec[1] = atom_j->x[1] - atom_i->x[1];
+	nbr_pj->dvec[2] = atom_j->x[2] - atom_i->x[2];
+	nbr_pj->d = rvec_Norm_Sqr( nbr_pj->dvec );
+	if( nbr_pj->d <= SQR(cutoff) ) {
+	  nbr_pj->d = sqrt(nbr_pj->d);
+	  flag = 1;
+	}
+	else {
+	  flag = 0;
+	}
+      }
+      
+      if( flag ) {
+	type_j = atom_j->type;
+	r_ij = nbr_pj->d;
+	sbp_j = &(system->reax_param.sbp[type_j]);
+	twbp = &(system->reax_param.tbp[type_i][type_j]);
+	
+	if( local ) {
+	  /* hydrogen bond lists */ 
+	  if( control->hbond_cut > 0 && (ihb==1 || ihb==2) && 
+	      nbr_pj->d <= control->hbond_cut ) {
+	    // fprintf( stderr, "%d %d\n", atom1, atom2 );
+	    jhb = sbp_j->p_hbond;
+	    if( ihb == 1 && jhb == 2 ) {
+	      hbonds->select.hbond_list[ihb_top].nbr = j;
+	      hbonds->select.hbond_list[ihb_top].scl = 1;
+	      hbonds->select.hbond_list[ihb_top].ptr = nbr_pj;
+	      ++ihb_top;
+	      ++num_hbonds;
+	    }
+	    else if( j < system->n && ihb == 2 && jhb == 1 ) {
+	      jhb_top = End_Index( atom_j->Hindex, hbonds );
+	      hbonds->select.hbond_list[jhb_top].nbr = i;
+	      hbonds->select.hbond_list[jhb_top].scl = -1;
+	      hbonds->select.hbond_list[jhb_top].ptr = nbr_pj;
+	      Set_End_Index( atom_j->Hindex, jhb_top+1, hbonds );
+	      ++num_hbonds;
+	    }
+	  }
+	}
+	    
+	
+	/* uncorrected bond orders */
+	if( //(workspace->bond_mark[i] < 3 || workspace->bond_mark[j] < 3) &&
+	    nbr_pj->d <= control->bond_cut &&
+	    BOp( workspace, bonds, control->bo_cut, 
+		 i , btop_i, nbr_pj, sbp_i, sbp_j, twbp ) ) {
+	  num_bonds += 2;
+	  ++btop_i;
+
+	  if( workspace->bond_mark[j] > workspace->bond_mark[i] + 1 )
+	    workspace->bond_mark[j] = workspace->bond_mark[i] + 1;
+	  else if( workspace->bond_mark[i] > workspace->bond_mark[j] + 1 ) {
+	    workspace->bond_mark[i] = workspace->bond_mark[j] + 1;
+	    //if( workspace->bond_mark[i] == 1000 )
+	    //  workspace->done_after[i] = pj;
+	  }
+	  //fprintf( stdout, "%d%d - %d(%d) %d(%d)\n", 
+	  //   i , j, i, workspace->bond_mark[i], j, workspace->bond_mark[j] );
+	}
+      }
+    }
+
+    Set_End_Index( i, btop_i, bonds );
+    if( local && ihb == 1 )
+      Set_End_Index( atom_i->Hindex, ihb_top, hbonds );
+  }
+
+  /*for( i = system->n; i < system->N; ++i ) 
+    if( workspace->bond_mark[i] > 3 ) {
+      start_i = Start_Index(i, bonds);
+      end_i = End_Index(i, bonds);
+      num_bonds -= (end_i - start_i);
+      Set_End_Index(i, start_i, bonds ); 
+      }*/
+  
+  workspace->realloc.num_bonds = num_bonds;
+  workspace->realloc.num_hbonds = num_hbonds;
+
+#if defined(DEBUG_FOCUS)
+  fprintf( stderr, "p%d @ step%d: num_bonds = %d num_hbonds = %d\n", 
+	   system->my_rank, data->step, num_bonds, num_hbonds );
+  MPI_Barrier( comm );
+#endif
+#if defined( DEBUG )
+  Print_Bonds( system, bonds, "debugbonds.out" );  
+  Print_Bond_List2( system, bonds, "pbonds.out" );  
+#endif
+
+  Validate_Lists( system, workspace, lists, data->step, 
+		  system->n, system->N, system->numH, comm );
+}
+
+
+void Estimate_Storages( reax_system *system, control_params *control, 
+			reax_list **lists, int *Htop, int *hb_top, 
+			int *bond_top, int *num_3body, MPI_Comm comm ) 
+{
+  int i, j, pj;
+  int start_i, end_i;
+  int type_i, type_j;
+  int ihb, jhb;
+  int local;
+  real cutoff;
+  real r_ij, r2;
+  real C12, C34, C56;
+  real BO, BO_s, BO_pi, BO_pi2;
+  reax_list *far_nbrs;
+  single_body_parameters *sbp_i, *sbp_j;
+  two_body_parameters *twbp;
+  far_neighbor_data *nbr_pj;
+  reax_atom *atom_i, *atom_j;
+
+  far_nbrs = *lists + FAR_NBRS;
+  *Htop = 0;
+  memset( hb_top, 0, sizeof(int) * system->local_cap );
+  memset( bond_top, 0, sizeof(int) * system->total_cap );
+  *num_3body = 0;
+
+  for( i = 0; i < system->N; ++i ) {
+    atom_i = &(system->my_atoms[i]);
+    type_i  = atom_i->type;
+    start_i = Start_Index(i, far_nbrs);
+    end_i   = End_Index(i, far_nbrs);
+    sbp_i = &(system->reax_param.sbp[type_i]);
+    
+    if( i < system->n ) {
+      local = 1;
+      cutoff = control->nonb_cut;
+      ++(*Htop);
+      ihb = sbp_i->p_hbond;
+    }
+    else {
+      local = 0;
+      cutoff = control->bond_cut;
+      ihb = -1;
+    }
+    
+    for( pj = start_i; pj < end_i; ++pj ) {
+      nbr_pj = &( far_nbrs->select.far_nbr_list[pj] );
+      j = nbr_pj->nbr;
+      atom_j = &(system->my_atoms[j]);
+
+      if(nbr_pj->d <= cutoff) {
+	type_j = system->my_atoms[j].type;
+	r_ij = nbr_pj->d;
+	sbp_j = &(system->reax_param.sbp[type_j]);
+	twbp = &(system->reax_param.tbp[type_i][type_j]);
+	
+	if( local ) {
+	  if( j < system->n || atom_i->orig_id < atom_j->orig_id ) //tryQEq ||1
+	    ++(*Htop);
+	
+	  /* hydrogen bond lists */ 
+	  if( control->hbond_cut > 0.1 && (ihb==1 || ihb==2) && 
+	      nbr_pj->d <= control->hbond_cut ) {
+	    jhb = sbp_j->p_hbond;
+	    if( ihb == 1 && jhb == 2 )
+	      ++hb_top[i];
+	    else if( j < system->n && ihb == 2 && jhb == 1 ) 
+	      ++hb_top[j];
+	  }
+	}
+	    
+	/* uncorrected bond orders */
+	if( nbr_pj->d <= control->bond_cut ) {
+	  r2 = SQR(r_ij);
+	  	  
+	  if( sbp_i->r_s > 0.0 && sbp_j->r_s > 0.0) {
+	    C12 = twbp->p_bo1 * pow( r_ij / twbp->r_s, twbp->p_bo2 );
+	    BO_s = (1.0 + control->bo_cut) * exp( C12 );
+	  }
+	  else BO_s = C12 = 0.0;
+	  
+	  if( sbp_i->r_pi > 0.0 && sbp_j->r_pi > 0.0) {
+	    C34 = twbp->p_bo3 * pow( r_ij / twbp->r_p, twbp->p_bo4 );
+	    BO_pi = exp( C34 );
+	  }
+	  else BO_pi = C34 = 0.0;
+	  
+	  if( sbp_i->r_pi_pi > 0.0 && sbp_j->r_pi_pi > 0.0) {
+	    C56 = twbp->p_bo5 * pow( r_ij / twbp->r_pp, twbp->p_bo6 );	
+	    BO_pi2= exp( C56 );
+	  }
+	  else BO_pi2 = C56 = 0.0;
+	  
+	  /* Initially BO values are the uncorrected ones, page 1 */
+	  BO = BO_s + BO_pi + BO_pi2;
+
+	  if( BO >= control->bo_cut ) {
+	    ++bond_top[i];
+	    ++bond_top[j];
+	  }
+	}
+      }
+    }
+  }
+
+  *Htop = (int)(MAX( *Htop * SAFE_ZONE, MIN_CAP * MIN_HENTRIES ));
+  for( i = 0; i < system->n; ++i )
+    hb_top[i] = (int)(MAX( hb_top[i] * SAFER_ZONE, MIN_HBONDS ));
+
+  for( i = 0; i < system->N; ++i ) {
+    *num_3body += SQR(bond_top[i]);
+    //if( i < system->n )
+    bond_top[i] = MAX( bond_top[i] * 2, MIN_BONDS );
+      //else bond_top[i] = MAX_BONDS;
+  }
+
+#if defined(DEBUG_FOCUS)
+  fprintf( stderr, "p%d @ estimate storages: Htop = %d, num_3body = %d\n", 
+	   system->my_rank, *Htop, *num_3body );
+  MPI_Barrier( comm );
+#endif
+}
+
+
+void Compute_Forces( reax_system *system, control_params *control, 
+		     simulation_data *data, storage *workspace, 
+		     reax_list **lists, output_controls *out_control, 
+		     mpi_datatypes *mpi_data )
+{
+  MPI_Comm comm;
+  int qeq_flag;
+#if defined(LOG_PERFORMANCE)
+  real t_start = 0;
+
+  //MPI_Barrier( mpi_data->world );
+  if( system->my_rank == MASTER_NODE )
+    t_start = Get_Time( );
+#endif
+
+  comm = mpi_data->world;
+  /********* init forces ************/
+#if defined(PURE_REAX)
+  if( control->qeq_freq && (data->step-data->prev_steps)%control->qeq_freq==0 )
+    qeq_flag = 1;
+  else qeq_flag = 0;
+#elif defined(LAMMPS_REAX)
+  qeq_flag = 0;
+#endif
+
+  if( qeq_flag )
+    Init_Forces( system, control, data, workspace, lists, out_control, comm );
+  else
+    Init_Forces_noQEq( system, control, data, workspace, 
+		       lists, out_control, comm );
+
+#if defined(LOG_PERFORMANCE)
+  //MPI_Barrier( mpi_data->world );
+  if( system->my_rank == MASTER_NODE )
+    Update_Timing_Info( &t_start, &(data->timing.init_forces) );
+#endif
+
+
+  /********* bonded interactions ************/
+  Compute_Bonded_Forces( system, control, data, workspace, 
+			 lists, out_control, mpi_data->world );
+
+#if defined(LOG_PERFORMANCE)
+  //MPI_Barrier( mpi_data->world );
+  if( system->my_rank == MASTER_NODE )
+    Update_Timing_Info( &t_start, &(data->timing.bonded) );
+#endif
+#if defined(DEBUG_FOCUS)
+  fprintf( stderr, "p%d @ step%d: completed bonded\n", 
+	   system->my_rank, data->step );
+  MPI_Barrier( mpi_data->world );
+#endif
+
+
+  /**************** qeq ************************/
+#if defined(PURE_REAX)
+  if( qeq_flag )
+    QEq( system, control, data, workspace, out_control, mpi_data );
+
+#if defined(LOG_PERFORMANCE)
+  //MPI_Barrier( mpi_data->world );
+  if( system->my_rank == MASTER_NODE ) 
+    Update_Timing_Info( &t_start, &(data->timing.qEq) );
+#endif
+#if defined(DEBUG_FOCUS)
+  fprintf(stderr, "p%d @ step%d: qeq completed\n", system->my_rank, data->step);
+  MPI_Barrier( mpi_data->world );
+#endif
+#endif //PURE_REAX
+
+
+  /********* nonbonded interactions ************/
+  Compute_NonBonded_Forces( system, control, data, workspace, 
+			    lists, out_control, mpi_data->world );
+
+#if defined(LOG_PERFORMANCE)
+  //MPI_Barrier( mpi_data->world );
+  if( system->my_rank == MASTER_NODE )
+    Update_Timing_Info( &t_start, &(data->timing.nonb) );
+#endif
+#if defined(DEBUG_FOCUS)
+  fprintf( stderr, "p%d @ step%d: nonbonded forces completed\n", 
+	   system->my_rank, data->step );
+  MPI_Barrier( mpi_data->world );
+#endif
+
+
+  /*********** total force ***************/
+  Compute_Total_Force( system, control, data, workspace, lists, mpi_data );
+
+#if defined(LOG_PERFORMANCE)
+  //MPI_Barrier( mpi_data->world );
+  if( system->my_rank == MASTER_NODE )
+    Update_Timing_Info( &t_start, &(data->timing.bonded) );
+#endif
+#if defined(DEBUG_FOCUS)
+  fprintf( stderr, "p%d @ step%d: total forces computed\n", 
+	   system->my_rank, data->step );
+  //Print_Total_Force( system, data, workspace );
+  MPI_Barrier( mpi_data->world );
+#endif
+
+#if defined(TEST_FORCES)
+  Print_Force_Files( system, control, data, workspace, 
+		     lists, out_control, mpi_data );
+#endif
+}
diff --git a/src/USER-REAXC/reaxc_forces.h b/src/USER-REAXC/reaxc_forces.h
new file mode 100644
index 0000000000..6723bc9660
--- /dev/null
+++ b/src/USER-REAXC/reaxc_forces.h
@@ -0,0 +1,35 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#ifndef __FORCES_H_
+#define __FORCES_H_
+
+#include "reaxc_types.h"
+#include "reaxc_defs.h"
+
+extern interaction_function Interaction_Functions[NUM_INTRS];
+
+void Init_Force_Functions( control_params* );
+void Compute_Forces( reax_system*, control_params*, simulation_data*, 
+		     storage*, reax_list**, output_controls*, mpi_datatypes* );
+void Estimate_Storages( reax_system*, control_params*, reax_list**, 
+			int*, int*, int*, int*, MPI_Comm );
+#endif
diff --git a/src/USER-REAXC/reaxc_hydrogen_bonds.cpp b/src/USER-REAXC/reaxc_hydrogen_bonds.cpp
new file mode 100644
index 0000000000..86013abcbd
--- /dev/null
+++ b/src/USER-REAXC/reaxc_hydrogen_bonds.cpp
@@ -0,0 +1,220 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#include "reaxc_types.h"
+#if defined(PURE_REAX)
+#include "hydrogen_bonds.h"
+#include "bond_orders.h"
+#include "list.h"
+#include "valence_angles.h"
+#include "vector.h"
+#elif defined(LAMMPS_REAX)
+#include "reaxc_hydrogen_bonds.h"
+#include "reaxc_bond_orders.h"
+#include "reaxc_list.h"
+#include "reaxc_valence_angles.h"
+#include "reaxc_vector.h"
+#endif
+
+
+void Hydrogen_Bonds( reax_system *system, control_params *control, 
+		     simulation_data *data, storage *workspace, 
+		     reax_list **lists, output_controls *out_control )
+{
+  int  i, j, k, pi, pk;
+  int  type_i, type_j, type_k;
+  int  start_j, end_j, hb_start_j, hb_end_j;
+  int  hblist[MAX_BONDS];
+  int  itr, top;
+  int  num_hb_intrs = 0;
+  ivec rel_jk;
+  real r_ij, r_jk, theta, cos_theta, sin_xhz4, cos_xhz1, sin_theta2;
+  real e_hb, exp_hb2, exp_hb3, CEhb1, CEhb2, CEhb3;
+  rvec dcos_theta_di, dcos_theta_dj, dcos_theta_dk;
+  rvec dvec_jk, force, ext_press;
+  // rtensor temp_rtensor, total_rtensor;
+  hbond_parameters *hbp;
+  bond_order_data *bo_ij;
+  bond_data *pbond_ij;
+  far_neighbor_data *nbr_jk;
+  reax_list *bonds, *hbonds;
+  bond_data *bond_list;
+  hbond_data *hbond_list;
+
+  bonds = (*lists) + BONDS;
+  bond_list = bonds->select.bond_list;
+  hbonds = (*lists) + HBONDS;
+  hbond_list = hbonds->select.hbond_list;
+
+  /* loops below discover the Hydrogen bonds between i-j-k triplets.
+     here j is H atom and there has to be some bond between i and j.
+     Hydrogen bond is between j and k.
+     so in this function i->X, j->H, k->Z when we map 
+     variables onto the ones in the handout.*/
+  for( j = 0; j < system->n; ++j )
+    /* j has to be of type H */
+    if( system->reax_param.sbp[system->my_atoms[j].type].p_hbond == 1 ) {
+      /*set j's variables */
+      type_j     = system->my_atoms[j].type;
+      start_j    = Start_Index(j, bonds);
+      end_j      = End_Index(j, bonds);
+      hb_start_j = Start_Index( system->my_atoms[j].Hindex, hbonds );
+      hb_end_j   = End_Index( system->my_atoms[j].Hindex, hbonds );
+      
+      top = 0;
+      for( pi = start_j; pi < end_j; ++pi )  {
+	pbond_ij = &( bond_list[pi] );
+	i = pbond_ij->nbr;
+	bo_ij = &(pbond_ij->bo_data);
+	type_i = system->my_atoms[i].type;
+	
+	if( system->reax_param.sbp[type_i].p_hbond == 2 && 
+	    bo_ij->BO >= HB_THRESHOLD )
+	  hblist[top++] = pi;
+      }
+      
+      // fprintf( stderr, "j: %d, top: %d, hb_start_j: %d, hb_end_j:%d\n", 
+      //          j, top, hb_start_j, hb_end_j );
+      
+      for( pk = hb_start_j; pk < hb_end_j; ++pk ) {
+	/* set k's varibles */
+	k = hbond_list[pk].nbr;
+	type_k = system->my_atoms[k].type;
+	nbr_jk = hbond_list[pk].ptr;
+	r_jk = nbr_jk->d;
+	rvec_Scale( dvec_jk, hbond_list[pk].scl, nbr_jk->dvec );
+	    
+	for( itr = 0; itr < top; ++itr ) {
+	  pi = hblist[itr];
+	  pbond_ij = &( bonds->select.bond_list[pi] );
+	  i = pbond_ij->nbr;
+			  
+	  if( system->my_atoms[i].orig_id != system->my_atoms[k].orig_id ) {
+	    bo_ij = &(pbond_ij->bo_data);
+	    type_i = system->my_atoms[i].type;
+	    r_ij = pbond_ij->d;	     
+	    hbp = &(system->reax_param.hbp[ type_i ][ type_j ][ type_k ]);
+	    ++num_hb_intrs;
+
+	    Calculate_Theta( pbond_ij->dvec, pbond_ij->d, dvec_jk, r_jk,
+			     &theta, &cos_theta );
+	    /* the derivative of cos(theta) */
+	    Calculate_dCos_Theta( pbond_ij->dvec, pbond_ij->d, dvec_jk, r_jk,
+				  &dcos_theta_di, &dcos_theta_dj, 
+				  &dcos_theta_dk );
+		    
+	    /* hyrogen bond energy*/
+	    sin_theta2 = sin( theta/2.0 );
+	    sin_xhz4 = SQR(sin_theta2);
+	    sin_xhz4 *= sin_xhz4;
+	    cos_xhz1 = ( 1.0 - cos_theta );
+	    exp_hb2 = exp( -hbp->p_hb2 * bo_ij->BO );
+	    exp_hb3 = exp( -hbp->p_hb3 * ( hbp->r0_hb / r_jk + 
+					   r_jk / hbp->r0_hb - 2.0 ) );
+
+	    data->my_en.e_hb += e_hb = 
+	      hbp->p_hb1 * (1.0 - exp_hb2) * exp_hb3 * sin_xhz4;
+
+	    CEhb1 = hbp->p_hb1 * hbp->p_hb2 * exp_hb2 * exp_hb3 * sin_xhz4;
+	    CEhb2 = -hbp->p_hb1/2.0 * (1.0 - exp_hb2) * exp_hb3 * cos_xhz1;
+	    CEhb3 = -hbp->p_hb3 * 
+	      (-hbp->r0_hb / SQR(r_jk) + 1.0 / hbp->r0_hb) * e_hb;
+		    
+	    /*fprintf( stdout, 
+	      "%6d%6d%6d%12.6f%12.6f%12.6f%12.6f%12.6f%12.6f%12.6f%12.6f%12.6f\n",
+	      system->my_atoms[i].orig_id, system->my_atoms[j].orig_id, 
+	      system->my_atoms[k].orig_id, 
+	      r_jk, theta, hbp->p_hb1, exp_hb2, hbp->p_hb3, hbp->r0_hb, 
+	      exp_hb3, sin_xhz4, e_hb ); */
+	    
+	    /* hydrogen bond forces */
+	    bo_ij->Cdbo += CEhb1; // dbo term
+
+	    if( control->virial == 0 ) {
+	      // dcos terms
+	      rvec_ScaledAdd( workspace->f[i], +CEhb2, dcos_theta_di ); 
+	      rvec_ScaledAdd( workspace->f[j], +CEhb2, dcos_theta_dj );
+	      rvec_ScaledAdd( workspace->f[k], +CEhb2, dcos_theta_dk );
+	      // dr terms
+	      rvec_ScaledAdd( workspace->f[j], -CEhb3/r_jk, dvec_jk ); 
+	      rvec_ScaledAdd( workspace->f[k], +CEhb3/r_jk, dvec_jk );
+	    }
+	    else {
+	      /* for pressure coupling, terms that are not related to bond order
+		 derivatives are added directly into pressure vector/tensor */
+	      rvec_Scale( force, +CEhb2, dcos_theta_di ); // dcos terms
+	      rvec_Add( workspace->f[i], force );
+	      rvec_iMultiply( ext_press, pbond_ij->rel_box, force );
+	      rvec_ScaledAdd( data->my_ext_press, 1.0, ext_press );
+
+	      rvec_ScaledAdd( workspace->f[j], +CEhb2, dcos_theta_dj );
+	      
+	      ivec_Scale( rel_jk, hbond_list[pk].scl, nbr_jk->rel_box );
+	      rvec_Scale( force, +CEhb2, dcos_theta_dk );
+	      rvec_Add( workspace->f[k], force );
+	      rvec_iMultiply( ext_press, rel_jk, force );
+	      rvec_ScaledAdd( data->my_ext_press, 1.0, ext_press );
+	      // dr terms
+	      rvec_ScaledAdd( workspace->f[j], -CEhb3/r_jk, dvec_jk ); 
+
+	      rvec_Scale( force, CEhb3/r_jk, dvec_jk );
+	      rvec_Add( workspace->f[k], force );
+	      rvec_iMultiply( ext_press, rel_jk, force );
+	      rvec_ScaledAdd( data->my_ext_press, 1.0, ext_press );
+	    }
+
+#ifdef TEST_ENERGY
+	    /* fprintf( out_control->ehb, 
+	       "%24.15e%24.15e%24.15e\n%24.15e%24.15e%24.15e\n%24.15e%24.15e%24.15e\n",
+	       dcos_theta_di[0], dcos_theta_di[1], dcos_theta_di[2], 
+	       dcos_theta_dj[0], dcos_theta_dj[1], dcos_theta_dj[2], 
+	       dcos_theta_dk[0], dcos_theta_dk[1], dcos_theta_dk[2]);
+	       fprintf( out_control->ehb, "%24.15e%24.15e%24.15e\n",
+	       CEhb1, CEhb2, CEhb3 ); */
+	    fprintf( out_control->ehb, 
+		     //"%6d%6d%6d%24.15e%24.15e%24.15e%24.15e%24.15e\n",
+		     "%6d%6d%6d%12.4f%12.4f%12.4f%12.4f%12.4f\n",
+		     system->my_atoms[i].orig_id, system->my_atoms[j].orig_id, 
+		     system->my_atoms[k].orig_id, 
+		     r_jk, theta, bo_ij->BO, e_hb, data->my_en.e_hb );       
+#endif
+#ifdef TEST_FORCES
+	    Add_dBO( system, lists, j, pi, +CEhb1, workspace->f_hb ); //dbo term
+	    // dcos terms
+	    rvec_ScaledAdd( workspace->f_hb[i], +CEhb2, dcos_theta_di );
+	    rvec_ScaledAdd( workspace->f_hb[j], +CEhb2, dcos_theta_dj );
+	    rvec_ScaledAdd( workspace->f_hb[k], +CEhb2, dcos_theta_dk );
+	    // dr terms
+	    rvec_ScaledAdd( workspace->f_hb[j], -CEhb3/r_jk, dvec_jk ); 
+	    rvec_ScaledAdd( workspace->f_hb[k], +CEhb3/r_jk, dvec_jk );
+#endif
+	  }
+	}
+      }
+    }
+
+#if defined(DEBUG)
+  fprintf( stderr, "Number of hydrogen bonds: %d\n", num_hb_intrs );
+  fprintf( stderr, "Hydrogen Bond Energy: %g\n", data->my_en.e_hb );
+  fprintf( stderr, "hydbonds: ext_press (%24.15e %24.15e %24.15e)\n", 
+	   data->ext_press[0], data->ext_press[1], data->ext_press[2] );
+#endif
+}
diff --git a/src/USER-REAXC/reaxc_hydrogen_bonds.h b/src/USER-REAXC/reaxc_hydrogen_bonds.h
new file mode 100644
index 0000000000..bb26928d62
--- /dev/null
+++ b/src/USER-REAXC/reaxc_hydrogen_bonds.h
@@ -0,0 +1,30 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#ifndef __HBONDS_H_
+#define __HBONDS_H_
+
+#include "reaxc_types.h"
+
+void Hydrogen_Bonds( reax_system*, control_params*, simulation_data*,
+		     storage*, reax_list**, output_controls* );
+
+#endif
diff --git a/src/USER-REAXC/reaxc_init_md.cpp b/src/USER-REAXC/reaxc_init_md.cpp
new file mode 100644
index 0000000000..52466eaec9
--- /dev/null
+++ b/src/USER-REAXC/reaxc_init_md.cpp
@@ -0,0 +1,916 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#include "reaxc_types.h"
+#if defined(PURE_REAX)
+#include "init_md.h"
+#include "allocate.h"
+#include "box.h"
+#include "comm_tools.h"
+#include "forces.h"
+#include "grid.h"
+#include "integrate.h"
+#include "io_tools.h"
+#include "list.h"
+#include "lookup.h"
+#include "neighbors.h"
+#include "random.h"
+#include "reset_tools.h"
+#include "system_props.h"
+#include "tool_box.h"
+#include "vector.h"
+#elif defined(LAMMPS_REAX)
+#include "reaxc_init_md.h"
+#include "reaxc_allocate.h"
+#include "reaxc_forces.h"
+#include "reaxc_io_tools.h"
+#include "reaxc_list.h"
+#include "reaxc_lookup.h"
+#include "reaxc_reset_tools.h"
+#include "reaxc_system_props.h"
+#include "reaxc_tool_box.h"
+#include "reaxc_vector.h"
+#endif
+
+
+#if defined(PURE_REAX)
+/************************ initialize system ************************/
+int Reposition_Atoms( reax_system *system, control_params *control, 
+		      simulation_data *data, mpi_datatypes *mpi_data, 
+		      char *msg )
+{
+  int   i;
+  rvec  dx;
+  
+  /* reposition atoms */
+  if( control->reposition_atoms == 0 ) { //fit atoms to periodic box
+    rvec_MakeZero( dx );
+  }
+  else if( control->reposition_atoms == 1 ) { //put center of mass to center
+    rvec_Scale( dx, 0.5, system->big_box.box_norms );
+    rvec_ScaledAdd( dx, -1., data->xcm );
+  }
+  else if( control->reposition_atoms == 2 ) { //put center of mass to origin
+    rvec_Scale( dx, -1., data->xcm );
+  }
+  else {
+    strcpy( msg, "reposition_atoms: invalid option" );
+    return FAILURE;
+  }
+  
+  for( i = 0; i < system->n; ++i )
+    // Inc_on_T3_Gen( system->my_atoms[i].x, dx, &(system->big_box) );
+    rvec_Add( system->my_atoms[i].x, dx );
+
+  return SUCCESS;
+}
+
+
+
+void Generate_Initial_Velocities( reax_system *system, real T )
+{
+  int i;
+  real m, scale, norm;
+  
+  
+  if( T <= 0.1 ) {
+    for( i = 0; i < system->n; i++ )
+      rvec_MakeZero( system->my_atoms[i].v );
+  }
+  else {
+    Randomize();
+    
+    for( i = 0; i < system->n; i++ ) {
+      rvec_Random( system->my_atoms[i].v );
+      
+      norm = rvec_Norm_Sqr( system->my_atoms[i].v );
+      m = system->reax_param.sbp[ system->my_atoms[i].type ].mass;
+      scale = sqrt( m * norm / (3.0 * K_B * T) );
+      
+      rvec_Scale( system->my_atoms[i].v, 1./scale, system->my_atoms[i].v );
+      
+      // fprintf( stderr, "v = %f %f %f\n", 
+      // system->my_atoms[i].v[0], 
+      // system->my_atoms[i].v[1], 
+      // system->my_atoms[i].v[2] );      
+      
+      // fprintf( stderr, "scale = %f\n", scale );
+      // fprintf( stderr, "v = %f %f %f\n", 
+      // system->my_atoms[i].v[0], 
+      // system->my_atoms[i].v[1], 
+      // system->my_atoms[i].v[2] );
+    }
+  }
+}
+
+
+int Init_System( reax_system *system, control_params *control, 
+		 simulation_data *data, storage *workspace, 
+		 mpi_datatypes *mpi_data, char *msg )
+{
+  int i;
+  reax_atom *atom;
+  int nrecv[MAX_NBRS];
+  
+  Setup_New_Grid( system, control, mpi_data->world );
+#if defined(DEBUG_FOCUS)
+  fprintf( stderr, "p%d GRID:\n", system->my_rank );
+  Print_Grid( &(system->my_grid), stderr );
+#endif
+  Bin_My_Atoms( system, &(workspace->realloc) );
+  Reorder_My_Atoms( system, workspace );
+
+  /* estimate N and total capacity */
+  for( i = 0; i < MAX_NBRS; ++i ) nrecv[i] = 0;
+  system->max_recved = 0;
+  system->N = SendRecv( system, mpi_data, mpi_data->boundary_atom_type, nrecv,
+			Estimate_Boundary_Atoms, Unpack_Estimate_Message, 1 );
+  system->total_cap = MAX( (int)(system->N * SAFE_ZONE), MIN_CAP );
+  Bin_Boundary_Atoms( system );
+
+  /* estimate numH and Hcap */
+  system->numH = 0;
+  if( control->hbond_cut > 0 )
+    for( i = 0; i < system->n; ++i ) {
+      atom = &(system->my_atoms[i]);
+      if( system->reax_param.sbp[ atom->type ].p_hbond == 1 )
+	atom->Hindex = system->numH++;
+      else atom->Hindex = -1;
+    }
+  system->Hcap = MAX( system->numH * SAFER_ZONE, MIN_CAP );
+
+  //Allocate_System( system, system->local_cap, system->total_cap, msg ); 
+#if defined(DEBUG_FOCUS)
+  fprintf( stderr, "p%d: n=%d local_cap=%d\n", 
+	   system->my_rank, system->n, system->local_cap );
+  fprintf( stderr, "p%d: N=%d total_cap=%d\n", 
+	   system->my_rank, system->N, system->total_cap );
+  fprintf( stderr, "p%d: numH=%d H_cap=%d\n", 
+	   system->my_rank, system->numH, system->Hcap );
+#endif
+ 
+  // if( Reposition_Atoms( system, control, data, mpi_data, msg ) == FAILURE )
+  //   return FAILURE;
+  
+  /* initialize velocities so that desired init T can be attained */
+  if( !control->restart || (control->restart && control->random_vel) )  
+    Generate_Initial_Velocities( system, control->T_init );
+  
+  return SUCCESS;
+}
+
+
+/************************ initialize simulation data ************************/
+int Init_Simulation_Data( reax_system *system, control_params *control, 
+			  simulation_data *data, mpi_datatypes *mpi_data, 
+			  char *msg )
+{
+  Reset_Simulation_Data( data, control->virial );
+
+  if( !control->restart )  
+    data->step = data->prev_steps = 0;
+
+  Compute_Total_Mass( system, data, mpi_data->comm_mesh3D );
+  Compute_Center_of_Mass( system, data, mpi_data, mpi_data->comm_mesh3D );    
+  Compute_Kinetic_Energy( system, data, mpi_data->comm_mesh3D );
+
+  switch( control->ensemble ){
+  case NVE:
+    data->N_f = 3 * system->bigN;
+    Evolve = Velocity_Verlet_NVE;
+    break;
+  
+  case bNVT:
+    data->N_f = 3 * system->bigN + 1;
+    Evolve = Velocity_Verlet_Berendsen_NVT;
+    break;
+  
+  case nhNVT:
+    fprintf( stderr, "WARNING: Nose-Hoover NVT is still under testing.\n" );
+    //return FAILURE;
+    data->N_f = 3 * system->bigN + 1;      
+    Evolve = Velocity_Verlet_Nose_Hoover_NVT_Klein;
+    if( !control->restart || (control->restart && control->random_vel) ) {
+      data->therm.G_xi = control->Tau_T * 
+	(2.0 * data->sys_en.e_kin - data->N_f * K_B * control->T );
+      data->therm.v_xi = data->therm.G_xi * control->dt;
+      data->therm.v_xi_old = 0;
+      data->therm.xi = 0;
+    }
+    break;
+        
+  case sNPT: /* Semi-Isotropic NPT */
+    data->N_f = 3 * system->bigN + 4;
+    Evolve = Velocity_Verlet_Berendsen_NPT;
+    if( !control->restart )
+      Reset_Pressures( data );
+    break;
+    
+  case iNPT: /* Isotropic NPT */
+    data->N_f = 3 * system->bigN + 2;
+    Evolve = Velocity_Verlet_Berendsen_NPT;
+    if( !control->restart )
+      Reset_Pressures( data );
+    break;
+  
+  case NPT: /* Anisotropic NPT */
+    strcpy( msg, "init_simulation_data: option not yet implemented" );
+    return FAILURE;
+    
+    data->N_f = 3 * system->bigN + 9;
+    Evolve = Velocity_Verlet_Berendsen_NPT;
+    /*if( !control->restart ) {
+      data->therm.G_xi = control->Tau_T * 
+      (2.0 * data->my_en.e_Kin - data->N_f * K_B * control->T );
+      data->therm.v_xi = data->therm.G_xi * control->dt;
+      data->iso_bar.eps = 0.33333 * log(system->box.volume);
+      data->inv_W = 1.0 / 
+      ( data->N_f * K_B * control->T * SQR(control->Tau_P) );
+      Compute_Pressure( system, control, data, out_control );
+      }*/
+    break;
+    
+  default:
+    strcpy( msg, "init_simulation_data: ensemble not recognized" );
+    return FAILURE;
+  }
+  
+  /* initialize the timer(s) */
+  MPI_Barrier( mpi_data->world );  // wait for everyone to come here
+  if( system->my_rank == MASTER_NODE ) {
+    data->timing.start = Get_Time( );
+#if defined(LOG_PERFORMANCE)
+    Reset_Timing( &data->timing );
+#endif
+  }
+  
+
+#if defined(DEBUG)
+      fprintf( stderr, "data->N_f: %8.3f\n", data->N_f );
+#endif
+  return SUCCESS;
+}
+
+#elif defined(LAMMPS_REAX)
+int Init_System( reax_system *system, control_params *control, char *msg )
+{
+  int i;
+  reax_atom *atom;
+
+  /* determine the local and total capacity */
+  system->local_cap = MAX( (int)(system->n * SAFE_ZONE), MIN_CAP );
+  system->total_cap = MAX( (int)(system->N * SAFE_ZONE), MIN_CAP );
+  
+  /* estimate numH and Hcap */
+  system->numH = 0;
+  if( control->hbond_cut > 0 )
+    for( i = 0; i < system->n; ++i ) {
+      atom = &(system->my_atoms[i]);
+      if( system->reax_param.sbp[ atom->type ].p_hbond == 1 )
+	atom->Hindex = system->numH++;
+      else atom->Hindex = -1;
+    }
+  system->Hcap = (int)(MAX( system->numH * SAFER_ZONE, MIN_CAP ));
+
+#if defined(DEBUG_FOCUS)
+  fprintf( stderr, "p%d: n=%d local_cap=%d\n", 
+	   system->my_rank, system->n, system->local_cap );
+  fprintf( stderr, "p%d: N=%d total_cap=%d\n", 
+	   system->my_rank, system->N, system->total_cap );
+  fprintf( stderr, "p%d: numH=%d H_cap=%d\n", 
+	   system->my_rank, system->numH, system->Hcap );
+#endif
+
+  return SUCCESS;
+}
+
+
+int Init_Simulation_Data( reax_system *system, control_params *control, 
+			  simulation_data *data, char *msg )
+{
+  Reset_Simulation_Data( data, control->virial );
+
+  /* initialize the timer(s) */
+  if( system->my_rank == MASTER_NODE ) {
+    data->timing.start = Get_Time( );
+#if defined(LOG_PERFORMANCE)
+    Reset_Timing( &data->timing );
+#endif
+  }
+
+  //if( !control->restart )  
+  data->step = data->prev_steps = 0;
+
+  return SUCCESS;
+}
+#endif
+
+
+
+/************************ initialize workspace ************************/
+/* Initialize Taper params */
+void Init_Taper( control_params *control,  storage *workspace, MPI_Comm comm )
+{
+  real d1, d7;
+  real swa, swa2, swa3;
+  real swb, swb2, swb3;
+
+  swa = control->nonb_low;
+  swb = control->nonb_cut;
+
+  if( fabs( swa ) > 0.01 )
+    fprintf( stderr, "Warning: non-zero lower Taper-radius cutoff\n" );
+  
+  if( swb < 0 ) {
+    fprintf( stderr, "Negative upper Taper-radius cutoff\n" );
+    MPI_Abort( comm,  INVALID_INPUT );
+  }
+  else if( swb < 5 )
+    fprintf( stderr, "Warning: very low Taper-radius cutoff: %f\n", swb );
+
+  d1 = swb - swa;
+  d7 = pow( d1, 7.0 );
+  swa2 = SQR( swa );
+  swa3 = CUBE( swa );
+  swb2 = SQR( swb );
+  swb3 = CUBE( swb );
+
+  workspace->Tap[7] =  20.0 / d7;
+  workspace->Tap[6] = -70.0 * (swa + swb) / d7;
+  workspace->Tap[5] =  84.0 * (swa2 + 3.0*swa*swb + swb2) / d7;
+  workspace->Tap[4] = -35.0 * (swa3 + 9.0*swa2*swb + 9.0*swa*swb2 + swb3 ) / d7;
+  workspace->Tap[3] = 140.0 * (swa3*swb + 3.0*swa2*swb2 + swa*swb3 ) / d7;
+  workspace->Tap[2] =-210.0 * (swa3*swb2 + swa2*swb3) / d7;
+  workspace->Tap[1] = 140.0 * swa3 * swb3 / d7;
+  workspace->Tap[0] = (-35.0*swa3*swb2*swb2 + 21.0*swa2*swb3*swb2 + 
+		     7.0*swa*swb3*swb3 + swb3*swb3*swb ) / d7;
+}
+
+
+int Init_Workspace( reax_system *system, control_params *control, 
+		    storage *workspace, MPI_Comm comm, char *msg )
+{ 
+  int ret;
+  
+  ret = Allocate_Workspace( system, control, workspace, 
+			    system->local_cap, system->total_cap, comm, msg );
+  if( ret != SUCCESS )
+    return ret;
+
+  memset( &(workspace->realloc), 0, sizeof(reallocate_data) );
+  Reset_Workspace( system, workspace );
+
+  /* Initialize the Taper function */
+  Init_Taper( control, workspace, comm );
+
+  return SUCCESS;
+}
+
+
+/************** setup communication data structures  **************/
+int Init_MPI_Datatypes( reax_system *system, storage *workspace, 
+			mpi_datatypes *mpi_data, MPI_Comm comm, char *msg )
+{
+#if defined(PURE_REAX)
+  int           i, block[11];
+  MPI_Aint      base, disp[11];
+  MPI_Datatype  type[11];
+  mpi_atom      sample;
+  boundary_atom b_sample;
+  restart_atom  r_sample;
+  rvec          rvec_sample;
+  rvec2         rvec2_sample;
+#endif
+
+  /* setup the world */
+  mpi_data->world = comm;
+  MPI_Comm_size( comm, &(system->wsize) );
+
+#if defined(PURE_REAX)
+  /* init mpi buffers  */
+  mpi_data->in1_buffer = NULL;
+  mpi_data->in2_buffer = NULL;
+
+  /* mpi_atom - [orig_id, imprt_id, type, num_bonds, num_hbonds, name, 
+                 x, v, f_old, s, t] */
+  block[0] = block[1] = block[2] = block[3] = block[4] = 1;
+  block[5] = 8;
+  block[6] = block[7] = block[8] = 3;
+  block[9] = block[10] = 4;
+
+  MPI_Address( &(sample.orig_id),    disp + 0 );
+  MPI_Address( &(sample.imprt_id),   disp + 1 );
+  MPI_Address( &(sample.type),       disp + 2 );
+  MPI_Address( &(sample.num_bonds),  disp + 3 );
+  MPI_Address( &(sample.num_hbonds), disp + 4 );
+  MPI_Address( &(sample.name),       disp + 5 );
+  MPI_Address( &(sample.x[0]),       disp + 6 );
+  MPI_Address( &(sample.v[0]),       disp + 7 );
+  MPI_Address( &(sample.f_old[0]),   disp + 8 );
+  MPI_Address( &(sample.s[0]),       disp + 9 );
+  MPI_Address( &(sample.t[0]),       disp + 10 ); 
+  
+  base = (MPI_Aint)(&(sample));
+  for( i = 0; i < 11; ++i ) disp[i] -= base;
+
+  type[0] = type[1] = type[2] = type[3] = type[4] = MPI_INT;
+  type[5] = MPI_CHAR;
+  type[6] = type[7] = type[8] = type[9] = type[10] = MPI_DOUBLE;
+
+  MPI_Type_struct( 11, block, disp, type, &(mpi_data->mpi_atom_type) );
+  MPI_Type_commit( &(mpi_data->mpi_atom_type) );
+
+  /* boundary_atom - [orig_id, imprt_id, type, num_bonds, num_hbonds, x] */
+  block[0] = block[1] = block[2] = block[3] = block[4] = 1;
+  block[5] = 3;
+  
+  MPI_Address( &(b_sample.orig_id),    disp + 0 );
+  MPI_Address( &(b_sample.imprt_id),   disp + 1 );
+  MPI_Address( &(b_sample.type),       disp + 2 );
+  MPI_Address( &(b_sample.num_bonds),  disp + 3 );
+  MPI_Address( &(b_sample.num_hbonds), disp + 4 );
+  MPI_Address( &(b_sample.x[0]),       disp + 5 );
+    
+  base = (MPI_Aint)(&(b_sample));
+  for( i = 0; i < 6; ++i ) disp[i] -= base;
+
+  type[0] = type[1] = type[2] = type[3] = type[4] = MPI_INT;
+  type[5] = MPI_DOUBLE;
+
+  MPI_Type_struct( 6, block, disp, type, &(mpi_data->boundary_atom_type) );
+  MPI_Type_commit( &(mpi_data->boundary_atom_type) );
+
+  /* mpi_rvec */
+  block[0] = 3;
+  MPI_Address( &(rvec_sample[0]), disp + 0 );
+  base = disp[0];
+  for( i = 0; i < 1; ++i ) disp[i] -= base;
+  type[0] = MPI_DOUBLE;
+  MPI_Type_struct( 1, block, disp, type, &(mpi_data->mpi_rvec) );
+  MPI_Type_commit( &(mpi_data->mpi_rvec) );
+
+  /* mpi_rvec2 */
+  block[0] = 2;
+  MPI_Address( &(rvec2_sample[0]), disp + 0 );
+  base = disp[0];
+  for( i = 0; i < 1; ++i ) disp[i] -= base;
+  type[0] = MPI_DOUBLE;
+  MPI_Type_struct( 1, block, disp, type, &(mpi_data->mpi_rvec2) );
+  MPI_Type_commit( &(mpi_data->mpi_rvec2) );
+
+  /* restart_atom - [orig_id, type, name[8], x, v] */
+  block[0] = block[1] = 1 ;
+  block[2] = 8; 
+  block[3] = block[4] = 3;
+  
+  MPI_Address( &(r_sample.orig_id),    disp + 0 );
+  MPI_Address( &(r_sample.type),       disp + 1 );
+  MPI_Address( &(r_sample.name),       disp + 2 );
+  MPI_Address( &(r_sample.x[0]),       disp + 3 );
+  MPI_Address( &(r_sample.v[0]),       disp + 4 );
+    
+  base = (MPI_Aint)(&(r_sample));
+  for( i = 0; i < 5; ++i ) disp[i] -= base;
+
+  type[0] = type[1] = MPI_INT;
+  type[2] = MPI_CHAR; 
+  type[3] = type[4] = MPI_DOUBLE;
+
+  MPI_Type_struct( 5, block, disp, type, &(mpi_data->restart_atom_type) );
+  MPI_Type_commit( &(mpi_data->restart_atom_type) );
+#endif
+
+  return SUCCESS;
+}
+
+
+/********************** allocate lists *************************/
+#if defined(PURE_REAX)
+int  Init_Lists( reax_system *system, control_params *control, 
+		 simulation_data *data, storage *workspace, reax_list **lists, 
+		 mpi_datatypes *mpi_data, char *msg )
+{
+  int i, num_nbrs;
+  int total_hbonds, total_bonds, bond_cap, num_3body, cap_3body, Htop;
+  int *hb_top, *bond_top;
+  MPI_Comm comm;
+  
+  comm = mpi_data->world;
+  //for( i = 0; i < MAX_NBRS; ++i ) nrecv[i] = system->my_nbrs[i].est_recv;
+  //system->N = SendRecv( system, mpi_data, mpi_data->boundary_atom_type, nrecv,
+  //		Sort_Boundary_Atoms, Unpack_Exchange_Message, 1 );
+  num_nbrs = Estimate_NumNeighbors( system, lists );
+  if(!Make_List( system->total_cap, num_nbrs, TYP_FAR_NEIGHBOR, 
+		 *lists+FAR_NBRS, comm )){
+    fprintf(stderr, "Problem in initializing far nbrs list. Terminating!\n");
+    MPI_Abort( comm, INSUFFICIENT_MEMORY );
+  }
+#if defined(DEBUG_FOCUS)
+  fprintf( stderr, "p%d: allocated far_nbrs: num_far=%d, space=%dMB\n",
+	   system->my_rank, num_nbrs, 
+	   (int)(num_nbrs*sizeof(far_neighbor_data)/(1024*1024)) );
+#endif
+
+  Generate_Neighbor_Lists( system, data, workspace, lists );
+  bond_top = (int*) calloc( system->total_cap, sizeof(int) );
+  hb_top = (int*) calloc( system->local_cap, sizeof(int) );
+  Estimate_Storages( system, control, lists,
+		     &Htop, hb_top, bond_top, &num_3body, comm );
+  
+  Allocate_Matrix( &(workspace->H), system->local_cap, Htop, comm );
+  workspace->L = NULL;
+  workspace->U = NULL;
+#if defined(DEBUG_FOCUS)
+  fprintf( stderr, "p%d: allocated H matrix: Htop=%d, space=%dMB\n", 
+	   system->my_rank, Htop, 
+	   (int)(Htop * sizeof(sparse_matrix_entry) / (1024*1024)) );
+#endif
+
+  if( control->hbond_cut > 0 ) {
+    /* init H indexes */
+    total_hbonds = 0;
+    for( i = 0; i < system->n; ++i ) {
+      system->my_atoms[i].num_hbonds = hb_top[i];
+      total_hbonds += hb_top[i];
+    }
+    total_hbonds = MAX( total_hbonds*SAFER_ZONE, MIN_CAP*MIN_HBONDS );
+
+    if( !Make_List( system->Hcap, total_hbonds, TYP_HBOND, 
+		    *lists+HBONDS, comm ) ) {
+      fprintf( stderr, "not enough space for hbonds list. terminating!\n" );
+      MPI_Abort( comm, INSUFFICIENT_MEMORY );
+    } 
+#if defined(DEBUG_FOCUS)
+    fprintf( stderr, "p%d: allocated hbonds: total_hbonds=%d, space=%dMB\n", 
+	     system->my_rank, total_hbonds, 
+	     (int)(total_hbonds*sizeof(hbond_data)/(1024*1024)) );
+#endif
+  }
+  
+  /* bonds list */
+  //Allocate_Bond_List( system->N, bond_top, (*lists)+BONDS );
+  //num_bonds = bond_top[system->N-1];
+  total_bonds = 0;
+  for( i = 0; i < system->N; ++i ) {
+    system->my_atoms[i].num_bonds = bond_top[i];
+    total_bonds += bond_top[i];
+  }
+  bond_cap = MAX( total_bonds*SAFE_ZONE, MIN_CAP*MIN_BONDS );
+  
+  if( !Make_List( system->total_cap, bond_cap, TYP_BOND, 
+		  *lists+BONDS, comm ) ) {
+    fprintf( stderr, "not enough space for bonds list. terminating!\n" );
+    MPI_Abort( comm, INSUFFICIENT_MEMORY );
+  }
+#if defined(DEBUG_FOCUS)
+  fprintf( stderr, "p%d: allocated bonds: total_bonds=%d, space=%dMB\n", 
+	   system->my_rank, bond_cap, 
+	   (int)(bond_cap*sizeof(bond_data)/(1024*1024)) );
+#endif
+
+  /* 3bodies list */
+  cap_3body = MAX( num_3body*SAFE_ZONE, MIN_3BODIES );
+  if( !Make_List( bond_cap, cap_3body, TYP_THREE_BODY, 
+		  *lists+THREE_BODIES, comm ) ){
+    fprintf( stderr, "Problem in initializing angles list. Terminating!\n" );
+    MPI_Abort( comm, INSUFFICIENT_MEMORY );
+  }
+#if defined(DEBUG_FOCUS)
+  fprintf( stderr, "p%d: allocated 3-body list: num_3body=%d, space=%dMB\n", 
+	   system->my_rank, cap_3body, 
+	   (int)(cap_3body*sizeof(three_body_interaction_data)/(1024*1024)) );
+#endif
+
+#if defined(TEST_FORCES)
+  if( !Make_List( system->total_cap, bond_cap*8, TYP_DDELTA, 
+		  *lists+DDELTAS, comm ) ) {
+    fprintf( stderr, "Problem in initializing dDelta list. Terminating!\n" );
+    MPI_Abort( comm, INSUFFICIENT_MEMORY );
+  }
+  fprintf( stderr, "p%d: allocated dDelta list: num_ddelta=%d space=%ldMB\n", 
+	   system->my_rank, bond_cap*30, 
+	   bond_cap*8*sizeof(dDelta_data)/(1024*1024) );
+
+  if( !Make_List( bond_cap, bond_cap*50, TYP_DBO, *lists+DBOS, comm ) ) {
+    fprintf( stderr, "Problem in initializing dBO list. Terminating!\n" );
+    MPI_Abort( comm, INSUFFICIENT_MEMORY );
+  }
+  fprintf( stderr, "p%d: allocated dbond list: num_dbonds=%d space=%ldMB\n", 
+	   system->my_rank, bond_cap*MAX_BONDS*3, 
+	   bond_cap*MAX_BONDS*3*sizeof(dbond_data)/(1024*1024) );
+#endif
+
+  free( hb_top );
+  free( bond_top );
+
+  return SUCCESS;
+}
+#elif defined(LAMMPS_REAX)
+int  Init_Lists( reax_system *system, control_params *control, 
+		 simulation_data *data, storage *workspace, reax_list **lists, 
+		 mpi_datatypes *mpi_data, char *msg )
+{
+  int i, num_nbrs;
+  int total_hbonds, total_bonds, bond_cap, num_3body, cap_3body, Htop;
+  int *hb_top, *bond_top;
+  int nrecv[MAX_NBRS];
+  MPI_Comm comm;
+  
+  comm = mpi_data->world;
+  bond_top = (int*) calloc( system->total_cap, sizeof(int) );
+  hb_top = (int*) calloc( system->local_cap, sizeof(int) );
+  Estimate_Storages( system, control, lists,
+		     &Htop, hb_top, bond_top, &num_3body, comm );
+  
+  if( control->hbond_cut > 0 ) {
+    /* init H indexes */
+    total_hbonds = 0;
+    for( i = 0; i < system->n; ++i ) {
+      system->my_atoms[i].num_hbonds = hb_top[i];
+      total_hbonds += hb_top[i];
+    }
+    total_hbonds = (int)(MAX( total_hbonds*SAFER_ZONE, MIN_CAP*MIN_HBONDS ));
+
+    if( !Make_List( system->Hcap, total_hbonds, TYP_HBOND, 
+		    *lists+HBONDS, comm ) ) {
+      fprintf( stderr, "not enough space for hbonds list. terminating!\n" );
+      MPI_Abort( comm, INSUFFICIENT_MEMORY );
+    } 
+#if defined(DEBUG_FOCUS)
+    fprintf( stderr, "p%d: allocated hbonds: total_hbonds=%d, space=%dMB\n", 
+	     system->my_rank, total_hbonds, 
+	     (int)(total_hbonds*sizeof(hbond_data)/(1024*1024)) );
+#endif
+  }
+  
+  /* bonds list */
+  //Allocate_Bond_List( system->N, bond_top, (*lists)+BONDS );
+  //num_bonds = bond_top[system->N-1];
+  total_bonds = 0;
+  for( i = 0; i < system->N; ++i ) {
+    system->my_atoms[i].num_bonds = bond_top[i];
+    total_bonds += bond_top[i];
+  }
+  bond_cap = (int)(MAX( total_bonds*SAFE_ZONE, MIN_CAP*MIN_BONDS ));
+  
+  if( !Make_List( system->total_cap, bond_cap, TYP_BOND, 
+		  *lists+BONDS, comm ) ) {
+    fprintf( stderr, "not enough space for bonds list. terminating!\n" );
+    MPI_Abort( comm, INSUFFICIENT_MEMORY );
+  }
+#if defined(DEBUG_FOCUS)
+  fprintf( stderr, "p%d: allocated bonds: total_bonds=%d, space=%dMB\n", 
+	   system->my_rank, bond_cap, 
+	   (int)(bond_cap*sizeof(bond_data)/(1024*1024)) );
+#endif
+
+  /* 3bodies list */
+  cap_3body = (int)(MAX( num_3body*SAFE_ZONE, MIN_3BODIES ));
+  if( !Make_List( bond_cap, cap_3body, TYP_THREE_BODY, 
+		  *lists+THREE_BODIES, comm ) ){
+    fprintf( stderr, "Problem in initializing angles list. Terminating!\n" );
+    MPI_Abort( comm, INSUFFICIENT_MEMORY );
+  }
+#if defined(DEBUG_FOCUS)
+  fprintf( stderr, "p%d: allocated 3-body list: num_3body=%d, space=%dMB\n", 
+	   system->my_rank, cap_3body, 
+	   (int)(cap_3body*sizeof(three_body_interaction_data)/(1024*1024)) );
+#endif
+
+#if defined(TEST_FORCES)
+  if( !Make_List( system->total_cap, bond_cap*8, TYP_DDELTA, 
+		  *lists+DDELTAS, comm ) ) {
+    fprintf( stderr, "Problem in initializing dDelta list. Terminating!\n" );
+    MPI_Abort( comm, INSUFFICIENT_MEMORY );
+  }
+  fprintf( stderr, "p%d: allocated dDelta list: num_ddelta=%d space=%ldMB\n", 
+	   system->my_rank, bond_cap*30, 
+	   bond_cap*8*sizeof(dDelta_data)/(1024*1024) );
+
+  if( !Make_List( bond_cap, bond_cap*50, TYP_DBO, (*lists)+DBOS, comm ) ) {
+    fprintf( stderr, "Problem in initializing dBO list. Terminating!\n" );
+    MPI_Abort( comm, INSUFFICIENT_MEMORY );
+  }
+  fprintf( stderr, "p%d: allocated dbond list: num_dbonds=%d space=%ldMB\n", 
+	   system->my_rank, bond_cap*MAX_BONDS*3, 
+	   bond_cap*MAX_BONDS*3*sizeof(dbond_data)/(1024*1024) );
+#endif
+
+  free( hb_top );
+  free( bond_top );
+
+  return SUCCESS;
+}
+#endif
+
+
+
+#if defined(PURE_REAX)
+void Initialize( reax_system *system, control_params *control, 
+		 simulation_data *data, storage *workspace, 
+		 reax_list **lists, output_controls *out_control, 
+		 mpi_datatypes *mpi_data )
+{
+  char msg[MAX_STR];
+
+  if( Init_MPI_Datatypes( system, workspace, mpi_data, MPI_COMM_WORLD, msg ) ==
+      FAILURE ) {
+    fprintf( stderr, "p%d: init_mpi_datatypes: could not create datatypes\n",
+	     system->my_rank );
+    fprintf( stderr, "p%d: mpi_data couldn't be initialized! terminating.\n",
+	     system->my_rank );
+    MPI_Abort( mpi_data->world, CANNOT_INITIALIZE );
+  }
+#if defined(DEBUG)
+  fprintf( stderr, "p%d: initialized mpi datatypes\n", system->my_rank );
+#endif
+
+  if( Init_System(system, control, data, workspace, mpi_data, msg) == FAILURE ){
+    fprintf( stderr, "p%d: %s\n", system->my_rank, msg ); 
+    fprintf( stderr, "p%d: system could not be initialized! terminating.\n",
+	     system->my_rank );
+    MPI_Abort( mpi_data->world, CANNOT_INITIALIZE );
+  }
+#if defined(DEBUG)
+  fprintf( stderr, "p%d: system initialized\n", system->my_rank );
+#endif
+
+  if( Init_Simulation_Data(system, control, data, mpi_data, msg) == FAILURE ) {
+    fprintf( stderr, "p%d: %s\n", system->my_rank, msg ); 
+    fprintf( stderr, "p%d: sim_data couldn't be initialized! terminating.\n",
+	     system->my_rank );
+    MPI_Abort( mpi_data->world, CANNOT_INITIALIZE );
+  }
+#if defined(DEBUG)
+  fprintf( stderr, "p%d: initialized simulation data\n", system->my_rank );
+#endif
+
+  if( Init_Workspace( system, control, workspace, mpi_data->world, msg ) == 
+      FAILURE ) {
+    fprintf( stderr, "p%d:init_workspace: not enough memory\n", 
+	     system->my_rank );
+    fprintf( stderr, "p%d:workspace couldn't be initialized! terminating.\n",
+	     system->my_rank );
+    MPI_Abort( mpi_data->world, CANNOT_INITIALIZE );
+  }
+#if defined(DEBUG)
+  fprintf( stderr, "p%d: initialized workspace\n", system->my_rank );
+#endif
+  
+  if( Init_Lists( system, control, data, workspace, lists, mpi_data, msg ) == 
+      FAILURE ) {
+      fprintf( stderr, "p%d: %s\n", system->my_rank, msg );
+      fprintf( stderr, "p%d: system could not be initialized! terminating.\n",
+	       system->my_rank );
+      MPI_Abort( mpi_data->world, CANNOT_INITIALIZE );
+    }
+#if defined(DEBUG)
+  fprintf( stderr, "p%d: initialized lists\n", system->my_rank );
+#endif
+
+  if(Init_Output_Files(system,control,out_control,mpi_data,msg) == FAILURE) {
+    fprintf( stderr, "p%d: %s\n", system->my_rank, msg );
+    fprintf( stderr, "p%d: could not open output files! terminating...\n", 
+	     system->my_rank );
+    MPI_Abort( mpi_data->world, CANNOT_INITIALIZE );
+  }
+#if defined(DEBUG)
+  fprintf( stderr, "p%d: output files opened\n", system->my_rank );
+#endif
+
+  if( control->tabulate ) {
+    if( Init_Lookup_Tables(system,control,workspace,mpi_data,msg) == FAILURE ) {
+      fprintf( stderr, "p%d: %s\n", system->my_rank, msg );
+      fprintf( stderr, "p%d: couldn't create lookup table! terminating.\n",
+	       system->my_rank );
+      MPI_Abort( mpi_data->world, CANNOT_INITIALIZE );
+    }
+#if defined(DEBUG)
+    fprintf( stderr, "p%d: initialized lookup tables\n", system->my_rank );
+#endif
+  }
+
+  Init_Force_Functions( control );
+#if defined(DEBUG)
+  fprintf( stderr, "p%d: initialized force functions\n", system->my_rank );
+#endif
+  /*#ifdef TEST_FORCES 
+    Init_Force_Test_Functions();
+    fprintf(stderr,"p%d: initialized force test functions\n",system->my_rank);
+    #endif */
+}
+
+#elif defined(LAMMPS_REAX)
+void Initialize( reax_system *system, control_params *control, 
+		 simulation_data *data, storage *workspace, 
+		 reax_list **lists, output_controls *out_control,
+		 mpi_datatypes *mpi_data, MPI_Comm comm )
+{
+  char msg[MAX_STR];
+
+
+  if( Init_MPI_Datatypes(system, workspace, mpi_data, comm, msg) == FAILURE ) {
+    fprintf( stderr, "p%d: init_mpi_datatypes: could not create datatypes\n",
+	     system->my_rank );
+    fprintf( stderr, "p%d: mpi_data couldn't be initialized! terminating.\n",
+	     system->my_rank );
+    MPI_Abort( mpi_data->world, CANNOT_INITIALIZE );
+  }
+#if defined(DEBUG)
+  fprintf( stderr, "p%d: initialized mpi datatypes\n", system->my_rank );
+#endif
+  
+  if( Init_System(system, control, msg) == FAILURE ){
+    fprintf( stderr, "p%d: %s\n", system->my_rank, msg ); 
+    fprintf( stderr, "p%d: system could not be initialized! terminating.\n",
+	     system->my_rank );
+    MPI_Abort( mpi_data->world, CANNOT_INITIALIZE );
+  }
+#if defined(DEBUG)
+  fprintf( stderr, "p%d: system initialized\n", system->my_rank );
+#endif
+
+  if( Init_Simulation_Data( system, control, data, msg ) == FAILURE ) {
+    fprintf( stderr, "p%d: %s\n", system->my_rank, msg ); 
+    fprintf( stderr, "p%d: sim_data couldn't be initialized! terminating.\n",
+	     system->my_rank );
+    MPI_Abort( mpi_data->world, CANNOT_INITIALIZE );
+  }
+#if defined(DEBUG)
+  fprintf( stderr, "p%d: initialized simulation data\n", system->my_rank );
+#endif
+
+  if( Init_Workspace( system, control, workspace, mpi_data->world, msg ) == 
+      FAILURE ) {
+    fprintf( stderr, "p%d:init_workspace: not enough memory\n", 
+	     system->my_rank );
+    fprintf( stderr, "p%d:workspace couldn't be initialized! terminating.\n",
+	     system->my_rank );
+    MPI_Abort( mpi_data->world, CANNOT_INITIALIZE );
+  }
+#if defined(DEBUG)
+  fprintf( stderr, "p%d: initialized workspace\n", system->my_rank );
+#endif
+
+  if( Init_Lists( system, control, data, workspace, lists, mpi_data, msg ) == 
+      FAILURE ) {
+      fprintf( stderr, "p%d: %s\n", system->my_rank, msg );
+      fprintf( stderr, "p%d: system could not be initialized! terminating.\n",
+	       system->my_rank );
+      MPI_Abort( mpi_data->world, CANNOT_INITIALIZE );
+    }
+#if defined(DEBUG)
+  fprintf( stderr, "p%d: initialized lists\n", system->my_rank );
+#endif
+
+  if( Init_Output_Files(system,control,out_control,mpi_data,msg)== FAILURE) {
+    fprintf( stderr, "p%d: %s\n", system->my_rank, msg );
+    fprintf( stderr, "p%d: could not open output files! terminating...\n", 
+	     system->my_rank );
+    MPI_Abort( mpi_data->world, CANNOT_INITIALIZE );
+  }
+#if defined(DEBUG)
+  fprintf( stderr, "p%d: output files opened\n", system->my_rank );
+#endif
+
+  if( control->tabulate ) {
+    if( Init_Lookup_Tables( system, control, workspace, mpi_data, msg ) == FAILURE ) {
+      fprintf( stderr, "p%d: %s\n", system->my_rank, msg );
+      fprintf( stderr, "p%d: couldn't create lookup table! terminating.\n",
+	       system->my_rank );
+      MPI_Abort( mpi_data->world, CANNOT_INITIALIZE );
+    }
+#if defined(DEBUG)
+    fprintf( stderr, "p%d: initialized lookup tables\n", system->my_rank );
+#endif
+  }
+
+
+  Init_Force_Functions( control );
+#if defined(DEBUG)
+  fprintf( stderr, "p%d: initialized force functions\n", system->my_rank );
+#endif
+  /*#if defined(TEST_FORCES) 
+    Init_Force_Test_Functions();
+    fprintf(stderr,"p%d: initialized force test functions\n",system->my_rank);
+  #endif*/
+}
+#endif
diff --git a/src/USER-REAXC/reaxc_init_md.h b/src/USER-REAXC/reaxc_init_md.h
new file mode 100644
index 0000000000..c7896f6821
--- /dev/null
+++ b/src/USER-REAXC/reaxc_init_md.h
@@ -0,0 +1,35 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#ifndef __INIT_MD_H_
+#define __INIT_MD_H_
+
+#include "reaxc_types.h"
+
+#if defined(PURE_REAX)
+void Initialize( reax_system*, control_params*, simulation_data*,
+		 storage*, reax_list**, output_controls*, mpi_datatypes* );
+#elif defined(LAMMPS_REAX)
+void Initialize( reax_system*, control_params*, simulation_data*, storage*, 
+		 reax_list**, output_controls*, mpi_datatypes*, MPI_Comm );
+#endif
+
+#endif
diff --git a/src/USER-REAXC/reaxc_io_tools.cpp b/src/USER-REAXC/reaxc_io_tools.cpp
new file mode 100644
index 0000000000..4020a3785e
--- /dev/null
+++ b/src/USER-REAXC/reaxc_io_tools.cpp
@@ -0,0 +1,1712 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#include "reaxc_types.h"
+#if defined(PURE_REAX)
+#include "io_tools.h"
+#include "basic_comm.h"
+#include "list.h"
+#include "reset_tools.h"
+#include "system_props.h"
+#include "tool_box.h"
+#include "traj.h"
+#include "vector.h"
+#elif defined(LAMMPS_REAX)
+#include "reaxc_io_tools.h"
+#include "reaxc_basic_comm.h"
+#include "reaxc_list.h"
+#include "reaxc_reset_tools.h"
+#include "reaxc_system_props.h"
+#include "reaxc_tool_box.h"
+#include "reaxc_traj.h"
+#include "reaxc_vector.h"
+#endif
+
+print_interaction Print_Interactions[NUM_INTRS];
+
+/************************ initialize output controls ************************/
+int Init_Output_Files( reax_system *system, control_params *control, 
+		       output_controls *out_control, mpi_datatypes *mpi_data, 
+		       char *msg )
+{
+  char temp[MAX_STR];
+  int ret;
+
+  if( out_control->write_steps > 0 ){
+    ret = Init_Traj( system, control, out_control, mpi_data, msg );
+    if( ret == FAILURE )
+      return ret;
+  }
+
+  if( system->my_rank == MASTER_NODE ) {
+    /* These files are written only by the master node */
+    if( out_control->energy_update_freq > 0 ) {
+#if defined(PURE_REAX)
+      /* init out file */
+      sprintf( temp, "%s.out", control->sim_name );
+      if( (out_control->out = fopen( temp, "w" )) != NULL ) {
+#if !defined(DEBUG) && !defined(DEBUG_FOCUS)
+	fprintf( out_control->out, "%-6s%14s%14s%14s%11s%13s%13s\n",
+		 "step", "total energy", "potential", "kinetic", 
+		 "T(K)", "V(A^3)", "P(Gpa)" );
+#else
+	fprintf( out_control->out, "%-6s%24s%24s%24s%13s%16s%13s\n",
+		 "step", "total energy", "potential", "kinetic", 
+		 "T(K)", "V(A^3)", "P(GPa)" );
+#endif
+	fflush( out_control->out );
+      }
+      else {
+	strcpy( msg, "init_out_controls: .out file could not be opened\n" );
+	return FAILURE;
+      }
+#endif
+
+      /* init potentials file */
+      sprintf( temp, "%s.pot", control->sim_name );
+      if( (out_control->pot = fopen( temp, "w" )) != NULL ) {
+#if !defined(DEBUG) && !defined(DEBUG_FOCUS)
+	fprintf( out_control->pot, 
+		 "%-6s%14s%14s%14s%14s%14s%14s%14s%14s%14s%14s%14s\n",
+		 "step", "ebond", "eatom", "elp", 
+		 "eang", "ecoa", "ehb", "etor", "econj", 
+		 "evdw","ecoul", "epol" );
+#else
+	fprintf( out_control->pot, 
+		 "%-6s%24s%24s%24s%24s%24s%24s%24s%24s%24s%24s%24s\n",
+		 "step", "ebond", "eatom", "elp", 
+		 "eang", "ecoa", "ehb", "etor", "econj", 
+		 "evdw","ecoul", "epol" );	
+#endif
+	fflush( out_control->pot );
+      }
+      else {
+	strcpy( msg, "init_out_controls: .pot file could not be opened\n" );
+	return FAILURE;
+      }
+      
+      /* init log file */
+#if defined(LOG_PERFORMANCE)
+      sprintf( temp, "%s.log", control->sim_name );
+      if( (out_control->log = fopen( temp, "w" )) != NULL ) {
+	fprintf( out_control->log, "%6s%8s%8s%8s%8s%8s%8s%8s%8s\n",
+		 "step", "total", "comm", "nbrs", "init", "bonded", "nonb", 
+		 "qeq", "matvecs" );
+	fflush( out_control->log );
+      }
+      else {
+	strcpy( msg, "init_out_controls: .log file could not be opened\n" );
+	return FAILURE;
+      }
+#endif
+    }
+
+    /* init pressure file */
+    if( control->ensemble == NPT  ||
+	control->ensemble == iNPT ||
+	control->ensemble == sNPT ) {
+      sprintf( temp, "%s.prs", control->sim_name );
+      if( (out_control->prs = fopen( temp, "w" )) != NULL ) {
+	fprintf(out_control->prs,"%8s%13s%13s%13s%13s%13s%13s%13s\n",
+		"step", "Pint/norm[x]", "Pint/norm[y]", "Pint/norm[z]",
+		"Pext/Ptot[x]", "Pext/Ptot[y]", "Pext/Ptot[z]", "Pkin/V" );
+	fflush( out_control->prs );
+      }
+      else {
+	strcpy(msg,"init_out_controls: .prs file couldn't be opened\n");
+	return FAILURE;
+      }
+    }
+
+    /* init electric dipole moment analysis file */
+    // not yet implemented in the parallel version!!!
+    // if( control->dipole_anal ) {
+    //   sprintf( temp, "%s.dpl", control->sim_name );
+    //   if( (out_control->dpl = fopen( temp, "w" )) != NULL ) {
+    // 	fprintf( out_control->dpl, "%6s%20s%30s",
+    // 		 "step", "molecule count", "avg dipole moment norm" );
+    // 	fflush( out_control->dpl );
+    //   }
+    //   else {
+    // 	strcpy(msg, "init_out_controls: .dpl file couldn't be opened\n");
+    // 	return FAILURE;
+    //   }
+    // }
+ 
+    /* init diffusion coef analysis file */
+    // not yet implemented in the parallel version!!!
+    // if( control->diffusion_coef ) {
+    //   sprintf( temp, "%s.drft", control->sim_name );
+    //   if( (out_control->drft = fopen( temp, "w" )) != NULL ) {
+    // 	fprintf( out_control->drft, "%7s%20s%20s\n", 
+    // 		 "step", "type count", "avg disp^2" );
+    // 	fflush( out_control->drft );
+    //   }
+    //   else {
+    // 	strcpy(msg,"init_out_controls: .drft file couldn't be opened\n");
+    // 	return FAILURE;
+    //   }
+    // }
+  }
+
+
+  /* init molecular analysis file */
+  /* proc0 opens this file and shares it with everyone.
+     then all processors write into it in a round-robin 
+     fashion controlled by their rank */
+  /*if( control->molecular_analysis ) {
+    if( system->my_rank == MASTER_NODE ) {
+      sprintf( temp, "%s.mol", control->sim_name );
+      if( (out_control->mol = fopen( temp, "w" )) == NULL ) {
+	strcpy(msg,"init_out_controls: .mol file could not be opened\n");
+	return FAILURE;
+      }
+    }
+
+    MPI_Bcast( &(out_control->mol), 1, MPI_LONG, 0, MPI_COMM_WORLD );
+    }*/
+
+
+#ifdef TEST_ENERGY
+  /* open bond energy file */
+  sprintf( temp, "%s.ebond.%d", control->sim_name, system->my_rank );
+  if( (out_control->ebond = fopen( temp, "w" )) == NULL ) {
+    strcpy(msg,"Init_Out_Files: .ebond file couldn't be opened\n");
+    return FAILURE;
+  }
+
+  /* open lone-pair energy file */
+  sprintf( temp, "%s.elp.%d", control->sim_name, system->my_rank );
+  if( (out_control->elp = fopen( temp, "w" )) == NULL ) {
+    strcpy(msg,"Init_Out_Files: .elp file couldn't be opened\n");
+    return FAILURE;
+  }
+
+  /* open overcoordination energy file */
+  sprintf( temp, "%s.eov.%d", control->sim_name, system->my_rank );
+  if( (out_control->eov = fopen( temp, "w" )) == NULL )	{
+    strcpy(msg,"Init_Out_Files: .eov file couldn't be opened\n");
+    return FAILURE;
+  }
+
+  /* open undercoordination energy file */
+  sprintf( temp, "%s.eun.%d", control->sim_name, system->my_rank );
+  if( (out_control->eun = fopen( temp, "w" )) == NULL )	{
+    strcpy(msg,"Init_Out_Files: .eun file couldn't be opened\n");
+    return FAILURE;
+  }
+
+  /* open angle energy file */
+  sprintf( temp, "%s.eval.%d", control->sim_name, system->my_rank );
+  if( (out_control->eval = fopen( temp, "w" )) == NULL ) {
+    strcpy(msg,"Init_Out_Files: .eval file couldn't be opened\n");
+    return FAILURE;
+  }
+
+  /* open coalition energy file */
+  sprintf( temp, "%s.ecoa.%d", control->sim_name, system->my_rank );
+  if( (out_control->ecoa = fopen( temp, "w" )) == NULL ) {
+    strcpy(msg,"Init_Out_Files: .ecoa file couldn't be opened\n");
+    return FAILURE;
+  }
+
+  /* open penalty energy file */
+  sprintf( temp, "%s.epen.%d", control->sim_name, system->my_rank );
+  if( (out_control->epen = fopen( temp, "w" )) == NULL ) {
+    strcpy(msg,"Init_Out_Files: .epen file couldn't be opened\n");
+    return FAILURE;
+  }
+
+  /* open torsion energy file */
+  sprintf( temp, "%s.etor.%d", control->sim_name, system->my_rank );
+  if( (out_control->etor = fopen( temp, "w" )) == NULL ) {
+    strcpy(msg,"Init_Out_Files: .etor file couldn't be opened\n");
+    return FAILURE;
+  }
+
+  /* open conjugation energy file */
+  sprintf( temp, "%s.econ.%d", control->sim_name, system->my_rank );
+  if( (out_control->econ = fopen( temp, "w" )) == NULL ) {
+    strcpy(msg,"Init_Out_Files: .econ file couldn't be opened\n");
+    return FAILURE;
+  }
+
+  /* open hydrogen bond energy file */
+  sprintf( temp, "%s.ehb.%d", control->sim_name, system->my_rank );
+  if( (out_control->ehb = fopen( temp, "w" )) == NULL )	{
+    strcpy(msg,"Init_Out_Files: .ehb file couldn't be opened\n");
+    return FAILURE;
+  }
+
+  /* open vdWaals energy file */
+  sprintf( temp, "%s.evdw.%d", control->sim_name, system->my_rank );
+  if( (out_control->evdw = fopen( temp, "w" )) == NULL ) {
+    strcpy(msg,"Init_Out_Files: .evdw file couldn't be opened\n");
+    return FAILURE;
+  }
+
+  /* open coulomb energy file */
+  sprintf( temp, "%s.ecou.%d", control->sim_name, system->my_rank );
+  if( (out_control->ecou = fopen( temp, "w" )) == NULL ) {
+    strcpy(msg,"Init_Out_Files: .ecou file couldn't be opened\n");
+    return FAILURE;
+  }
+#endif
+
+
+#ifdef TEST_FORCES
+  /* open bond orders file */
+  sprintf( temp, "%s.fbo.%d", control->sim_name, system->my_rank );
+  if( (out_control->fbo = fopen( temp, "w" )) == NULL ) {
+    strcpy(msg,"Init_Out_Files: .fbo file couldn't be opened\n");
+    return FAILURE;
+  }
+  
+  /* open bond orders derivatives file */
+  sprintf( temp, "%s.fdbo.%d", control->sim_name, system->my_rank );
+  if( (out_control->fdbo = fopen( temp, "w" )) == NULL ) {
+    strcpy(msg,"Init_Out_Files: .fdbo file couldn't be opened\n");
+    return FAILURE;
+  }
+
+  /* produce a single force file - to be written by p0 */
+  if( system->my_rank == MASTER_NODE ) {
+    /* open bond forces file */
+    sprintf( temp, "%s.fbond", control->sim_name );
+    if( (out_control->fbond = fopen( temp, "w" )) == NULL ) {
+      strcpy(msg,"Init_Out_Files: .fbond file couldn't be opened\n");
+      return FAILURE;
+    }
+
+    /* open lone-pair forces file */
+    sprintf( temp, "%s.flp", control->sim_name );
+    if( (out_control->flp = fopen( temp, "w" )) == NULL ) {
+      strcpy(msg,"Init_Out_Files: .flp file couldn't be opened\n");
+      return FAILURE;
+    }
+    
+    /* open overcoordination forces file */
+    sprintf( temp, "%s.fov", control->sim_name );
+    if( (out_control->fov = fopen( temp, "w" )) == NULL ) {
+      strcpy(msg,"Init_Out_Files: .fov file couldn't be opened\n");
+      return FAILURE;
+    }
+
+    /* open undercoordination forces file */
+    sprintf( temp, "%s.fun", control->sim_name );
+    if( (out_control->fun = fopen( temp, "w" )) == NULL ) {
+      strcpy(msg,"Init_Out_Files: .fun file couldn't be opened\n");
+      return FAILURE;
+    }    
+
+    /* open angle forces file */
+    sprintf( temp, "%s.fang", control->sim_name );
+    if( (out_control->fang = fopen( temp, "w" )) == NULL ) {
+      strcpy(msg,"Init_Out_Files: .fang file couldn't be opened\n");
+      return FAILURE;
+    }
+
+    /* open coalition forces file */
+    sprintf( temp, "%s.fcoa", control->sim_name );
+    if( (out_control->fcoa = fopen( temp, "w" )) == NULL ) {
+      strcpy(msg,"Init_Out_Files: .fcoa file couldn't be opened\n");
+      return FAILURE;
+    }
+    
+    /* open penalty forces file */
+    sprintf( temp, "%s.fpen", control->sim_name );
+    if( (out_control->fpen = fopen( temp, "w" )) == NULL ) {
+      strcpy(msg,"Init_Out_Files: .fpen file couldn't be opened\n");
+      return FAILURE;
+    }
+    
+    /* open torsion forces file */
+    sprintf( temp, "%s.ftor", control->sim_name );
+    if( (out_control->ftor = fopen( temp, "w" )) == NULL ) {
+      strcpy(msg,"Init_Out_Files: .ftor file couldn't be opened\n");
+      return FAILURE;
+    }
+
+    /* open conjugation forces file */
+    sprintf( temp, "%s.fcon", control->sim_name );
+    if( (out_control->fcon = fopen( temp, "w" )) == NULL ) {
+      strcpy(msg,"Init_Out_Files: .fcon file couldn't be opened\n");
+      return FAILURE;
+    }
+
+    /* open hydrogen bond forces file */
+    sprintf( temp, "%s.fhb", control->sim_name );
+    if( (out_control->fhb = fopen( temp, "w" )) == NULL )	{
+      strcpy(msg,"Init_Out_Files: .fhb file couldn't be opened\n");
+      return FAILURE;
+    }
+    
+    /* open vdw forces file */
+    sprintf( temp, "%s.fvdw", control->sim_name );
+    if( (out_control->fvdw = fopen( temp, "w" )) == NULL ) {
+      strcpy(msg,"Init_Out_Files: .fvdw file couldn't be opened\n");
+      return FAILURE;
+    }
+
+    /* open nonbonded forces file */
+    sprintf( temp, "%s.fele", control->sim_name );
+    if( (out_control->fele = fopen( temp, "w" )) == NULL ) {
+      strcpy(msg,"Init_Out_Files: .fele file couldn't be opened\n");
+      return FAILURE;
+    }
+    
+    /* open total force file */
+    sprintf( temp, "%s.ftot", control->sim_name );
+    if( (out_control->ftot = fopen( temp, "w" )) == NULL ) {
+      strcpy(msg,"Init_Out_Files: .ftot file couldn't be opened\n");
+      return FAILURE;
+    }
+
+    /* open force comprison file */
+    sprintf( temp, "%s.fcomp", control->sim_name );
+    if( (out_control->fcomp = fopen( temp, "w" )) == NULL ) {
+      strcpy(msg,"Init_Out_Files: .fcomp file couldn't be opened\n");
+      return FAILURE;
+    }
+  }
+#endif
+
+#if defined(PURE_REAX)
+#if defined(TEST_FORCES) || defined(TEST_ENERGY)
+    /* open far neighbor list file */
+  sprintf( temp, "%s.far_nbrs_list.%d", control->sim_name, system->my_rank );
+  if( (out_control->flist = fopen( temp, "w" )) == NULL ) {
+    strcpy(msg,"Init_Out_Files: .far_nbrs_list file couldn't be opened\n");
+    return FAILURE;
+  }
+
+  /* open bond list file */
+  sprintf( temp, "%s.bond_list.%d", control->sim_name, system->my_rank );
+  if( (out_control->blist = fopen( temp, "w" )) == NULL ) {
+    strcpy(msg,"Init_Out_Files: .bond_list file couldn't be opened\n");
+    return FAILURE;
+  }
+
+  /* open near neighbor list file */
+  sprintf( temp, "%s.near_nbrs_list.%d", control->sim_name, system->my_rank );
+  if( (out_control->nlist = fopen( temp, "w" )) == NULL ) {
+    strcpy(msg,"Init_Out_Files: .near_nbrs_list file couldn't be opened\n");
+    return FAILURE;
+  }
+#endif
+#endif
+
+  return SUCCESS;
+}
+
+
+/************************ close output files ************************/
+int Close_Output_Files( reax_system *system, control_params *control, 
+			output_controls *out_control, mpi_datatypes *mpi_data )
+{
+  if( out_control->write_steps > 0 )
+    End_Traj( system->my_rank, out_control );
+
+  if( system->my_rank == MASTER_NODE ) {
+    if( out_control->energy_update_freq > 0 ) {
+#if defined(PURE_REAX)
+      fclose( out_control->out );
+#endif
+      fclose( out_control->pot );
+#if defined(LOG_PERFORMANCE)
+      fclose( out_control->log );
+#endif
+    }
+
+    if( control->ensemble == NPT || control->ensemble == iNPT ||
+	control->ensemble == sNPT )
+      fclose( out_control->prs );
+
+    // not yet implemented in the parallel version
+    //if( control->dipole_anal ) fclose( out_control->dpl );
+    //if( control->diffusion_coef ) fclose( out_control->drft );
+    //if( control->molecular_analysis ) fclose( out_control->mol );
+  }
+  
+#ifdef TEST_ENERGY
+  fclose( out_control->ebond );
+  fclose( out_control->elp );
+  fclose( out_control->eov );
+  fclose( out_control->eun );
+  fclose( out_control->eval );
+  fclose( out_control->epen );
+  fclose( out_control->ecoa );
+  fclose( out_control->ehb );
+  fclose( out_control->etor );
+  fclose( out_control->econ );
+  fclose( out_control->evdw );
+  fclose( out_control->ecou );
+#endif
+
+#ifdef TEST_FORCES
+  fclose( out_control->fbo );
+  fclose( out_control->fdbo );
+
+  if( system->my_rank == MASTER_NODE ) {
+    fclose( out_control->fbond ); 
+    fclose( out_control->flp );
+    fclose( out_control->fov );
+    fclose( out_control->fun );
+    fclose( out_control->fang );
+    fclose( out_control->fcoa );
+    fclose( out_control->fpen );
+    fclose( out_control->ftor );
+    fclose( out_control->fcon );
+    fclose( out_control->fhb );
+    fclose( out_control->fvdw );
+    fclose( out_control->fele );
+    fclose( out_control->ftot );
+    fclose( out_control->fcomp );
+  }
+#endif
+
+#if defined(PURE_REAX)
+#if defined(TEST_FORCES) || defined(TEST_ENERGY)
+  fclose( out_control->flist );
+  fclose( out_control->blist );
+  fclose( out_control->nlist );
+#endif
+#endif
+
+  return SUCCESS;
+}
+
+
+
+void Print_Box( simulation_box* box, char *name, FILE *out )
+{
+  // int i, j;
+
+  fprintf( out, "%s:\n", name );
+  fprintf( out, "\tmin[%8.3f %8.3f %8.3f]\n", 
+	   box->min[0], box->min[1], box->min[2] );
+  fprintf( out, "\tmax[%8.3f %8.3f %8.3f]\n",
+	   box->max[0], box->max[1], box->max[2] );
+  fprintf( out, "\tdims[%8.3f%8.3f%8.3f]\n", 
+	   box->box_norms[0], box->box_norms[1], box->box_norms[2] );
+
+  // fprintf( out, "box: {" );
+  // for( i = 0; i < 3; ++i )
+  //   {
+  //     fprintf( out, "{" );
+  //     for( j = 0; j < 3; ++j )
+  //       fprintf( out, "%8.3f ", box->box[i][j] );
+  //     fprintf( out, "}" );
+  //   }
+  // fprintf( out, "}\n" );
+
+  // fprintf( out, "box_trans: {" );
+  // for( i = 0; i < 3; ++i )
+  //   {
+  //     fprintf( out, "{" );
+  //     for( j = 0; j < 3; ++j )
+  // 	fprintf( out, "%8.3f ", box->trans[i][j] );
+  //     fprintf( out, "}" );
+  //   }
+  // fprintf( out, "}\n" );
+
+  // fprintf( out, "box_trinv: {" );
+  // for( i = 0; i < 3; ++i )
+  //   {
+  //     fprintf( out, "{" );
+  //     for( j = 0; j < 3; ++j )
+  // 	fprintf( out, "%8.3f ", box->trans_inv[i][j] );
+  //     fprintf( out, "}" );
+  //   }
+  // fprintf( out, "}\n" );
+}
+
+
+
+void Print_Grid( grid* g, FILE *out )
+{
+  int x, y, z, gc_type;
+  ivec gc_str;
+  char gcell_type_text[10][12] = 
+    { "NO_NBRS", "NEAR_ONLY", "HBOND_ONLY", "FAR_ONLY",  
+      "NEAR_HBOND", "NEAR_FAR", "HBOND_FAR", "FULL_NBRS", "NATIVE" };
+
+  fprintf( out, "\tnumber of grid cells: %d %d %d\n",
+	   g->ncells[0], g->ncells[1], g->ncells[2] );
+  fprintf( out, "\tgcell lengths: %8.3f %8.3f %8.3f\n", 
+	   g->cell_len[0], g->cell_len[1], g->cell_len[2] );
+  fprintf( out, "\tinverses of gcell lengths: %8.3f %8.3f %8.3f\n",
+	   g->inv_len[0], g->inv_len[1], g->inv_len[2] );
+  fprintf( out, "\t---------------------------------\n" );
+  fprintf( out, "\tnumber of native gcells: %d %d %d\n",
+	   g->native_cells[0], g->native_cells[1], g->native_cells[2] );
+  fprintf( out, "\tnative gcell span: %d-%d  %d-%d  %d-%d\n",
+	   g->native_str[0], g->native_end[0], 
+	   g->native_str[1], g->native_end[1], 
+	   g->native_str[2], g->native_end[2] );
+  fprintf( out, "\t---------------------------------\n" );
+  fprintf( out, "\tvlist gcell stretch: %d %d %d\n",
+	   g->vlist_span[0], g->vlist_span[1], g->vlist_span[2] );
+  fprintf( out, "\tnonbonded nbrs gcell stretch: %d %d %d\n",
+	   g->nonb_span[0], g->nonb_span[1], g->nonb_span[2] );
+  fprintf( out, "\tbonded nbrs gcell stretch: %d %d %d\n",
+	   g->bond_span[0], g->bond_span[1], g->bond_span[2] );
+  fprintf( out, "\t---------------------------------\n" );
+  fprintf( out, "\tghost gcell span: %d %d %d\n",
+	   g->ghost_span[0], g->ghost_span[1], g->ghost_span[2] );
+  fprintf( out, "\tnonbonded ghost gcell span: %d %d %d\n",
+	   g->ghost_nonb_span[0],g->ghost_nonb_span[1],g->ghost_nonb_span[2]);
+  fprintf(out, "\thbonded ghost gcell span: %d %d %d\n",
+	  g->ghost_hbond_span[0],g->ghost_hbond_span[1],g->ghost_hbond_span[2]);
+  fprintf( out, "\tbonded ghost gcell span: %d %d %d\n",
+	   g->ghost_bond_span[0],g->ghost_bond_span[1],g->ghost_bond_span[2]);
+  //fprintf(out, "\t---------------------------------\n" );
+  //fprintf(out, "\tmax number of gcells at the boundary: %d\n", g->gcell_cap);
+  fprintf( out, "\t---------------------------------\n" );
+  
+  fprintf( stderr, "GCELL MARKS:\n" );
+  gc_type = g->cells[0][0][0].type;
+  ivec_MakeZero( gc_str );
+
+  x = y = z = 0;
+  for( x = 0; x < g->ncells[0]; ++x )
+    for( y = 0; y < g->ncells[1]; ++y )
+      for( z = 0; z < g->ncells[2]; ++z )
+	if( g->cells[x][y][z].type != gc_type ){
+	  fprintf( stderr, 
+		   "\tgcells from(%2d %2d %2d) to (%2d %2d %2d): %d - %s\n",
+		   gc_str[0], gc_str[1], gc_str[2], x, y, z, 
+		   gc_type, gcell_type_text[gc_type] );
+	  gc_type = g->cells[x][y][z].type;
+	  gc_str[0] = x;
+	  gc_str[1] = y;
+	  gc_str[2] = z;
+	}
+  fprintf( stderr, "\tgcells from(%2d %2d %2d) to (%2d %2d %2d): %d - %s\n",
+	   gc_str[0], gc_str[1], gc_str[2], x, y, z,
+	   gc_type, gcell_type_text[gc_type] );
+  fprintf( out, "-------------------------------------\n" );
+}
+
+
+
+void Print_GCell_Exchange_Bounds( int my_rank, neighbor_proc *my_nbrs )
+{
+  ivec r;
+  int nbr;
+  neighbor_proc *nbr_pr;
+  char fname[100];
+  FILE *f;
+  char exch[3][10] = { "NONE", "NEAR_EXCH", "FULL_EXCH" };
+
+  sprintf( fname, "gcell_exchange_bounds%d", my_rank );
+  f = fopen( fname, "w" );
+ 
+  /* loop over neighbor processes */
+  for( r[0] = -1; r[0] <= 1; ++r[0])
+    for( r[1] = -1; r[1] <= 1; ++r[1] )
+      for( r[2] = -1; r[2] <= 1; ++r[2] )       
+	if( r[0]!=0 || r[1]!=0 || r[2]!=0 ) {
+	  nbr_pr = &(my_nbrs[nbr]);
+	  
+	  fprintf( f, "p%-2d GCELL BOUNDARIES with r(%2d %2d %2d):\n",
+		   my_rank, r[0], r[1], r[2] );
+	  
+	  fprintf( f, "\tsend_type %s: send(%d %d %d) to (%d %d %d)\n", 
+		   exch[nbr_pr->send_type],
+		   nbr_pr->str_send[0], nbr_pr->str_send[1], 
+		   nbr_pr->str_send[2],
+		   nbr_pr->end_send[0], nbr_pr->end_send[1],
+		   nbr_pr->end_send[2] );
+	  
+	  fprintf( f, "\trecv_type %s: recv(%d %d %d) to (%d %d %d)\n", 
+		   exch[nbr_pr->recv_type],
+		   nbr_pr->str_recv[0], nbr_pr->str_recv[1], 
+		   nbr_pr->str_recv[2],
+		   nbr_pr->end_recv[0], nbr_pr->end_recv[1],
+		   nbr_pr->end_recv[2] );
+	}
+  
+  fclose(f);
+}
+
+
+
+void Print_Native_GCells( reax_system *system )
+{
+  int        i, j, k, l;
+  char       fname[100];
+  FILE      *f;
+  grid      *g;
+  grid_cell *gc;
+  char gcell_type_text[10][12] = 
+    { "NO_NBRS", "NEAR_ONLY", "HBOND_ONLY", "FAR_ONLY",  
+      "NEAR_HBOND", "NEAR_FAR", "HBOND_FAR", "FULL_NBRS", "NATIVE" };
+
+  sprintf( fname, "native_gcells.%d", system->my_rank );
+  f = fopen( fname, "w" );
+  g = &(system->my_grid);
+
+  for( i = g->native_str[0]; i < g->native_end[0]; i++ )
+    for( j = g->native_str[1]; j < g->native_end[1]; j++ )
+      for( k = g->native_str[2]; k < g->native_end[2]; k++ )
+  	{
+  	  gc = &( g->cells[i][j][k] );
+
+  	  fprintf( f, "p%d gcell(%2d %2d %2d) of type %d(%s)\n",
+  		   system->my_rank, i, j, k, 
+		   gc->type, gcell_type_text[gc->type] );
+
+  	  fprintf( f, "\tatom list start: %d, end: %d\n\t", gc->str, gc->end );
+
+	  for( l = gc->str; l < gc->end; ++l )
+  	    fprintf( f, "%5d", system->my_atoms[l].orig_id );
+  	  fprintf( f, "\n" );
+  	}  
+
+  fclose(f);
+}
+
+
+
+void Print_All_GCells( reax_system *system )
+{
+  int        i, j, k, l;
+  char       fname[100];
+  FILE      *f;
+  grid      *g;
+  grid_cell *gc;
+  char gcell_type_text[10][12] = 
+    { "NO_NBRS", "NEAR_ONLY", "HBOND_ONLY", "FAR_ONLY",  
+      "NEAR_HBOND", "NEAR_FAR", "HBOND_FAR", "FULL_NBRS", "NATIVE" };
+
+  sprintf( fname, "all_gcells.%d", system->my_rank );
+  f = fopen( fname, "w" );
+  g = &(system->my_grid);
+
+  for( i = 0; i < g->ncells[0]; i++ )
+    for( j = 0; j < g->ncells[1]; j++ )
+      for( k = 0; k < g->ncells[2]; k++ )
+  	{
+  	  gc = &( g->cells[i][j][k] );
+
+  	  fprintf( f, "p%d gcell(%2d %2d %2d) of type %d(%s)\n",
+  		   system->my_rank, i, j, k, 
+		   gc->type, gcell_type_text[gc->type] );
+
+  	  fprintf( f, "\tatom list start: %d, end: %d\n\t", gc->str, gc->end );
+  	  
+	  for( l = gc->str; l < gc->end; ++l )
+  	    fprintf( f, "%5d", system->my_atoms[l].orig_id );
+  	  fprintf( f, "\n" );
+  	}  
+
+  fclose(f);
+}
+
+
+
+void Print_My_Atoms( reax_system *system )
+{
+  int   i;
+  char  fname[100];
+  FILE *fh;
+
+  sprintf( fname, "my_atoms.%d", system->my_rank );
+  if( (fh = fopen( fname, "w" )) == NULL )
+    {
+      fprintf( stderr, "error in opening my_atoms file" );
+      MPI_Abort( MPI_COMM_WORLD, FILE_NOT_FOUND );
+    }
+
+  // fprintf( stderr, "p%d had %d atoms\n",
+  //   system->my_rank, system->n );
+
+  for( i = 0; i < system->n; ++i )
+    fprintf( fh, "p%-2d %-5d %2d %24.15e%24.15e%24.15e\n",
+	     system->my_rank, 
+	     system->my_atoms[i].orig_id, system->my_atoms[i].type, 
+	     system->my_atoms[i].x[0], 
+	     system->my_atoms[i].x[1], 
+	     system->my_atoms[i].x[2] );
+
+  fclose( fh );
+}
+
+
+void Print_My_Ext_Atoms( reax_system *system )
+{
+  int   i;
+  char  fname[100];
+  FILE *fh;
+
+  sprintf( fname, "my_ext_atoms.%d", system->my_rank );
+  if( (fh = fopen( fname, "w" )) == NULL )
+    {
+      fprintf( stderr, "error in opening my_ext_atoms file" );
+      MPI_Abort( MPI_COMM_WORLD, FILE_NOT_FOUND );
+    }
+
+  // fprintf( stderr, "p%d had %d atoms\n",
+  //   system->my_rank, system->n );
+
+  for( i = 0; i < system->N; ++i )
+    fprintf( fh, "p%-2d %-5d imprt%-5d %2d %24.15e%24.15e%24.15e\n",
+	     system->my_rank, system->my_atoms[i].orig_id, 
+	     system->my_atoms[i].imprt_id, system->my_atoms[i].type, 
+	     system->my_atoms[i].x[0], 
+	     system->my_atoms[i].x[1], 
+	     system->my_atoms[i].x[2] );
+
+  fclose( fh );
+}
+
+
+void Print_Far_Neighbors( reax_system *system, reax_list **lists, 
+			  control_params *control )
+{
+  char  fname[100];
+  int   i, j, id_i, id_j, nbr, natoms;  
+  FILE *fout;
+  reax_list *far_nbrs;
+
+  sprintf( fname, "%s.far_nbrs.%d", control->sim_name, system->my_rank );
+  fout      = fopen( fname, "w" );
+  far_nbrs = (*lists) + FAR_NBRS;
+  natoms = system->N;
+
+  for( i = 0; i < natoms; ++i ) {
+    id_i = system->my_atoms[i].orig_id;
+
+    for( j = Start_Index(i,far_nbrs); j < End_Index(i,far_nbrs); ++j ) {
+      nbr = far_nbrs->select.far_nbr_list[j].nbr;
+      id_j = system->my_atoms[nbr].orig_id;
+
+      fprintf( fout, "%6d%6d%24.15e%24.15e%24.15e%24.15e\n",
+	       id_i, id_j, far_nbrs->select.far_nbr_list[j].d,
+	       far_nbrs->select.far_nbr_list[j].dvec[0],
+	       far_nbrs->select.far_nbr_list[j].dvec[1],
+	       far_nbrs->select.far_nbr_list[j].dvec[2] );
+	
+      fprintf( fout, "%6d%6d%24.15e%24.15e%24.15e%24.15e\n",
+	       id_j, id_i, far_nbrs->select.far_nbr_list[j].d,
+	       -far_nbrs->select.far_nbr_list[j].dvec[0],
+	       -far_nbrs->select.far_nbr_list[j].dvec[1],
+	       -far_nbrs->select.far_nbr_list[j].dvec[2] );
+    }
+  }
+    
+  fclose( fout );
+}
+
+
+void Print_Sparse_Matrix( reax_system *system, sparse_matrix *A )
+{
+  int i, j;
+
+  for( i = 0; i < A->n; ++i )
+    for( j = A->start[i]; j < A->end[i]; ++j )
+      fprintf( stderr, "%d %d %.15e\n", 
+	       system->my_atoms[i].orig_id,
+	       system->my_atoms[A->entries[j].j].orig_id, 
+	       A->entries[j].val );
+}
+
+
+void Print_Sparse_Matrix2( reax_system *system, sparse_matrix *A, char *fname )
+{
+  int i, j;
+  FILE *f = fopen( fname, "w" );
+
+  for( i = 0; i < A->n; ++i )
+    for( j = A->start[i]; j < A->end[i]; ++j )
+      fprintf( f, "%d %d %.15e\n", 
+	       system->my_atoms[i].orig_id,
+	       system->my_atoms[A->entries[j].j].orig_id, 
+	       A->entries[j].val );
+
+  fclose(f);
+}
+
+
+void Print_Symmetric_Sparse(reax_system *system, sparse_matrix *A, char *fname)
+{
+  int i, j;
+  reax_atom *ai, *aj;
+  FILE *f = fopen( fname, "w" );
+
+  for( i = 0; i < A->n; ++i ) {
+    ai = &(system->my_atoms[i]);
+    for( j = A->start[i]; j < A->end[i]; ++j ) {
+      aj = &(system->my_atoms[A->entries[j].j]);
+      fprintf( f, "%d %d %.15e\n", 
+	       ai->renumber, aj->renumber, A->entries[j].val );
+      if( A->entries[j].j < system->n && ai->renumber != aj->renumber )
+	fprintf( f, "%d %d %.15e\n", 
+		 aj->renumber, ai->renumber, A->entries[j].val );
+    }
+  }
+
+  fclose(f);
+}
+
+
+void Print_Linear_System( reax_system *system, control_params *control, 
+			  storage *workspace, int step )
+{
+  int   i, j;
+  char  fname[100];
+  reax_atom *ai, *aj;
+  sparse_matrix *H;
+  FILE *out;
+
+  // print rhs and init guesses for QEq
+  sprintf( fname, "%s.p%dstate%d", control->sim_name, system->my_rank, step );
+  out = fopen( fname, "w" );
+  for( i = 0; i < system->n; i++ ) {
+    ai = &(system->my_atoms[i]);
+    fprintf( out, "%6d%2d%24.15e%24.15e%24.15e%24.15e%24.15e%24.15e%24.15e\n", 
+	     ai->renumber, ai->type, ai->x[0], ai->x[1], ai->x[2], 
+	     workspace->s[i], workspace->b_s[i], 
+	     workspace->t[i], workspace->b_t[i] );
+  }
+  fclose( out );
+  
+  // print QEq coef matrix
+  sprintf( fname, "%s.p%dH%d", control->sim_name, system->my_rank, step );
+  Print_Symmetric_Sparse( system, workspace->H, fname );
+  
+  // print the incomplete H matrix
+  /*sprintf( fname, "%s.p%dHinc%d", control->sim_name, system->my_rank, step );
+  out = fopen( fname, "w" );
+  H = workspace->H;
+  for( i = 0; i < H->n; ++i ) {
+    ai = &(system->my_atoms[i]);
+    for( j = H->start[i]; j < H->end[i]; ++j ) 
+      if( H->entries[j].j < system->n ) {
+	aj = &(system->my_atoms[H->entries[j].j]);
+	fprintf( out, "%d %d %.15e\n", 
+		 ai->orig_id, aj->orig_id, H->entries[j].val );
+	if( ai->orig_id != aj->orig_id )
+	  fprintf( out, "%d %d %.15e\n", 
+		   aj->orig_id, ai->orig_id, H->entries[j].val );
+      }
+  }
+  fclose( out );*/
+  
+  // print the L from incomplete cholesky decomposition
+  /*sprintf( fname, "%s.p%dL%d", control->sim_name, system->my_rank, step );
+    Print_Sparse_Matrix2( system, workspace->L, fname );*/
+}
+
+
+void Print_LinSys_Soln( reax_system *system, real *x, real *b_prm, real *b )
+{
+  int    i;
+  char   fname[100];
+  FILE  *fout;
+
+  sprintf( fname, "qeq.%d.out", system->my_rank );
+  fout = fopen( fname, "w" );
+
+  for( i = 0; i < system->n; ++i )
+    fprintf( fout, "%6d%10.4f%10.4f%10.4f\n", 
+	     system->my_atoms[i].orig_id, x[i], b_prm[i], b[i] );
+
+  fclose( fout );
+}
+
+
+void Print_Charges( reax_system *system )
+{
+  int    i;
+  char   fname[100];
+  FILE  *fout;
+
+  sprintf( fname, "q.%d.out", system->my_rank );
+  fout = fopen( fname, "w" );
+
+  for( i = 0; i < system->n; ++i )
+    fprintf( fout, "%6d %10.7f %10.7f %10.7f\n", 
+	     system->my_atoms[i].orig_id, 
+	     system->my_atoms[i].s[0], 
+	     system->my_atoms[i].t[0], 
+	     system->my_atoms[i].q );
+
+  fclose( fout );
+}
+
+
+void Print_Bonds( reax_system *system, reax_list *bonds, char *fname )
+{
+  int i, j, pj;
+  bond_data *pbond;
+  bond_order_data *bo_ij;
+  FILE *f = fopen( fname, "w" );
+
+  for( i = 0; i < system->N; ++i )
+    for( pj = Start_Index(i, bonds); pj < End_Index(i, bonds); ++pj ) {
+      pbond = &(bonds->select.bond_list[pj]);
+      bo_ij = &(pbond->bo_data);
+      j = pbond->nbr;
+      //fprintf( f, "%6d%6d%23.15e%23.15e%23.15e%23.15e%23.15e\n", 
+      //       system->my_atoms[i].orig_id, system->my_atoms[j].orig_id, 
+      //       pbond->d, bo_ij->BO, bo_ij->BO_s, bo_ij->BO_pi, bo_ij->BO_pi2 );
+      fprintf( f, "%8d%8d %24.15f %24.15f\n", 
+	       i, j,//system->my_atoms[i].orig_id, system->my_atoms[j].orig_id, 
+	       pbond->d, bo_ij->BO );
+    }
+
+  fclose(f);
+}
+
+
+int fn_qsort_intcmp( const void *a, const void *b ) 
+{ 
+  return( *(int *)a - *(int *)b ); 
+} 
+
+void Print_Bond_List2( reax_system *system, reax_list *bonds, char *fname )
+{
+  int i,j, id_i, id_j, nbr, pj;
+  FILE *f = fopen( fname, "w" );
+  int temp[500];
+  int num=0;
+
+  for( i = 0; i < system->n; ++i ) {
+    num=0;
+    id_i = system->my_atoms[i].orig_id;
+    fprintf( f, "%6d:", id_i);
+    for( pj = Start_Index(i, bonds); pj < End_Index(i, bonds); ++pj ) {
+      nbr = bonds->select.bond_list[pj].nbr;	
+      id_j = system->my_atoms[nbr].orig_id;
+      if( id_i < id_j ) 
+	temp[num++] = id_j;
+    }
+    
+    qsort(&temp, num, sizeof(int), fn_qsort_intcmp);
+    for(j=0; j < num; j++)
+      fprintf(f, "%6d", temp[j] );
+    fprintf(f, "\n");
+  }
+}
+
+
+void Print_Total_Force( reax_system *system, simulation_data *data, 
+			storage *workspace )
+{
+  int    i;
+
+  fprintf( stderr, "step: %d\n", data->step );
+  fprintf( stderr, "%6s\t%-38s\n", "atom", "atom.f[0,1,2]");
+
+  for( i = 0; i < system->N; ++i )
+    fprintf( stderr, "%6d %f %f %f\n", 
+	     //"%6d%24.15e%24.15e%24.15e\n", 
+	     system->my_atoms[i].orig_id,
+	     workspace->f[i][0], workspace->f[i][1], workspace->f[i][2] );
+}
+
+void Output_Results( reax_system *system, control_params *control, 
+		     simulation_data *data, reax_list **lists, 
+		     output_controls *out_control, mpi_datatypes *mpi_data )
+{
+#if defined(LOG_PERFORMANCE)
+  real t_elapsed, denom;
+#endif
+
+  if((out_control->energy_update_freq > 0 && 
+      data->step%out_control->energy_update_freq == 0) ||
+     (out_control->write_steps > 0 && 
+      data->step%out_control->write_steps == 0)){
+    /* update system-wide energies */
+    Compute_System_Energy( system, data, mpi_data->world );
+    
+    /* output energies */
+    if( system->my_rank == MASTER_NODE && 
+	out_control->energy_update_freq > 0 &&
+	data->step % out_control->energy_update_freq == 0 ) {
+#if !defined(DEBUG) && !defined(DEBUG_FOCUS)
+#if defined(PURE_REAX)
+      fprintf( out_control->out, 
+	       "%-6d%14.2f%14.2f%14.2f%11.2f%13.2f%13.5f\n",
+	       data->step, data->sys_en.e_tot, data->sys_en.e_pot, 
+	       E_CONV * data->sys_en.e_kin, data->therm.T,
+	       system->big_box.V, data->iso_bar.P );
+      fflush( out_control->out );
+#endif
+
+      fprintf( out_control->pot, 
+	       "%-6d%14.2f%14.2f%14.2f%14.2f%14.2f%14.2f%14.2f%14.2f%14.2f%14.2f%14.2f\n",
+	       data->step,
+	       data->sys_en.e_bond,
+	       data->sys_en.e_ov + data->sys_en.e_un,  data->sys_en.e_lp,
+	       data->sys_en.e_ang + data->sys_en.e_pen, data->sys_en.e_coa,
+	       data->sys_en.e_hb,
+	       data->sys_en.e_tor, data->sys_en.e_con, 
+	       data->sys_en.e_vdW, data->sys_en.e_ele, data->sys_en.e_pol);
+      fflush( out_control->pot );
+#else
+#if defined(PURE_REAX)
+      fprintf( out_control->out, 
+	       "%-6d%24.15e%24.15e%24.15e%13.5f%16.5f%13.5f\n",
+	       data->step, data->sys_en.e_tot, data->sys_en.e_pot,
+	       E_CONV * data->sys_en.e_kin, data->therm.T,
+	       system->big_box.V, data->iso_bar.P );
+      fflush( out_control->out );
+#endif
+
+      fprintf( out_control->pot, 
+	       "%-6d%24.15e%24.15e%24.15e%24.15e%24.15e%24.15e%24.15e%24.15e%24.15e%24.15e%24.15e\n",
+	       data->step,
+	       data->sys_en.e_bond,
+	       data->sys_en.e_ov + data->sys_en.e_un,  data->sys_en.e_lp,
+	       data->sys_en.e_ang + data->sys_en.e_pen, data->sys_en.e_coa,
+	       data->sys_en.e_hb,
+	       data->sys_en.e_tor, data->sys_en.e_con, 
+	       data->sys_en.e_vdW, data->sys_en.e_ele, data->sys_en.e_pol);
+      fflush( out_control->pot );
+#endif //DEBUG
+      
+#if defined(LOG_PERFORMANCE)
+      t_elapsed = Get_Timing_Info( data->timing.total );
+      if( data->step - data->prev_steps > 0 )
+	denom = 1.0 / out_control->energy_update_freq;
+      else denom = 1;
+      
+      fprintf( out_control->log, "%6d%8.3f%8.3f%8.3f%8.3f%8.3f%8.3f%8.3f%6d\n",
+	       data->step, 
+	       t_elapsed * denom, 
+	       data->timing.comm * denom,
+	       data->timing.nbrs * denom,
+	       data->timing.init_forces * denom,
+	       data->timing.bonded * denom,
+	       data->timing.nonb * denom,
+	       data->timing.qEq * denom,
+	       (int)((data->timing.s_matvecs+data->timing.t_matvecs)*denom) );
+      
+      Reset_Timing( &(data->timing) );
+      fflush( out_control->log );
+#endif //LOG_PERFORMANCE
+      
+      if( control->virial ){
+	fprintf( out_control->prs, 
+		 "%8d%13.6f%13.6f%13.6f%13.6f%13.6f%13.6f%13.6f\n",
+		 data->step, 
+		 data->int_press[0], data->int_press[1], data->int_press[2],
+		 data->ext_press[0], data->ext_press[1], data->ext_press[2], 
+		 data->kin_press );
+	
+	fprintf( out_control->prs, 
+		 "%8s%13.6f%13.6f%13.6f%13.6f%13.6f%13.6f%13.6f\n",
+		 "",system->big_box.box_norms[0], system->big_box.box_norms[1], 
+		 system->big_box.box_norms[2],
+		 data->tot_press[0], data->tot_press[1], data->tot_press[2], 
+		 system->big_box.V );
+	
+	fflush( out_control->prs);
+      }
+    }
+    
+    /* write current frame */
+    if( out_control->write_steps > 0 && 
+	(data->step-data->prev_steps) % out_control->write_steps == 0 ) {
+      Append_Frame( system, control, data, lists, out_control, mpi_data );
+    }
+  }
+  
+#if defined(DEBUG)
+  fprintf( stderr, "output_results... done\n" );
+#endif
+}
+
+
+#ifdef TEST_ENERGY
+void Debug_Marker_Bonded( output_controls *out_control, int step )
+{
+  fprintf( out_control->ebond, "step: %d\n%6s%6s%12s%12s%12s\n", 
+	   step, "atom1", "atom2", "bo", "ebond", "total" );
+  fprintf( out_control->elp, "step: %d\n%6s%12s%12s%12s\n", 
+	   step, "atom", "nlp", "elp", "total" );
+  fprintf( out_control->eov, "step: %d\n%6s%12s%12s\n", 
+	   step, "atom", "eov", "total" );
+  fprintf( out_control->eun, "step: %d\n%6s%12s%12s\n", 
+	   step, "atom", "eun", "total" );
+  fprintf( out_control->eval, "step: %d\n%6s%6s%6s%12s%12s%12s%12s%12s%12s\n", 
+	   step, "atom1", "atom2", "atom3", "angle", "theta0", 
+	   "bo(12)", "bo(23)", "eval", "total" );
+  fprintf( out_control->epen, "step: %d\n%6s%6s%6s%12s%12s%12s%12s%12s\n", 
+	   step, "atom1", "atom2", "atom3", "angle", "bo(12)", "bo(23)",
+	   "epen", "total" );
+  fprintf( out_control->ecoa, "step: %d\n%6s%6s%6s%12s%12s%12s%12s%12s\n", 
+	   step, "atom1", "atom2", "atom3", "angle", "bo(12)", "bo(23)",
+	   "ecoa", "total" );
+  fprintf( out_control->ehb,  "step: %d\n%6s%6s%6s%12s%12s%12s%12s%12s\n", 
+	   step, "atom1", "atom2", "atom3", "r(23)", "angle", "bo(12)", 
+	   "ehb", "total" );
+  fprintf( out_control->etor, "step: %d\n%6s%6s%6s%6s%12s%12s%12s%12s\n", 
+	   step, "atom1", "atom2", "atom3", "atom4", "phi", "bo(23)", 
+	   "etor", "total" );
+  fprintf( out_control->econ,"step:%d\n%6s%6s%6s%6s%12s%12s%12s%12s%12s%12s\n",
+	   step, "atom1", "atom2", "atom3", "atom4", 
+	   "phi", "bo(12)", "bo(23)", "bo(34)", "econ", "total" );
+}
+
+void Debug_Marker_Nonbonded( output_controls *out_control, int step )
+{
+  fprintf( out_control->evdw, "step: %d\n%6s%6s%12s%12s%12s\n",
+	   step, "atom1", "atom2", "r12", "evdw", "total" );
+  fprintf( out_control->ecou, "step: %d\n%6s%6s%12s%12s%12s%12s%12s\n",
+	   step, "atom1", "atom2", "r12", "q1", "q2", "ecou", "total" );
+}
+
+#endif
+
+
+#ifdef TEST_FORCES
+void Dummy_Printer( reax_system *system, control_params *control,
+		    simulation_data *data, storage *workspace, 
+		    reax_list **lists, output_controls *out_control )
+{
+}
+
+
+
+void Print_Bond_Orders( reax_system *system, control_params *control, 
+			simulation_data *data, storage *workspace, 
+			reax_list **lists, output_controls *out_control )
+{
+  int i, pj, pk;
+  bond_order_data *bo_ij;
+  dbond_data *dbo_k;
+  reax_list *bonds = (*lists) + BONDS;
+  reax_list *dBOs  = (*lists) + DBOS;
+
+  /* bond orders */
+  fprintf( out_control->fbo, "step: %d\n", data->step );
+  fprintf( out_control->fbo, "%6s%6s%12s%12s%12s%12s%12s\n", 
+	   "atom1", "atom2", "r_ij", "total_bo", "bo_s", "bo_p", "bo_pp" );
+  
+  for( i = 0; i < system->N; ++i )
+    for( pj = Start_Index(i, bonds); pj < End_Index(i, bonds); ++pj ) {
+	bo_ij = &(bonds->select.bond_list[pj].bo_data);	
+	fprintf( out_control->fbo, 
+		 "%6d%6d%24.15e%24.15e%24.15e%24.15e%24.15e\n", 
+		 system->my_atoms[i].orig_id, 
+		 system->my_atoms[bonds->select.bond_list[pj].nbr].orig_id,
+		 bonds->select.bond_list[pj].d,
+		 bo_ij->BO, bo_ij->BO_s, bo_ij->BO_pi, bo_ij->BO_pi2 );
+    }
+
+
+  /* derivatives of bond orders */
+  fprintf( out_control->fdbo, "step: %d\n", data->step );
+  fprintf( out_control->fdbo, "%6s%6s%6s%24s%24s%24s\n", 
+	   "atom1", "atom2", "atom2", "dBO", "dBOpi", "dBOpi2" ); 
+  for( i = 0; i < system->N; ++i )
+    for( pj = Start_Index(i, bonds); pj < End_Index(i, bonds); ++pj ) {
+      /* fprintf( out_control->fdbo, "%6d %6d\tstart: %6d\tend: %6d\n", 
+	 system->my_atoms[i].orig_id, 
+	 system->my_atoms[bonds->select.bond_list[pj].nbr].orig_id,
+	 Start_Index( pj, dBOs ), End_Index( pj, dBOs ) ); */      
+      for( pk = Start_Index(pj, dBOs); pk < End_Index(pj, dBOs); ++pk ) {
+	dbo_k = &(dBOs->select.dbo_list[pk]);
+	fprintf( out_control->fdbo, "%6d%6d%6d%24.15e%24.15e%24.15e\n",
+		 system->my_atoms[i].orig_id, 
+		 system->my_atoms[bonds->select.bond_list[pj].nbr].orig_id,
+		 system->my_atoms[dbo_k->wrt].orig_id,
+		 dbo_k->dBO[0], dbo_k->dBO[1], dbo_k->dBO[2] );
+	
+	fprintf( out_control->fdbo, "%6d%6d%6d%24.15e%24.15e%24.15e\n",
+		 system->my_atoms[i].orig_id, 
+		 system->my_atoms[bonds->select.bond_list[pj].nbr].orig_id,
+		 system->my_atoms[dbo_k->wrt].orig_id,
+		 dbo_k->dBOpi[0], dbo_k->dBOpi[1], dbo_k->dBOpi[2] );
+	
+	fprintf( out_control->fdbo, "%6d%6d%6d%24.15e%24.15e%24.15e\n",
+		 system->my_atoms[i].orig_id, 
+		 system->my_atoms[bonds->select.bond_list[pj].nbr].orig_id,
+		 system->my_atoms[dbo_k->wrt].orig_id,
+		 dbo_k->dBOpi2[0], dbo_k->dBOpi2[1], dbo_k->dBOpi2[2] ); 
+      }
+    }
+}
+
+
+void Print_Forces( FILE *f, storage *workspace, int N, int step )
+{
+  int i;
+
+  fprintf( f, "step: %d\n", step );
+  for( i = 0; i < N; ++i )
+    //fprintf( f, "%6d %23.15e %23.15e %23.15e\n", 
+    //fprintf( f, "%6d%12.6f%12.6f%12.6f\n", 
+    fprintf( f, "%6d %19.9e %19.9e %19.9e\n", 
+	     workspace->id_all[i], workspace->f_all[i][0], 
+	     workspace->f_all[i][1], workspace->f_all[i][2] );	     
+}
+
+
+void Print_Force_Files( reax_system *system, control_params *control, 
+		        simulation_data *data, storage *workspace, 
+		        reax_list **lists, output_controls *out_control, 
+			mpi_datatypes *mpi_data )
+{
+  int i, d; 
+
+  Coll_ids_at_Master( system, workspace, mpi_data );
+
+  Print_Bond_Orders( system, control, data, workspace, lists, out_control );
+
+  Coll_rvecs_at_Master( system, workspace, mpi_data, workspace->f_be );
+  if( system->my_rank == MASTER_NODE )
+    Print_Forces( out_control->fbond, workspace, system->bigN, data->step );
+
+  Coll_rvecs_at_Master( system, workspace, mpi_data, workspace->f_lp );
+  if( system->my_rank == MASTER_NODE )
+    Print_Forces( out_control->flp, workspace, system->bigN, data->step );
+
+  Coll_rvecs_at_Master( system, workspace, mpi_data, workspace->f_ov );
+  if( system->my_rank == MASTER_NODE )
+    Print_Forces( out_control->fov, workspace, system->bigN, data->step );
+
+  Coll_rvecs_at_Master( system, workspace, mpi_data, workspace->f_un );
+  if( system->my_rank == MASTER_NODE )
+    Print_Forces( out_control->fun, workspace, system->bigN, data->step );
+
+  Coll_rvecs_at_Master( system, workspace, mpi_data, workspace->f_ang );
+  if( system->my_rank == MASTER_NODE )
+    Print_Forces( out_control->fang, workspace, system->bigN, data->step );
+
+  Coll_rvecs_at_Master( system, workspace, mpi_data, workspace->f_coa );
+  if( system->my_rank == MASTER_NODE )
+    Print_Forces( out_control->fcoa, workspace, system->bigN, data->step );
+
+  Coll_rvecs_at_Master( system, workspace, mpi_data, workspace->f_pen );
+  if( system->my_rank == MASTER_NODE )
+    Print_Forces( out_control->fpen, workspace, system->bigN, data->step );
+
+  Coll_rvecs_at_Master( system, workspace, mpi_data, workspace->f_tor );
+  if( system->my_rank == MASTER_NODE )
+    Print_Forces( out_control->ftor, workspace, system->bigN, data->step );
+
+  Coll_rvecs_at_Master( system, workspace, mpi_data, workspace->f_con );
+  if( system->my_rank == MASTER_NODE )
+    Print_Forces( out_control->fcon, workspace, system->bigN, data->step );
+
+  Coll_rvecs_at_Master( system, workspace, mpi_data, workspace->f_hb );
+  if( system->my_rank == MASTER_NODE )
+    Print_Forces( out_control->fhb, workspace, system->bigN, data->step );
+
+  Coll_rvecs_at_Master( system, workspace, mpi_data, workspace->f_vdw );
+  if( system->my_rank == MASTER_NODE )
+    Print_Forces( out_control->fvdw, workspace, system->bigN, data->step );
+
+  Coll_rvecs_at_Master( system, workspace, mpi_data, workspace->f_ele );
+  if( system->my_rank == MASTER_NODE )
+    Print_Forces( out_control->fele, workspace, system->bigN, data->step );
+
+  Coll_rvecs_at_Master( system, workspace, mpi_data, workspace->f );
+  if( system->my_rank == MASTER_NODE )
+    Print_Forces( out_control->ftot, workspace, system->bigN, data->step );
+
+  for( i = 0; i < system->n; ++i ) {
+    for( d = 0; d < 3; ++d )
+      workspace->f_tot[i][d] = workspace->f_be[i][d] + 
+	workspace->f_lp[i][d]+workspace->f_ov[i][d]+workspace->f_un[i][d] + 
+	workspace->f_ang[i][d]+workspace->f_pen[i][d]+workspace->f_coa[i][d] +
+	workspace->f_tor[i][d]+workspace->f_con[i][d] + 
+	workspace->f_vdw[i][d]+workspace->f_ele[i][d] +
+	workspace->f_hb[i][d];
+  }
+
+  Coll_rvecs_at_Master( system, workspace, mpi_data, workspace->f_tot );
+  if( system->my_rank == MASTER_NODE )
+    Print_Forces( out_control->fcomp, workspace, system->bigN, data->step );
+}
+#endif
+
+
+#if defined(TEST_FORCES) || defined(TEST_ENERGY) 
+
+void Print_Far_Neighbors_List( reax_system *system, reax_list **lists, 
+			       control_params *control, simulation_data *data, 
+			       output_controls *out_control )
+{
+  int   i, j, id_i, id_j, nbr, natoms;  
+  int num=0;
+  int temp[500];
+  reax_list *far_nbrs;
+
+  far_nbrs = (*lists) + FAR_NBRS;
+  fprintf( out_control->flist, "step: %d\n", data->step );
+  fprintf( out_control->flist, "%6s\t%-38s\n", "atom", "Far_nbrs_list");
+
+
+  natoms = system->n;
+  for( i = 0; i < natoms; ++i ) {
+    id_i = system->my_atoms[i].orig_id;
+    fprintf( out_control->flist, "%6d:",id_i);
+    num=0;
+    
+    for( j = Start_Index(i,far_nbrs); j < End_Index(i,far_nbrs); ++j ) {
+      nbr = far_nbrs->select.far_nbr_list[j].nbr;
+      id_j = system->my_atoms[nbr].orig_id;
+      temp[num++] = id_j;
+    }
+    
+    qsort(&temp, num, sizeof(int), fn_qsort_intcmp);
+    for(j=0; j < num; j++)
+      fprintf(out_control->flist, "%6d",temp[j]);
+    fprintf( out_control->flist, "\n");
+  }
+}
+
+void Print_Bond_List( reax_system *system, control_params *control, 
+		      simulation_data *data, reax_list **lists, 
+		      output_controls *out_control)
+{
+  int i,j, id_i, id_j, nbr, pj;
+  reax_list *bonds = (*lists) + BONDS;
+
+  int temp[500];
+  int num=0;
+
+  fprintf( out_control->blist, "step: %d\n", data->step );
+  fprintf( out_control->blist, "%6s\t%-38s\n", "atom", "Bond_list");
+
+  /* bond list */
+  for( i = 0; i < system->n; ++i ) {
+    num=0;
+    id_i = system->my_atoms[i].orig_id;
+    fprintf( out_control->blist, "%6d:", id_i);
+    for( pj = Start_Index(i, bonds); pj < End_Index(i, bonds); ++pj ) {
+      nbr = bonds->select.bond_list[pj].nbr;	
+      id_j = system->my_atoms[nbr].orig_id;
+      if( id_i < id_j ) 
+	temp[num++] = id_j;
+    }
+    
+    qsort(&temp, num, sizeof(int), fn_qsort_intcmp);
+    for(j=0; j < num; j++)
+      fprintf(out_control->blist, "%6d",temp[j]);
+    fprintf(out_control->blist, "\n");
+  }
+}
+
+
+#endif
+
+
+#ifdef OLD_VERSION
+void Print_Init_Atoms( reax_system *system, storage *workspace )
+{
+  int i;
+
+  fprintf( stderr, "p%d had %d atoms\n",
+	   system->my_rank, workspace->init_cnt );
+
+  for( i = 0; i < workspace->init_cnt; ++i )
+    fprintf( stderr, "p%d, atom%d: %d  %s  %8.3f %8.3f %8.3f\n",
+	     system->my_rank, i, 
+	     workspace->init_atoms[i].type, workspace->init_atoms[i].name, 
+	     workspace->init_atoms[i].x[0], 
+	     workspace->init_atoms[i].x[1], 
+	     workspace->init_atoms[i].x[2] );
+}
+#endif //OLD_VERSION
+
+
+/*void Print_Bond_Forces( reax_system *system, control_params *control, 
+			simulation_data *data, storage *workspace, 
+			reax_list **lists, output_controls *out_control )
+{
+  int i;
+
+  fprintf( out_control->fbond, "step: %d\n", data->step );
+  fprintf( out_control->fbond, "%6s%24s%24s%24s\n", 
+	   "atom", "f_be[0]", "f_be[1]", "f_be[2]" ); 
+  
+  for( i = 0; i < system->bigN; ++i )
+    fprintf(out_control->fbond, "%6d%24.15e%24.15e%24.15e\n",
+	    system->my_atoms[i].orig_id, 
+	    workspace->f_all[i][0], workspace->f_all[i][1], 
+	    workspace->f_all[i][2]);
+}
+
+void Print_LonePair_Forces( reax_system *system, control_params *control, 
+			    simulation_data *data, storage *workspace, 
+			    reax_list **lists, output_controls *out_control )
+{
+  int i;
+
+  fprintf( out_control->flp, "step: %d\n", data->step );
+  fprintf( out_control->flp, "%6s%24s\n", "atom", "f_lonepair" );
+  
+  for( i = 0; i < system->bigN; ++i )
+    fprintf(out_control->flp, "%6d%24.15e%24.15e%24.15e\n",
+	    system->my_atoms[i].orig_id, 
+	    workspace->f_all[i][0], workspace->f_all[i][1], 
+	    workspace->f_all[i][2]);
+}
+
+
+void Print_OverCoor_Forces( reax_system *system, control_params *control,
+			    simulation_data *data, storage *workspace, 
+			    reax_list **lists, output_controls *out_control )
+{
+  int i;
+
+  fprintf( out_control->fov, "step: %d\n", data->step );
+  fprintf( out_control->fov, "%6s%-38s%-38s%-38s\n", 
+	   "atom","f_over[0]", "f_over[1]", "f_over[2]" );
+  
+  for( i = 0; i < system->bigN; ++i )
+    fprintf( out_control->fov, 
+	     "%6d %24.15e%24.15e%24.15e 0 0 0\n",
+	     system->my_atoms[i].orig_id, 
+	     workspace->f_all[i][0], workspace->f_all[i][1], 
+	     workspace->f_all[i][2] );
+}
+
+
+void Print_UnderCoor_Forces( reax_system *system, control_params *control,
+			     simulation_data *data, storage *workspace, 
+			     reax_list **lists, output_controls *out_control )
+{
+  int i;
+
+  fprintf( out_control->fun, "step: %d\n", data->step );
+  fprintf( out_control->fun, "%6s%-38s%-38s%-38s\n", 
+	   "atom","f_under[0]", "f_under[1]", "f_under[2]" );
+  
+  for( i = 0; i < system->bigN; ++i )
+    fprintf( out_control->fun, 
+	     "%6d %24.15e%24.15e%24.15e 0 0 0\n",
+	     system->my_atoms[i].orig_id, 
+	     workspace->f_all[i][0], workspace->f_all[i][1], 
+	     workspace->f_all[i][2] );
+}
+
+
+void Print_ValAngle_Forces( reax_system *system, control_params *control, 
+			    simulation_data *data, storage *workspace, 
+			    reax_list **lists, output_controls *out_control )
+{
+  int j;
+
+  fprintf( out_control->f3body, "step: %d\n", data->step );
+  fprintf( out_control->f3body, "%6s%-37s%-37s%-37s%-38s\n", 
+	   "atom", "3-body total", "f_ang", "f_pen", "f_coa" );
+  
+  for( j = 0; j < system->N; ++j ){
+    if( rvec_isZero(workspace->f_pen[j]) && rvec_isZero(workspace->f_coa[j]) )
+      fprintf( out_control->f3body, 
+	       "%6d %24.15e%24.15e%24.15e  0 0 0  0 0 0\n",
+	       system->my_atoms[j].orig_id, 
+	       workspace->f_ang[j][0], workspace->f_ang[j][1], 
+	       workspace->f_ang[j][2] );
+    else if( rvec_isZero(workspace->f_coa[j]) )
+      fprintf( out_control->f3body, 
+	       "%6d %24.15e%24.15e%24.15e %24.15e%24.15e%24.15e "	\
+	       "%24.15e%24.15e%24.15e\n",
+	       system->my_atoms[j].orig_id, 
+	       workspace->f_ang[j][0] + workspace->f_pen[j][0],
+	       workspace->f_ang[j][1] + workspace->f_pen[j][1],
+	       workspace->f_ang[j][2] + workspace->f_pen[j][2],
+	       workspace->f_ang[j][0], workspace->f_ang[j][1],
+	       workspace->f_ang[j][2],
+	       workspace->f_pen[j][0], workspace->f_pen[j][1],
+	       workspace->f_pen[j][2] );
+    else{
+      fprintf( out_control->f3body, "%6d %24.15e%24.15e%24.15e ",
+	     system->my_atoms[j].orig_id, 
+	       workspace->f_ang[j][0] + workspace->f_pen[j][0] + 
+	       workspace->f_coa[j][0],
+	       workspace->f_ang[j][1] + workspace->f_pen[j][1] + 
+	       workspace->f_coa[j][1],
+	       workspace->f_ang[j][2] + workspace->f_pen[j][2] + 
+	       workspace->f_coa[j][2] );
+    
+      fprintf( out_control->f3body, 
+	       "%24.15e%24.15e%24.15e %24.15e%24.15e%24.15e "\
+	       "%24.15e%24.15e%24.15e\n",
+	       workspace->f_ang[j][0], workspace->f_ang[j][1],
+	       workspace->f_ang[j][2],
+	       workspace->f_pen[j][0], workspace->f_pen[j][1],
+	       workspace->f_pen[j][2],
+	       workspace->f_coa[j][0], workspace->f_coa[j][1],
+	       workspace->f_coa[j][2] );
+	}
+  }
+}
+
+
+void Print_Hydrogen_Bond_Forces( reax_system *system, control_params *control, 
+				 simulation_data *data, storage *workspace, 
+				 reax_list **lists, output_controls *out_control)
+{
+  int j;
+
+  fprintf( out_control->fhb, "step: %d\n", data->step );
+  fprintf( out_control->fhb, "%6s\t%-38s\n", "atom", "f_hb[0,1,2]" );
+  
+  for( j = 0; j < system->N; ++j )
+    fprintf(out_control->fhb, "%6d%24.15e%24.15e%24.15e\n",
+	     system->my_atoms[j].orig_id, 
+	     workspace->f_hb[j][0], 
+	     workspace->f_hb[j][1], 
+	     workspace->f_hb[j][2] );
+}
+
+
+void Print_Four_Body_Forces( reax_system *system, control_params *control, 
+			     simulation_data *data, storage *workspace, 
+			     reax_list **lists, output_controls *out_control )
+{
+  int j;
+
+  fprintf( out_control->f4body, "step: %d\n", data->step );
+  fprintf( out_control->f4body, "%6s\t%-38s%-38s%-38s\n", 
+	   "atom", "4-body total", "f_tor", "f_con" );
+
+  for( j = 0; j < system->N; ++j ){
+    if( !rvec_isZero( workspace->f_con[j] ) )
+      fprintf( out_control->f4body, 
+	       "%6d %24.15e%24.15e%24.15e %24.15e%24.15e%24.15e "\
+	       "%24.15e%24.15e%24.15e\n",
+	     system->my_atoms[j].orig_id, 
+	       workspace->f_tor[j][0] + workspace->f_con[j][0], 
+	       workspace->f_tor[j][1] + workspace->f_con[j][1], 
+	       workspace->f_tor[j][2] + workspace->f_con[j][2],
+	       workspace->f_tor[j][0], workspace->f_tor[j][1], 
+	       workspace->f_tor[j][2],
+	       workspace->f_con[j][0], workspace->f_con[j][1], 
+	       workspace->f_con[j][2] );
+    else
+      fprintf( out_control->f4body, 
+	       "%6d %24.15e%24.15e%24.15e  0 0 0\n",
+	       system->my_atoms[j].orig_id, workspace->f_tor[j][0],
+	       workspace->f_tor[j][1], workspace->f_tor[j][2] );
+  }
+
+}
+
+
+void Print_vdW_Coulomb_Forces( reax_system *system, control_params *control, 
+			       simulation_data *data, storage *workspace, 
+			       reax_list **lists, output_controls *out_control )
+{
+  int  i;
+
+  return;
+
+  fprintf( out_control->fnonb, "step: %d\n", data->step );
+  fprintf( out_control->fnonb, "%6s\t%-38s%-38s%-38s\n", 
+	   "atom", "nonbonded_total[0,1,2]", "f_vdw[0,1,2]", "f_ele[0,1,2]" );
+
+  for( i = 0; i < system->N; ++i )
+    fprintf( out_control->fnonb, 
+	     "%6d%24.15e%24.15e%24.15e%24.15e%24.15e%24.15e%24.15e%24.15e%24.15e\n", 
+	     system->my_atoms[i].orig_id, 
+	     workspace->f_vdw[i][0] + workspace->f_ele[i][0],
+	     workspace->f_vdw[i][1] + workspace->f_ele[i][1], 
+	     workspace->f_vdw[i][2] + workspace->f_ele[i][2],
+	     workspace->f_vdw[i][0], 
+	     workspace->f_vdw[i][1], 
+	     workspace->f_vdw[i][2],
+	     workspace->f_ele[i][0], 
+	     workspace->f_ele[i][1], 
+	     workspace->f_ele[i][2] );
+}
+
+
+void Print_Total_Force( reax_system *system, control_params *control, 
+			simulation_data *data, storage *workspace, 
+			reax_list **lists, output_controls *out_control )
+{
+  int    i;
+
+  return;
+
+  fprintf( out_control->ftot, "step: %d\n", data->step );
+  fprintf( out_control->ftot, "%6s\t%-38s\n", "atom", "atom.f[0,1,2]");
+
+  for( i = 0; i < system->n; ++i )
+    fprintf( out_control->ftot, "%6d%24.15e%24.15e%24.15e\n", 
+	     system->my_atoms[i].orig_id,
+	     system->my_atoms[i].f[0], 
+	     system->my_atoms[i].f[1], 
+	     system->my_atoms[i].f[2] );
+}
+
+
+void Compare_Total_Forces( reax_system *system, control_params *control, 
+			   simulation_data *data, storage *workspace, 
+			   reax_list **lists, output_controls *out_control )
+{
+  int i;
+
+  return;
+
+  fprintf( out_control->ftot2, "step: %d\n", data->step );
+  fprintf( out_control->ftot2, "%6s\t%-38s%-38s\n", 
+	   "atom", "f_total[0,1,2]", "test_force_total[0,1,2]" );
+
+  for( i = 0; i < system->N; ++i )
+    fprintf( out_control->ftot2, "%6d%24.15e%24.15e%24.15e%24.15e%24.15e%24.15e\n", 
+	     system->my_atoms[i].orig_id,
+	     system->my_atoms[i].f[0], 
+	     system->my_atoms[i].f[1], 
+	     system->my_atoms[i].f[2],
+	     workspace->f_be[i][0] + workspace->f_lp[i][0] + 
+	     workspace->f_ov[i][0] + workspace->f_un[i][0] + 
+	     workspace->f_ang[i][0]+ workspace->f_pen[i][0]+ 
+	     workspace->f_coa[i][0]+ + workspace->f_hb[i][0] + 
+	     workspace->f_tor[i][0] + workspace->f_con[i][0] + 
+	     workspace->f_vdw[i][0] + workspace->f_ele[i][0],
+	     workspace->f_be[i][1] + workspace->f_lp[i][1] + 
+	     workspace->f_ov[i][1] + workspace->f_un[i][1] + 
+             workspace->f_ang[i][1]+ workspace->f_pen[i][1]+ 
+	     workspace->f_coa[i][1]+ + workspace->f_hb[i][1] + 
+	     workspace->f_tor[i][1] + workspace->f_con[i][1] + 
+	     workspace->f_vdw[i][1] + workspace->f_ele[i][1], 
+	     workspace->f_be[i][2] + workspace->f_lp[i][2] + 
+	     workspace->f_ov[i][2] + workspace->f_un[i][2] + 
+             workspace->f_ang[i][2]+ workspace->f_pen[i][2] + 
+	     workspace->f_coa[i][2]+ + workspace->f_hb[i][2] + 
+	     workspace->f_tor[i][2] + workspace->f_con[i][2] + 
+	     workspace->f_vdw[i][2] + workspace->f_ele[i][2] );
+}*/
+
+/*void Init_Force_Test_Functions( )
+{
+  Print_Interactions[0] = Print_Bond_Orders;
+  Print_Interactions[1] = Print_Bond_Forces;
+  Print_Interactions[2] = Print_LonePair_Forces;
+  Print_Interactions[3] = Print_OverUnderCoor_Forces;
+  Print_Interactions[4] = Print_Three_Body_Forces;
+  Print_Interactions[5] = Print_Four_Body_Forces;
+  Print_Interactions[6] = Print_Hydrogen_Bond_Forces;
+  Print_Interactions[7] = Print_vdW_Coulomb_Forces;
+  Print_Interactions[8] = Print_Total_Force;
+  Print_Interactions[9] = Compare_Total_Forces;
+  }*/
diff --git a/src/USER-REAXC/reaxc_io_tools.h b/src/USER-REAXC/reaxc_io_tools.h
new file mode 100644
index 0000000000..c009f14df7
--- /dev/null
+++ b/src/USER-REAXC/reaxc_io_tools.h
@@ -0,0 +1,107 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#ifndef __IO_TOOLS_H_
+#define __IO_TOOLS_H_
+
+#include "reaxc_types.h"
+
+int Init_Output_Files( reax_system*, control_params*, 
+		       output_controls*, mpi_datatypes*, char* );
+int Close_Output_Files( reax_system*, control_params*,  
+			output_controls*, mpi_datatypes* );
+
+void  Print_Box( simulation_box*, char*, FILE* );
+
+void  Print_Grid( grid*, FILE* );
+void  Print_GCell_Exchange_Bounds( int, neighbor_proc* );
+void  Print_Native_GCells( reax_system* );
+void  Print_All_GCells( reax_system*);
+
+void  Print_Init_Atoms( reax_system*, storage* );
+void  Print_My_Atoms( reax_system* );
+void  Print_My_Ext_Atoms( reax_system* );
+
+void  Print_Far_Neighbors( reax_system*, reax_list**, control_params *);
+void  Print_Sparse_Matrix( reax_system*, sparse_matrix* );
+void  Print_Sparse_Matrix2( reax_system*, sparse_matrix*, char* );
+void  Print_Linear_System( reax_system*, control_params*, storage*, int );
+void  Print_LinSys_Soln( reax_system*, real*, real*, real* );
+void  Print_Charges( reax_system* );
+void  Print_Bonds( reax_system*, reax_list*, char* );
+void  Print_Bond_List2( reax_system*, reax_list*, char* );
+void  Print_Total_Force( reax_system*, simulation_data*, storage* );
+void  Output_Results( reax_system*, control_params*, simulation_data*, 
+		      reax_list**, output_controls*, mpi_datatypes* );
+
+#if defined(DEBUG_FOCUS) || defined(TEST_FORCES) || defined(TEST_ENERGY) 
+void Debug_Marker_Bonded( output_controls*, int );
+void Debug_Marker_Nonbonded( output_controls*, int );
+void  Print_Near_Neighbors_List( reax_system*, reax_list**, control_params*, 
+				 simulation_data*, output_controls* );
+void  Print_Far_Neighbors_List( reax_system*, reax_list**, control_params*, 
+				simulation_data*, output_controls* );
+void  Print_Bond_List( reax_system*, control_params*, simulation_data*, 
+		       reax_list**, output_controls* );
+/*void Dummy_Printer( reax_system*, control_params*, simulation_data*, 
+		    storage*, reax_list**, output_controls* );
+void Print_Bond_Orders( reax_system*, control_params*, simulation_data*, 
+			storage*, reax_list**, output_controls* );
+void Print_Bond_Forces( reax_system*, control_params*, simulation_data*, 
+			storage*, reax_list**, output_controls* );
+void Print_LonePair_Forces( reax_system*, control_params*, simulation_data*, 
+			    storage*, reax_list**, output_controls* );
+void Print_OverUnderCoor_Forces( reax_system*, control_params*, 
+				 simulation_data*, storage*, reax_list**, 
+				 output_controls* );
+void Print_Three_Body_Forces( reax_system*, control_params*, simulation_data*, 
+				 storage*, reax_list**, output_controls* );
+void Print_Hydrogen_Bond_Forces( reax_system*, control_params*, 
+				 simulation_data*, storage*, reax_list**, 
+				 output_controls* );
+void Print_Four_Body_Forces( reax_system*, control_params*, simulation_data*, 
+				 storage*, reax_list**, output_controls* );
+void Print_vdW_Coulomb_Forces( reax_system*, control_params*, 
+			       simulation_data*, storage*, reax_list**, 
+			       output_controls* );
+void Print_Total_Force( reax_system*, control_params*, simulation_data*, 
+			storage*, reax_list**, output_controls* );
+void Compare_Total_Forces( reax_system*, control_params*, simulation_data*, 
+storage*, reax_list**, output_controls* );*/
+//void  Print_Total_Force( reax_system*, control_params* );
+void Print_Force_Files( reax_system*, control_params*, simulation_data*, 
+			storage*, reax_list**, output_controls*, 
+			mpi_datatypes * );
+//void Init_Force_Test_Functions( );
+
+int fn_qsort_intcmp( const void *, const void * ); 
+
+void Print_Far_Neighbors_List( reax_system*, reax_list**, control_params*, 
+			       simulation_data*, output_controls* );
+
+void Print_Near_Neighbors_List( reax_system*, reax_list**, control_params*,
+				simulation_data*, output_controls* );
+
+void Print_Bond_List( reax_system*, control_params*, simulation_data*, 
+		      reax_list**, output_controls*);
+
+#endif
+#endif
diff --git a/src/USER-REAXC/reaxc_list.cpp b/src/USER-REAXC/reaxc_list.cpp
new file mode 100644
index 0000000000..0ea3d7d875
--- /dev/null
+++ b/src/USER-REAXC/reaxc_list.cpp
@@ -0,0 +1,157 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#include "reaxc_types.h"
+#if defined(PURE_REAX)
+#include "list.h"
+#include "tool_box.h"
+#elif defined(LAMMPS_REAX)
+#include "reaxc_list.h"
+#include "reaxc_tool_box.h"
+#endif
+
+
+/************* allocate list space ******************/
+int Make_List(int n, int num_intrs, int type, reax_list *l, MPI_Comm comm)
+{
+  l->allocated = 1;
+  
+  l->n = n;
+  l->num_intrs = num_intrs;
+    
+  l->index = (int*) smalloc( n * sizeof(int), "list:index", comm );
+  l->end_index = (int*) smalloc( n * sizeof(int), "list:end_index", comm );
+
+  l->type = type;
+#if defined(DEBUG_FOCUS)
+  fprintf( stderr, "list: n=%d num_intrs=%d type=%d\n", n, num_intrs, type );
+#endif
+
+  switch(l->type) {
+  case TYP_VOID:
+    l->select.v = (void*) smalloc(l->num_intrs * sizeof(void*), "list:v", comm);
+    break;
+    
+  case TYP_THREE_BODY:
+    l->select.three_body_list = (three_body_interaction_data*) 
+      smalloc( l->num_intrs * sizeof(three_body_interaction_data), 
+	       "list:three_bodies", comm );
+    break;
+    
+  case TYP_BOND:
+    l->select.bond_list = (bond_data*) 
+      smalloc( l->num_intrs * sizeof(bond_data), "list:bonds", comm );
+    break;
+    
+  case TYP_DBO:
+    l->select.dbo_list = (dbond_data*) 
+      smalloc( l->num_intrs * sizeof(dbond_data), "list:dbonds", comm );
+    break;
+    
+  case TYP_DDELTA:
+    l->select.dDelta_list = (dDelta_data*) 
+      smalloc( l->num_intrs * sizeof(dDelta_data), "list:dDeltas", comm );
+    break;
+    
+  case TYP_FAR_NEIGHBOR:
+    l->select.far_nbr_list = (far_neighbor_data*) 
+      smalloc(l->num_intrs * sizeof(far_neighbor_data), "list:far_nbrs", comm);
+    break;
+        
+  case TYP_HBOND:
+    l->select.hbond_list = (hbond_data*)
+      smalloc( l->num_intrs * sizeof(hbond_data), "list:hbonds", comm );
+    break;			
+    
+  default:
+    fprintf( stderr, "ERROR: no %d list type defined!\n", l->type );
+    MPI_Abort( comm, INVALID_INPUT );
+  }
+
+  return SUCCESS;
+}
+
+
+void Delete_List( reax_list *l, MPI_Comm comm )
+{
+  if( l->allocated == 0 )
+    return;
+  l->allocated = 0;
+
+  sfree( l->index, "list:index" );
+  sfree( l->end_index, "list:end_index" );
+  
+  switch(l->type) {
+  case TYP_VOID:
+    sfree( l->select.v, "list:v" );
+    break;
+  case TYP_HBOND:
+    sfree( l->select.hbond_list, "list:hbonds" );
+    break;
+  case TYP_FAR_NEIGHBOR:
+    sfree( l->select.far_nbr_list, "list:far_nbrs" );
+    break;
+  case TYP_BOND:
+    sfree( l->select.bond_list, "list:bonds" );
+    break;
+  case TYP_DBO:
+    sfree( l->select.dbo_list, "list:dbos" );
+    break;
+  case TYP_DDELTA:
+    sfree( l->select.dDelta_list, "list:dDeltas" );
+    break;
+  case TYP_THREE_BODY:
+    sfree( l->select.three_body_list, "list:three_bodies" );
+    break;
+
+  default:
+    fprintf( stderr, "ERROR: no %d list type defined!\n", l->type );
+    MPI_Abort( comm, INVALID_INPUT );
+  }
+}
+
+
+#if defined(PURE_REAX)
+inline int Num_Entries( int i, reax_list *l )
+{
+  return l->end_index[i] - l->index[i];
+}
+
+inline int Start_Index( int i, reax_list *l )
+{
+  return l->index[i];
+}
+
+inline int End_Index( int i, reax_list *l )
+{
+  return l->end_index[i];
+}
+
+inline void Set_Start_Index( int i, int val, reax_list *l )
+{
+  l->index[i] = val;
+}
+
+inline void Set_End_Index( int i, int val, reax_list *l )
+{
+  l->end_index[i] = val;
+}
+#endif
diff --git a/src/USER-REAXC/reaxc_list.h b/src/USER-REAXC/reaxc_list.h
new file mode 100644
index 0000000000..cca217dbf7
--- /dev/null
+++ b/src/USER-REAXC/reaxc_list.h
@@ -0,0 +1,63 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#ifndef __LIST_H_
+#define __LIST_H_
+
+#include "reaxc_types.h"
+
+int  Make_List( int, int, int, reax_list*, MPI_Comm );
+void Delete_List( reax_list*, MPI_Comm );
+
+inline int  Num_Entries(int,reax_list*);
+inline int  Start_Index( int, reax_list* );
+inline int  End_Index( int, reax_list* );
+inline void Set_Start_Index(int,int,reax_list*);
+inline void Set_End_Index(int,int,reax_list*);
+
+#if defined(LAMMPS_REAX)
+inline int Num_Entries( int i, reax_list *l )
+{
+  return l->end_index[i] - l->index[i];
+}
+
+inline int Start_Index( int i, reax_list *l )
+{
+  return l->index[i];
+}
+
+inline int End_Index( int i, reax_list *l )
+{
+  return l->end_index[i];
+}
+
+inline void Set_Start_Index( int i, int val, reax_list *l )
+{
+  l->index[i] = val;
+}
+
+inline void Set_End_Index( int i, int val, reax_list *l )
+{
+  l->end_index[i] = val;
+}
+#endif // LAMMPS_REAX
+
+#endif
diff --git a/src/USER-REAXC/reaxc_lookup.cpp b/src/USER-REAXC/reaxc_lookup.cpp
new file mode 100644
index 0000000000..a4b851b9d8
--- /dev/null
+++ b/src/USER-REAXC/reaxc_lookup.cpp
@@ -0,0 +1,339 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#include "reaxc_types.h"
+#if defined(PURE_REAX)
+#include "lookup.h"
+#include "nonbonded.h"
+#include "tool_box.h"
+#elif defined(LAMMPS_REAX)
+#include "reaxc_lookup.h"
+#include "reaxc_nonbonded.h"
+#include "reaxc_tool_box.h"
+#endif
+
+LR_lookup_table **LR;
+
+/* Fills solution into x. Warning: will modify c and d! */
+void Tridiagonal_Solve( const real *a, const real *b, 
+			real *c, real *d, real *x, unsigned int n){
+  int i;
+  real id;
+ 
+  /* Modify the coefficients. */
+  c[0] /= b[0];	/* Division by zero risk. */
+  d[0] /= b[0];	/* Division by zero would imply a singular matrix. */
+  for(i = 1; i < n; i++){
+    id = (b[i] - c[i-1] * a[i]);  /* Division by zero risk. */
+    c[i] /= id;	        /* Last value calculated is redundant. */
+    d[i] = (d[i] - d[i-1] * a[i])/id;
+  }
+  
+  /* Now back substitute. */
+  x[n - 1] = d[n - 1];
+  for(i = n - 2; i >= 0; i--)
+    x[i] = d[i] - c[i] * x[i + 1];
+}
+
+
+void Natural_Cubic_Spline( const real *h, const real *f, 
+			   cubic_spline_coef *coef, unsigned int n, 
+			   MPI_Comm comm )
+{
+  int i;
+  real *a, *b, *c, *d, *v;
+
+  /* allocate space for the linear system */
+  a = (real*) smalloc( n * sizeof(real), "cubic_spline:a", comm );
+  b = (real*) smalloc( n * sizeof(real), "cubic_spline:a", comm );
+  c = (real*) smalloc( n * sizeof(real), "cubic_spline:a", comm );
+  d = (real*) smalloc( n * sizeof(real), "cubic_spline:a", comm );
+  v = (real*) smalloc( n * sizeof(real), "cubic_spline:a", comm );
+
+  /* build the linear system */
+  a[0] = a[1] = a[n-1] = 0;
+  for( i = 2; i < n-1; ++i )
+    a[i] = h[i-1];
+
+  b[0] = b[n-1] = 0;
+  for( i = 1; i < n-1; ++i )
+    b[i] = 2 * (h[i-1] + h[i]); 
+
+  c[0] = c[n-2] = c[n-1] = 0;
+  for( i = 1; i < n-2; ++i )
+    c[i] = h[i];
+
+  d[0] = d[n-1] = 0;
+  for( i = 1; i < n-1; ++i )
+    d[i] = 6 * ((f[i+1]-f[i])/h[i] - (f[i]-f[i-1])/h[i-1]);
+  
+  v[0] = 0;
+  v[n-1] = 0;
+  Tridiagonal_Solve( &(a[1]), &(b[1]), &(c[1]), &(d[1]), &(v[1]), n-2 );
+  
+  for( i = 1; i < n; ++i ){
+    coef[i-1].d = (v[i] - v[i-1]) / (6*h[i-1]);
+    coef[i-1].c = v[i]/2;
+    coef[i-1].b = (f[i]-f[i-1])/h[i-1] + h[i-1]*(2*v[i] + v[i-1])/6;
+    coef[i-1].a = f[i];
+  }
+
+  sfree( a, "cubic_spline:a" );
+  sfree( b, "cubic_spline:b" );
+  sfree( c, "cubic_spline:c" );
+  sfree( d, "cubic_spline:d" );
+  sfree( v, "cubic_spline:v" );
+}
+
+
+
+void Complete_Cubic_Spline( const real *h, const real *f, real v0, real vlast,
+			    cubic_spline_coef *coef, unsigned int n, 
+			    MPI_Comm comm )
+{
+  int i;
+  real *a, *b, *c, *d, *v;
+
+  /* allocate space for the linear system */
+  a = (real*) smalloc( n * sizeof(real), "cubic_spline:a", comm );
+  b = (real*) smalloc( n * sizeof(real), "cubic_spline:a", comm );
+  c = (real*) smalloc( n * sizeof(real), "cubic_spline:a", comm );
+  d = (real*) smalloc( n * sizeof(real), "cubic_spline:a", comm );
+  v = (real*) smalloc( n * sizeof(real), "cubic_spline:a", comm );
+
+  /* build the linear system */
+  a[0] = 0;
+  for( i = 1; i < n; ++i )
+    a[i] = h[i-1];
+
+  b[0] = 2*h[0];
+  for( i = 1; i < n; ++i )
+    b[i] = 2 * (h[i-1] + h[i]); 
+
+  c[n-1] = 0;
+  for( i = 0; i < n-1; ++i )
+    c[i] = h[i];
+
+  d[0] = 6 * (f[1]-f[0])/h[0] - 6 * v0;   
+  d[n-1] = 6 * vlast - 6 * (f[n-1]-f[n-2]/h[n-2]);
+  for( i = 1; i < n-1; ++i )
+    d[i] = 6 * ((f[i+1]-f[i])/h[i] - (f[i]-f[i-1])/h[i-1]);
+
+  Tridiagonal_Solve( &(a[0]), &(b[0]), &(c[0]), &(d[0]), &(v[0]), n );
+
+  for( i = 1; i < n; ++i ){
+    coef[i-1].d = (v[i] - v[i-1]) / (6*h[i-1]);
+    coef[i-1].c = v[i]/2;
+    coef[i-1].b = (f[i]-f[i-1])/h[i-1] + h[i-1]*(2*v[i] + v[i-1])/6;
+    coef[i-1].a = f[i];
+  }
+
+  sfree( a, "cubic_spline:a" );
+  sfree( b, "cubic_spline:b" );
+  sfree( c, "cubic_spline:c" );
+  sfree( d, "cubic_spline:d" );
+  sfree( v, "cubic_spline:v" );
+}
+
+
+void LR_Lookup( LR_lookup_table *t, real r, LR_data *y )
+{
+  int i;
+  real base, dif;
+
+  i = (int)(r * t->inv_dx);
+  if( i == 0 )  ++i;
+  base = (real)(i+1) * t->dx;
+  dif = r - base;
+
+  y->e_vdW = ((t->vdW[i].d*dif + t->vdW[i].c)*dif + t->vdW[i].b)*dif + 
+    t->vdW[i].a;
+  y->CEvd = ((t->CEvd[i].d*dif + t->CEvd[i].c)*dif + 
+	     t->CEvd[i].b)*dif + t->CEvd[i].a;
+
+  y->e_ele = ((t->ele[i].d*dif + t->ele[i].c)*dif + t->ele[i].b)*dif + 
+    t->ele[i].a;
+  y->CEclmb = ((t->CEclmb[i].d*dif + t->CEclmb[i].c)*dif + t->CEclmb[i].b)*dif +
+    t->CEclmb[i].a;
+
+  y->H = y->e_ele * EV_to_KCALpMOL / C_ele;
+}
+
+
+int Init_Lookup_Tables( reax_system *system, control_params *control, 
+			storage *workspace, mpi_datatypes *mpi_data, char *msg )
+{
+  int i, j, r;
+  int num_atom_types;
+  int existing_types[MAX_ATOM_TYPES], aggregated[MAX_ATOM_TYPES];
+  real dr;
+  real *h, *fh, *fvdw, *fele, *fCEvd, *fCEclmb;
+  real v0_vdw, v0_ele, vlast_vdw, vlast_ele;
+  MPI_Comm comm;
+
+  /* initializations */
+  v0_vdw = 0;
+  v0_ele = 0;
+  vlast_vdw = 0;
+  vlast_ele = 0;
+  comm = mpi_data->world;
+
+  num_atom_types = system->reax_param.num_atom_types;
+  dr = control->nonb_cut / control->tabulate;
+  h = (real*) 
+    smalloc( (control->tabulate+2) * sizeof(real), "lookup:h", comm );
+  fh = (real*) 
+    smalloc( (control->tabulate+2) * sizeof(real), "lookup:fh", comm );
+  fvdw = (real*) 
+    smalloc( (control->tabulate+2) * sizeof(real), "lookup:fvdw", comm );
+  fCEvd = (real*) 
+    smalloc( (control->tabulate+2) * sizeof(real), "lookup:fCEvd", comm );
+  fele = (real*) 
+    smalloc( (control->tabulate+2) * sizeof(real), "lookup:fele", comm );
+  fCEclmb = (real*) 
+    smalloc( (control->tabulate+2) * sizeof(real), "lookup:fCEclmb", comm );
+  
+  /* allocate Long-Range LookUp Table space based on 
+     number of atom types in the ffield file */
+  LR = (LR_lookup_table**) 
+    scalloc( num_atom_types, sizeof(LR_lookup_table*), "lookup:LR", comm );
+  for( i = 0; i < num_atom_types; ++i )
+    LR[i] = (LR_lookup_table*) 
+      scalloc( num_atom_types, sizeof(LR_lookup_table), "lookup:LR[i]", comm );
+
+  /* most atom types in ffield file will not exist in the current
+     simulation. to avoid unnecessary lookup table space, determine
+     the atom types that exist in the current simulation */
+  for( i = 0; i < MAX_ATOM_TYPES; ++i )
+    existing_types[i] = 0;
+  for( i = 0; i < system->n; ++i )
+    existing_types[ system->my_atoms[i].type ] = 1;
+
+  MPI_Allreduce( existing_types, aggregated, MAX_ATOM_TYPES, 
+		 MPI_INT, MPI_SUM, mpi_data->world );
+
+  /* fill in the lookup table entries for existing atom types.
+     only lower half should be enough. */
+  for( i = 0; i < num_atom_types; ++i )
+    if( aggregated[i] )
+      //for( j = 0; j < num_atom_types; ++j )
+      for( j = i; j < num_atom_types; ++j )
+	if( aggregated[j] ) {
+	  LR[i][j].xmin = 0;
+	  LR[i][j].xmax = control->nonb_cut;
+	  LR[i][j].n = control->tabulate + 2;
+	  LR[i][j].dx = dr;
+	  LR[i][j].inv_dx = control->tabulate / control->nonb_cut;
+	  LR[i][j].y = (LR_data*) 
+	    smalloc( LR[i][j].n * sizeof(LR_data), "lookup:LR[i,j].y", comm );
+	  LR[i][j].H = (cubic_spline_coef*) 
+	    smalloc( LR[i][j].n*sizeof(cubic_spline_coef),"lookup:LR[i,j].H" , 
+		     comm );
+	  LR[i][j].vdW = (cubic_spline_coef*) 
+	    smalloc( LR[i][j].n*sizeof(cubic_spline_coef),"lookup:LR[i,j].vdW",
+		     comm);
+	  LR[i][j].CEvd = (cubic_spline_coef*) 
+	    smalloc( LR[i][j].n*sizeof(cubic_spline_coef),"lookup:LR[i,j].CEvd",
+		     comm);
+	  LR[i][j].ele = (cubic_spline_coef*) 
+	    smalloc( LR[i][j].n*sizeof(cubic_spline_coef),"lookup:LR[i,j].ele", 
+		     comm );
+	  LR[i][j].CEclmb = (cubic_spline_coef*) 
+	    smalloc( LR[i][j].n*sizeof(cubic_spline_coef), 
+		     "lookup:LR[i,j].CEclmb", comm );
+	  
+	  for( r = 1; r <= control->tabulate; ++r ) {
+	    LR_vdW_Coulomb( system, workspace, i, j, r * dr, &(LR[i][j].y[r]) );
+	    h[r] = LR[i][j].dx;
+	    fh[r] = LR[i][j].y[r].H;
+	    fvdw[r] = LR[i][j].y[r].e_vdW;
+	    fCEvd[r] = LR[i][j].y[r].CEvd;
+	    fele[r] = LR[i][j].y[r].e_ele;
+	    fCEclmb[r] = LR[i][j].y[r].CEclmb;
+	  }
+
+	  // init the start-end points
+	  h[r] = LR[i][j].dx;
+	  v0_vdw = LR[i][j].y[1].CEvd;
+	  v0_ele = LR[i][j].y[1].CEclmb;
+	  fh[r] = fh[r-1];
+	  fvdw[r] = fvdw[r-1];
+	  fCEvd[r] = fCEvd[r-1];
+	  fele[r] = fele[r-1];
+	  fCEclmb[r] = fCEclmb[r-1];
+	  vlast_vdw = fCEvd[r-1];
+	  vlast_ele = fele[r-1];
+	  
+	  Natural_Cubic_Spline( &h[1], &fh[1], 
+				&(LR[i][j].H[1]), control->tabulate+1, comm );
+
+	  Complete_Cubic_Spline( &h[1], &fvdw[1], v0_vdw, vlast_vdw, 
+				 &(LR[i][j].vdW[1]), control->tabulate+1, 
+				 comm );
+
+	  Natural_Cubic_Spline( &h[1], &fCEvd[1], 
+				&(LR[i][j].CEvd[1]), control->tabulate+1, 
+				comm );
+
+	  Complete_Cubic_Spline( &h[1], &fele[1], v0_ele, vlast_ele, 
+				 &(LR[i][j].ele[1]), control->tabulate+1, 
+				 comm );
+
+	  Natural_Cubic_Spline( &h[1], &fCEclmb[1], 
+				&(LR[i][j].CEclmb[1]), control->tabulate+1, 
+				comm );
+	}
+	else{
+	  LR[i][j].n = 0;
+	}
+  
+  free(h);
+  free(fh);
+  free(fvdw);
+  free(fCEvd);
+  free(fele);
+  free(fCEclmb);
+
+  return 1;
+}
+
+
+void Deallocate_Lookup_Tables( reax_system *system )
+{
+  int i, j;
+  int ntypes;
+
+  ntypes = system->reax_param.num_atom_types;
+
+  for( i = 0; i < ntypes; ++i ) {
+    for( j = i; j < ntypes; ++j )
+      if( LR[i][j].n ) {
+	sfree( LR[i][j].y, "LR[i,j].y" );
+	sfree( LR[i][j].H, "LR[i,j].H" );
+	sfree( LR[i][j].vdW, "LR[i,j].vdW" );
+	sfree( LR[i][j].CEvd, "LR[i,j].CEvd" );
+	sfree( LR[i][j].ele, "LR[i,j].ele" );
+	sfree( LR[i][j].CEclmb, "LR[i,j].CEclmb" );
+      }
+    sfree( LR[i], "LR[i]" );
+  }
+  sfree( LR, "LR" );
+}
diff --git a/src/USER-REAXC/reaxc_lookup.h b/src/USER-REAXC/reaxc_lookup.h
new file mode 100644
index 0000000000..28658386b4
--- /dev/null
+++ b/src/USER-REAXC/reaxc_lookup.h
@@ -0,0 +1,32 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#ifndef __LOOKUP_H_
+#define __LOOKUP_H_
+
+#include "reaxc_types.h"
+
+int Init_Lookup_Tables( reax_system*, control_params*, storage*, 
+			mpi_datatypes*, char* );
+
+void Deallocate_Lookup_Tables( reax_system* );
+
+#endif
diff --git a/src/USER-REAXC/reaxc_multi_body.cpp b/src/USER-REAXC/reaxc_multi_body.cpp
new file mode 100644
index 0000000000..88b671e24a
--- /dev/null
+++ b/src/USER-REAXC/reaxc_multi_body.cpp
@@ -0,0 +1,311 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#include "reaxc_types.h"
+#if defined(PURE_REAX)
+#include "multi_body.h"
+#include "bond_orders.h"
+#include "list.h"
+#include "vector.h"
+#elif defined(LAMMPS_REAX)
+#include "reaxc_multi_body.h"
+#include "reaxc_bond_orders.h"
+#include "reaxc_list.h"
+#include "reaxc_vector.h"
+#endif
+
+
+void Atom_Energy( reax_system *system, control_params *control, 
+		  simulation_data *data, storage *workspace, reax_list **lists,
+		  output_controls *out_control )
+{
+  int i, j, pj, type_i, type_j;
+  real Delta_lpcorr, dfvl;
+  real e_lp, expvd2, inv_expvd2, dElp, CElp, DlpVi;
+  real e_lph, Di, vov3, deahu2dbo, deahu2dsbo;
+  real e_ov, CEover1, CEover2, CEover3, CEover4;
+  real exp_ovun1, exp_ovun2, sum_ovun1, sum_ovun2;
+  real exp_ovun2n, exp_ovun6, exp_ovun8;
+  real inv_exp_ovun1, inv_exp_ovun2, inv_exp_ovun2n, inv_exp_ovun8;
+  real e_un, CEunder1, CEunder2, CEunder3, CEunder4;
+  real p_lp1, p_lp2, p_lp3;
+  real p_ovun2, p_ovun3, p_ovun4, p_ovun5, p_ovun6, p_ovun7, p_ovun8;
+
+  single_body_parameters *sbp_i, *sbp_j;
+  two_body_parameters *twbp;
+  bond_data *pbond;
+  bond_order_data *bo_ij; 
+  reax_list *bonds = (*lists) + BONDS;
+
+  /* Initialize parameters */
+  p_lp1 = system->reax_param.gp.l[15];
+  p_lp3 = system->reax_param.gp.l[5];
+  p_ovun3 = system->reax_param.gp.l[32];
+  p_ovun4 = system->reax_param.gp.l[31];
+  p_ovun6 = system->reax_param.gp.l[6];
+  p_ovun7 = system->reax_param.gp.l[8];
+  p_ovun8 = system->reax_param.gp.l[9];
+
+  for( i = 0; i < system->n; ++i ) {
+    /* set the parameter pointer */
+    type_i = system->my_atoms[i].type;
+    sbp_i = &(system->reax_param.sbp[ type_i ]);
+
+    /* lone-pair Energy */
+    p_lp2 = sbp_i->p_lp2;      
+    expvd2 = exp( -75 * workspace->Delta_lp[i] );
+    inv_expvd2 = 1. / (1. + expvd2 );
+      
+    /* calculate the energy */
+    data->my_en.e_lp += e_lp = 
+      p_lp2 * workspace->Delta_lp[i] * inv_expvd2;
+	
+    dElp = p_lp2 * inv_expvd2 + 
+      75 * p_lp2 * workspace->Delta_lp[i] * expvd2 * SQR(inv_expvd2);
+    CElp = dElp * workspace->dDelta_lp[i];
+
+    workspace->CdDelta[i] += CElp;  // lp - 1st term  
+
+#ifdef TEST_ENERGY
+//  fprintf( out_control->elp, "%24.15e%24.15e%24.15e%24.15e\n",
+//	     p_lp2, workspace->Delta_lp_temp[i], expvd2, dElp );
+//  fprintf( out_control->elp, "%6d%24.15e%24.15e%24.15e\n",
+    fprintf( out_control->elp, "%6d%12.4f%12.4f%12.4f\n",
+	     system->my_atoms[i].orig_id, workspace->nlp[i], 
+	     e_lp, data->my_en.e_lp );
+#endif
+#ifdef TEST_FORCES
+    Add_dDelta( system, lists, i, CElp, workspace->f_lp );  // lp - 1st term
+#endif
+
+    /* correction for C2 */
+    if( system->reax_param.gp.l[5] > 0.001 &&
+	!strcmp( system->reax_param.sbp[type_i].name, "C" ) )
+      for( pj = Start_Index(i, bonds); pj < End_Index(i, bonds); ++pj )
+	if( system->my_atoms[i].orig_id < 
+	    system->my_atoms[bonds->select.bond_list[pj].nbr].orig_id ) {
+	  j = bonds->select.bond_list[pj].nbr;
+	  type_j = system->my_atoms[j].type;
+
+	  if( !strcmp( system->reax_param.sbp[type_j].name, "C" ) ) {
+	    twbp = &( system->reax_param.tbp[type_i][type_j]);
+	    bo_ij = &( bonds->select.bond_list[pj].bo_data );
+	    Di = workspace->Delta[i];
+	    vov3 = bo_ij->BO - Di - 0.040*pow(Di, 4.);
+
+	    if( vov3 > 3. ) {
+	      data->my_en.e_lp += e_lph = p_lp3 * SQR(vov3-3.0);
+		
+	      deahu2dbo = 2.*p_lp3*(vov3 - 3.);
+	      deahu2dsbo = 2.*p_lp3*(vov3 - 3.)*(-1. - 0.16*pow(Di, 3.));
+		
+	      bo_ij->Cdbo += deahu2dbo;
+	      workspace->CdDelta[i] += deahu2dsbo;
+#ifdef TEST_ENERGY
+	      fprintf(out_control->elp,"C2cor%6d%6d%12.6f%12.6f%12.6f\n",
+	            system->my_atoms[i].orig_id, system->my_atoms[j].orig_id,
+	            e_lph, deahu2dbo, deahu2dsbo );
+#endif
+#ifdef TEST_FORCES
+	      Add_dBO(system, lists, i, pj, deahu2dbo, workspace->f_lp);
+	      Add_dDelta(system, lists, i, deahu2dsbo, workspace->f_lp);
+#endif
+	    }
+	  }    
+	}
+  }
+
+
+  for( i = 0; i < system->n; ++i ) {
+    type_i = system->my_atoms[i].type;
+    sbp_i = &(system->reax_param.sbp[ type_i ]);
+
+    /* over-coordination energy */
+    if( sbp_i->mass > 21.0 ) 
+      dfvl = 0.0;
+    else dfvl = 1.0; // only for 1st-row elements
+      
+    p_ovun2 = sbp_i->p_ovun2;
+    sum_ovun1 = sum_ovun2 = 0;
+    for( pj = Start_Index(i, bonds); pj < End_Index(i, bonds); ++pj ) {
+	j = bonds->select.bond_list[pj].nbr;
+	type_j = system->my_atoms[j].type;
+	bo_ij = &(bonds->select.bond_list[pj].bo_data);
+	sbp_j = &(system->reax_param.sbp[ type_j ]);
+	twbp = &(system->reax_param.tbp[ type_i ][ type_j ]);
+
+	sum_ovun1 += twbp->p_ovun1 * twbp->De_s * bo_ij->BO;
+	sum_ovun2 += (workspace->Delta[j] - dfvl*workspace->Delta_lp_temp[j])*
+	  ( bo_ij->BO_pi + bo_ij->BO_pi2 );
+
+	/*fprintf( stdout, "%4d%4d%12.6f%12.6f%12.6f\n",
+            i+1, j+1,      
+            dfvl * workspace->Delta_lp_temp[j], 
+	    sbp_j->nlp_opt,
+            workspace->nlp_temp[j] );*/
+      }
+
+    exp_ovun1 = p_ovun3 * exp( p_ovun4 * sum_ovun2 );
+    inv_exp_ovun1 = 1.0 / (1 + exp_ovun1);
+    Delta_lpcorr  = workspace->Delta[i] - 
+      (dfvl * workspace->Delta_lp_temp[i]) * inv_exp_ovun1;
+	
+    exp_ovun2 = exp( p_ovun2 * Delta_lpcorr );
+    inv_exp_ovun2 = 1.0 / (1.0 + exp_ovun2);
+	
+    DlpVi = 1.0 / (Delta_lpcorr + sbp_i->valency + 1e-8);
+    CEover1 = Delta_lpcorr * DlpVi * inv_exp_ovun2;
+			
+    data->my_en.e_ov += e_ov = sum_ovun1 * CEover1;
+
+    CEover2 = sum_ovun1 * DlpVi * inv_exp_ovun2 *
+      (1.0 - Delta_lpcorr * ( DlpVi + p_ovun2 * exp_ovun2 * inv_exp_ovun2 ));
+
+    CEover3 = CEover2 * (1.0 - dfvl * workspace->dDelta_lp[i] * inv_exp_ovun1 );
+
+    CEover4 = CEover2 * (dfvl * workspace->Delta_lp_temp[i]) * 
+      p_ovun4 * exp_ovun1 * SQR(inv_exp_ovun1);
+
+      
+    /* under-coordination potential */
+    p_ovun2 = sbp_i->p_ovun2;
+    p_ovun5 = sbp_i->p_ovun5;
+	
+    exp_ovun2n = 1.0 / exp_ovun2;
+    exp_ovun6 = exp( p_ovun6 * Delta_lpcorr );
+    exp_ovun8 = p_ovun7 * exp(p_ovun8 * sum_ovun2);
+    inv_exp_ovun2n = 1.0 / (1.0 + exp_ovun2n);
+    inv_exp_ovun8 = 1.0 / (1.0 + exp_ovun8);
+
+    data->my_en.e_un += e_un =
+      -p_ovun5 * (1.0 - exp_ovun6) * inv_exp_ovun2n * inv_exp_ovun8;
+			
+    CEunder1 = inv_exp_ovun2n * 
+      ( p_ovun5 * p_ovun6 * exp_ovun6 * inv_exp_ovun8 +
+	p_ovun2 * e_un * exp_ovun2n );
+    CEunder2 = -e_un * p_ovun8 * exp_ovun8 * inv_exp_ovun8;
+    CEunder3 = CEunder1 * (1.0 - dfvl*workspace->dDelta_lp[i]*inv_exp_ovun1);
+    CEunder4 = CEunder1 * (dfvl*workspace->Delta_lp_temp[i]) * 
+      p_ovun4 * exp_ovun1 * SQR(inv_exp_ovun1) + CEunder2;
+
+
+    /* forces */
+    workspace->CdDelta[i] += CEover3;   // OvCoor - 2nd term
+    workspace->CdDelta[i] += CEunder3;  // UnCoor - 1st term
+
+#ifdef TEST_FORCES
+    Add_dDelta( system, lists, i, CEover3, workspace->f_ov ); // OvCoor 2nd
+    Add_dDelta( system, lists, i, CEunder3, workspace->f_un ); // UnCoor 1st
+#endif
+      
+    for( pj = Start_Index(i, bonds); pj < End_Index(i, bonds); ++pj ) {
+      pbond = &(bonds->select.bond_list[pj]);
+      j = pbond->nbr;
+      bo_ij = &(pbond->bo_data);
+      twbp  = &(system->reax_param.tbp[ system->my_atoms[i].type ]
+		[system->my_atoms[pbond->nbr].type]);
+
+
+      bo_ij->Cdbo += CEover1 * twbp->p_ovun1 * twbp->De_s;// OvCoor-1st 
+      workspace->CdDelta[j] += CEover4 * (1.0 - dfvl*workspace->dDelta_lp[j]) * 
+	(bo_ij->BO_pi + bo_ij->BO_pi2); // OvCoor-3a
+      bo_ij->Cdbopi += CEover4 * 
+	(workspace->Delta[j] - dfvl*workspace->Delta_lp_temp[j]); // OvCoor-3b
+      bo_ij->Cdbopi2 += CEover4 * 
+	(workspace->Delta[j] - dfvl*workspace->Delta_lp_temp[j]);  // OvCoor-3b
+
+
+      workspace->CdDelta[j] += CEunder4 * (1.0 - dfvl*workspace->dDelta_lp[j]) *
+	(bo_ij->BO_pi + bo_ij->BO_pi2);   // UnCoor - 2a
+      bo_ij->Cdbopi += CEunder4 * 
+	(workspace->Delta[j] - dfvl*workspace->Delta_lp_temp[j]);  // UnCoor-2b
+      bo_ij->Cdbopi2 += CEunder4 * 
+	(workspace->Delta[j] - dfvl*workspace->Delta_lp_temp[j]);  // UnCoor-2b
+
+
+#ifdef TEST_ENERGY
+/*	  fprintf( out_control->eov, "%6d%12.6f\n", 
+		   workspace->reverse_map[j], 
+		   // CEover1 * twbp->p_ovun1 * twbp->De_s, CEover3, 
+		   CEover4 * (1.0 - workspace->dDelta_lp[j]) * 
+		   (bo_ij->BO_pi + bo_ij->BO_pi2)
+*///		   /*CEover4 * (workspace->Delta[j]-workspace->Delta_lp[j])*/);
+//	  fprintf( out_control->eov, "%6d%12.6f\n", 
+//	  fprintf( out_control->eov, "%6d%24.15e\n", 
+//		   system->my_atoms[j].orig_id, 
+		   // CEover1 * twbp->p_ovun1 * twbp->De_s, CEover3, 
+//		   CEover4 * (1.0 - workspace->dDelta_lp[j]) * 
+//		   (bo_ij->BO_pi + bo_ij->BO_pi2)
+//		   /*CEover4 * (workspace->Delta[j]-workspace->Delta_lp[j])*/);
+
+	  // CEunder4 * (1.0 - workspace->dDelta_lp[j]) * 
+	  // (bo_ij->BO_pi + bo_ij->BO_pi2),
+	  // CEunder4 * (workspace->Delta[j] - workspace->Delta_lp[j]) );
+#endif
+
+#ifdef TEST_FORCES
+      Add_dBO( system, lists, i, pj, CEover1 * twbp->p_ovun1 * twbp->De_s,
+	       workspace->f_ov ); // OvCoor - 1st term
+
+      Add_dDelta( system, lists, j,
+		  CEover4 * (1.0 - dfvl*workspace->dDelta_lp[j]) * 
+		  (bo_ij->BO_pi + bo_ij->BO_pi2),
+		  workspace->f_ov );   // OvCoor - 3a
+
+      Add_dBOpinpi2( system, lists, i, pj, 
+		     CEover4 * (workspace->Delta[j] - 
+				dfvl * workspace->Delta_lp_temp[j]),
+		     CEover4 * (workspace->Delta[j] - 
+				dfvl * workspace->Delta_lp_temp[j]),
+		     workspace->f_ov, workspace->f_ov ); // OvCoor - 3b
+
+      Add_dDelta( system, lists, j,
+		  CEunder4 * (1.0 - dfvl*workspace->dDelta_lp[j]) * 
+		  (bo_ij->BO_pi + bo_ij->BO_pi2),
+		  workspace->f_un ); // UnCoor - 2a
+
+      Add_dBOpinpi2( system, lists, i, pj, 
+		     CEunder4 * (workspace->Delta[j] - 
+				 dfvl * workspace->Delta_lp_temp[j]),
+		     CEunder4 * (workspace->Delta[j] - 
+				 dfvl * workspace->Delta_lp_temp[j]),
+		     workspace->f_un, workspace->f_un ); // UnCoor - 2b
+#endif
+    }
+
+#ifdef TEST_ENERGY
+    //fprintf( out_control->elp, "%6d%24.15e%24.15e%24.15e\n",
+    //fprintf( out_control->elp, "%6d%12.4f%12.4f%12.4f\n",
+    //     system->my_atoms[i].orig_id, workspace->nlp[i], 
+    //     e_lp, data->my_en.e_lp );
+    
+    //fprintf( out_control->eov, "%6d%24.15e%24.15e\n", 
+    fprintf( out_control->eov, "%6d%12.4f%12.4f\n", 
+	     system->my_atoms[i].orig_id, 
+	     e_ov, data->my_en.e_ov + data->my_en.e_un );
+    
+    //fprintf( out_control->eun, "%6d%24.15e%24.15e\n", 
+    fprintf( out_control->eun, "%6d%12.4f%12.4f\n", 
+	     system->my_atoms[i].orig_id, 
+	     e_un, data->my_en.e_ov + data->my_en.e_un );
+#endif
+  }
+}
diff --git a/src/USER-REAXC/reaxc_multi_body.h b/src/USER-REAXC/reaxc_multi_body.h
new file mode 100644
index 0000000000..dcd11fc7e7
--- /dev/null
+++ b/src/USER-REAXC/reaxc_multi_body.h
@@ -0,0 +1,31 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#ifndef __MULTI_BODY_H_
+#define __MULTI_BODY_H_
+
+#include "reaxc_types.h"
+
+void Atom_Energy( reax_system*, control_params*, simulation_data*,
+		  storage*, reax_list**, output_controls* );
+
+#endif
+
diff --git a/src/USER-REAXC/reaxc_nonbonded.cpp b/src/USER-REAXC/reaxc_nonbonded.cpp
new file mode 100644
index 0000000000..419779a68f
--- /dev/null
+++ b/src/USER-REAXC/reaxc_nonbonded.cpp
@@ -0,0 +1,424 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#include "reaxc_types.h"
+#if defined(PURE_REAX)
+#include "nonbonded.h"
+#include "bond_orders.h"
+#include "list.h"
+#include "vector.h"
+#elif defined(LAMMPS_REAX)
+#include "reaxc_nonbonded.h"
+#include "reaxc_bond_orders.h"
+#include "reaxc_list.h"
+#include "reaxc_vector.h"
+#endif
+
+
+void vdW_Coulomb_Energy( reax_system *system, control_params *control, 
+			 simulation_data *data, storage *workspace, 
+			 reax_list **lists, output_controls *out_control )
+{
+  int i, j, pj, natoms;
+  int start_i, end_i, orig_i, orig_j;
+  real p_vdW1, p_vdW1i;
+  real powr_vdW1, powgi_vdW1;
+  real tmp, r_ij, fn13, exp1, exp2;
+  real Tap, dTap, dfn13, CEvd, CEclmb, de_core;
+  real dr3gamij_1, dr3gamij_3;
+  real e_ele, e_vdW, e_core;
+  rvec temp, ext_press;
+  two_body_parameters *twbp;
+  far_neighbor_data *nbr_pj;
+  reax_list *far_nbrs;
+  // rtensor temp_rtensor, total_rtensor;
+
+  natoms = system->n;
+  far_nbrs = (*lists) + FAR_NBRS;
+  p_vdW1 = system->reax_param.gp.l[28];
+  p_vdW1i = 1.0 / p_vdW1;
+  e_core = 0;
+  e_vdW = 0;
+
+  for( i = 0; i < natoms; ++i ) {
+    start_i = Start_Index(i, far_nbrs);
+    end_i   = End_Index(i, far_nbrs);
+    orig_i  = system->my_atoms[i].orig_id;
+    //fprintf( stderr, "i:%d, start_i: %d, end_i: %d\n", i, start_i, end_i );
+
+    for( pj = start_i; pj < end_i; ++pj ) {
+      nbr_pj = &(far_nbrs->select.far_nbr_list[pj]);
+      j = nbr_pj->nbr;
+      orig_j  = system->my_atoms[j].orig_id;
+
+      if( nbr_pj->d <= control->nonb_cut && (j < natoms || orig_i < orig_j) ) {
+	r_ij = nbr_pj->d;
+	twbp = &(system->reax_param.tbp[ system->my_atoms[i].type ]
+		                       [ system->my_atoms[j].type ]);
+
+      /* Calculate Taper and its derivative */
+      // Tap = nbr_pj->Tap;   -- precomputed during compte_H
+      Tap = workspace->Tap[7] * r_ij + workspace->Tap[6];
+      Tap = Tap * r_ij + workspace->Tap[5];
+      Tap = Tap * r_ij + workspace->Tap[4];
+      Tap = Tap * r_ij + workspace->Tap[3];
+      Tap = Tap * r_ij + workspace->Tap[2];
+      Tap = Tap * r_ij + workspace->Tap[1];
+      Tap = Tap * r_ij + workspace->Tap[0];
+	  
+      dTap = 7*workspace->Tap[7] * r_ij + 6*workspace->Tap[6];
+      dTap = dTap * r_ij + 5*workspace->Tap[5];
+      dTap = dTap * r_ij + 4*workspace->Tap[4];
+      dTap = dTap * r_ij + 3*workspace->Tap[3];
+      dTap = dTap * r_ij + 2*workspace->Tap[2];
+      dTap += workspace->Tap[1]/r_ij;
+
+      /*vdWaals Calculations*/
+      if(system->reax_param.gp.vdw_type==1 || system->reax_param.gp.vdw_type==3)
+	{ // shielding
+	  powr_vdW1 = pow(r_ij, p_vdW1);
+	  powgi_vdW1 = pow( 1.0 / twbp->gamma_w, p_vdW1);
+	
+	  fn13 = pow( powr_vdW1 + powgi_vdW1, p_vdW1i );
+	  exp1 = exp( twbp->alpha * (1.0 - fn13 / twbp->r_vdW) );
+	  exp2 = exp( 0.5 * twbp->alpha * (1.0 - fn13 / twbp->r_vdW) );
+
+	  e_vdW = twbp->D * (exp1 - 2.0 * exp2);	  
+	  data->my_en.e_vdW += Tap * e_vdW;
+	
+	  dfn13 = pow( powr_vdW1 + powgi_vdW1, p_vdW1i - 1.0) * 
+	    pow(r_ij, p_vdW1 - 2.0);
+	  
+	  CEvd = dTap * e_vdW - 
+	    Tap * twbp->D * (twbp->alpha / twbp->r_vdW) * (exp1 - exp2) * dfn13;
+	}
+      else{ // no shielding
+	exp1 = exp( twbp->alpha * (1.0 - r_ij / twbp->r_vdW) );
+	exp2 = exp( 0.5 * twbp->alpha * (1.0 - r_ij / twbp->r_vdW) );
+	
+	e_vdW = twbp->D * (exp1 - 2.0 * exp2);
+	data->my_en.e_vdW += Tap * e_vdW;
+	
+	CEvd = dTap * e_vdW - 
+	  Tap * twbp->D * (twbp->alpha / twbp->r_vdW) * (exp1 - exp2);
+      }
+
+      if(system->reax_param.gp.vdw_type==2 || system->reax_param.gp.vdw_type==3)
+	{ // innner wall
+	  e_core = twbp->ecore * exp(twbp->acore * (1.0-(r_ij/twbp->rcore)));
+	  data->my_en.e_vdW += Tap * e_core;
+
+	  de_core = -(twbp->acore/twbp->rcore) * e_core;
+	  CEvd += dTap * e_core + Tap * de_core;
+	}
+
+      /*Coulomb Calculations*/
+      dr3gamij_1 = ( r_ij * r_ij * r_ij + twbp->gamma );
+      dr3gamij_3 = pow( dr3gamij_1 , 0.33333333333333 );
+
+      tmp = Tap / dr3gamij_3;
+      data->my_en.e_ele += e_ele = 
+	C_ele * system->my_atoms[i].q * system->my_atoms[j].q * tmp;
+		
+	  
+      CEclmb = C_ele * system->my_atoms[i].q * system->my_atoms[j].q * 
+	( dTap -  Tap * r_ij / dr3gamij_1 ) / dr3gamij_3;
+      // fprintf( fout, "%5d %5d %10.6f %10.6f\n",
+      //   MIN( system->my_atoms[i].orig_id, system->my_atoms[j].orig_id ),
+      //   MAX( system->my_atoms[i].orig_id, system->my_atoms[j].orig_id ), 
+      //   CEvd, CEclmb );       	  		  
+
+      if( control->virial == 0 ) {
+	rvec_ScaledAdd( workspace->f[i], -(CEvd + CEclmb), nbr_pj->dvec );
+	rvec_ScaledAdd( workspace->f[j], +(CEvd + CEclmb), nbr_pj->dvec );
+      }
+      else { /* NPT, iNPT or sNPT */
+	/* for pressure coupling, terms not related to bond order 
+	   derivatives are added directly into pressure vector/tensor */
+	rvec_Scale( temp, CEvd + CEclmb, nbr_pj->dvec );
+	    
+	rvec_ScaledAdd( workspace->f[i], -1., temp );
+	rvec_Add( workspace->f[j], temp );
+	    
+	rvec_iMultiply( ext_press, nbr_pj->rel_box, temp );
+	rvec_Add( data->my_ext_press, ext_press );
+	    
+	// fprintf( stderr, "nonbonded(%d,%d): rel_box (%f %f %f)
+	//   force(%f %f %f) ext_press (%12.6f %12.6f %12.6f)\n", 
+	//   i, j, nbr_pj->rel_box[0], nbr_pj->rel_box[1], nbr_pj->rel_box[2],
+	//   temp[0], temp[1], temp[2],
+	//   data->ext_press[0], data->ext_press[1], data->ext_press[2] );
+      }
+
+#ifdef TEST_ENERGY
+      // fprintf( out_control->evdw, 
+      // "%12.9f%12.9f%12.9f%12.9f%12.9f%12.9f%12.9f%12.9f\n", 
+      // workspace->Tap[7],workspace->Tap[6],workspace->Tap[5],
+      // workspace->Tap[4],workspace->Tap[3],workspace->Tap[2], 
+      // workspace->Tap[1], Tap );
+      //fprintf( out_control->evdw, "%6d%6d%24.15e%24.15e%24.15e\n",
+      fprintf( out_control->evdw, "%6d%6d%12.4f%12.4f%12.4f\n",
+	       system->my_atoms[i].orig_id, system->my_atoms[j].orig_id, 
+	       r_ij, e_vdW, data->my_en.e_vdW );
+      //fprintf(out_control->ecou,"%6d%6d%24.15e%24.15e%24.15e%24.15e%24.15e\n",
+      fprintf( out_control->ecou, "%6d%6d%12.4f%12.4f%12.4f%12.4f%12.4f\n",
+	       system->my_atoms[i].orig_id, system->my_atoms[j].orig_id,
+	       r_ij, system->my_atoms[i].q, system->my_atoms[j].q, 
+	       e_ele, data->my_en.e_ele );
+#endif
+#ifdef TEST_FORCES
+      rvec_ScaledAdd( workspace->f_vdw[i], -CEvd, nbr_pj->dvec );
+      rvec_ScaledAdd( workspace->f_vdw[j], +CEvd, nbr_pj->dvec );
+      rvec_ScaledAdd( workspace->f_ele[i], -CEclmb, nbr_pj->dvec );
+      rvec_ScaledAdd( workspace->f_ele[j], +CEclmb, nbr_pj->dvec );
+#endif
+      }
+    }
+  }
+
+#if defined(DEBUG)
+  fprintf( stderr, "nonbonded: ext_press (%12.6f %12.6f %12.6f)\n", 
+	   data->ext_press[0], data->ext_press[1], data->ext_press[2] );
+  MPI_Barrier( MPI_COMM_WORLD );
+#endif
+
+  Compute_Polarization_Energy( system, data );
+}
+
+
+
+void Tabulated_vdW_Coulomb_Energy( reax_system *system,control_params *control, 
+				   simulation_data *data, storage *workspace, 
+				   reax_list **lists, 
+				   output_controls *out_control )
+{
+  int i, j, pj, r, natoms, steps, update_freq, update_energies;
+  int type_i, type_j, tmin, tmax;
+  int start_i, end_i, orig_i, orig_j;
+  real r_ij, base, dif;
+  real e_vdW, e_ele;
+  real CEvd, CEclmb;
+  rvec temp, ext_press;
+  far_neighbor_data *nbr_pj;
+  reax_list *far_nbrs;
+  LR_lookup_table *t;
+
+  natoms = system->n;
+  far_nbrs = (*lists) + FAR_NBRS;
+  steps = data->step - data->prev_steps;
+  update_freq = out_control->energy_update_freq;
+  update_energies = update_freq > 0 && steps % update_freq == 0;
+  e_ele = e_vdW = 0;
+
+  for( i = 0; i < natoms; ++i ) {
+    type_i  = system->my_atoms[i].type;
+    start_i = Start_Index(i,far_nbrs);
+    end_i   = End_Index(i,far_nbrs);
+    orig_i  = system->my_atoms[i].orig_id;
+
+    for( pj = start_i; pj < end_i; ++pj ) {
+      nbr_pj = &(far_nbrs->select.far_nbr_list[pj]);
+      j = nbr_pj->nbr;
+      orig_j  = system->my_atoms[j].orig_id;
+
+      if( nbr_pj->d <= control->nonb_cut && (j < natoms || orig_i < orig_j) ) {
+      j = nbr_pj->nbr;
+      type_j = system->my_atoms[j].type;
+      r_ij   = nbr_pj->d;
+      tmin  = MIN( type_i, type_j );
+      tmax  = MAX( type_i, type_j );
+      t = &( LR[tmin][tmax] ); 
+      //t = &( LR[type_i][type_j] ); 
+
+      /* Cubic Spline Interpolation */
+      r = (int)(r_ij * t->inv_dx);
+      if( r == 0 )  ++r;
+      base = (real)(r+1) * t->dx;
+      dif = r_ij - base;
+      //fprintf(stderr, "r: %f, i: %d, base: %f, dif: %f\n", r, i, base, dif);
+      
+      if( update_energies ) {
+	e_vdW = ((t->vdW[r].d*dif + t->vdW[r].c)*dif + t->vdW[r].b)*dif + 
+	  t->vdW[r].a;
+	
+	e_ele = ((t->ele[r].d*dif + t->ele[r].c)*dif + t->ele[r].b)*dif + 
+	  t->ele[r].a;
+	e_ele *= system->my_atoms[i].q * system->my_atoms[j].q;
+	
+	data->my_en.e_vdW += e_vdW;
+	data->my_en.e_ele += e_ele;
+      }	
+      
+      CEvd = ((t->CEvd[r].d*dif + t->CEvd[r].c)*dif + t->CEvd[r].b)*dif + 
+	t->CEvd[r].a;
+            
+      CEclmb = ((t->CEclmb[r].d*dif+t->CEclmb[r].c)*dif+t->CEclmb[r].b)*dif + 
+	t->CEclmb[r].a;
+      CEclmb *= system->my_atoms[i].q * system->my_atoms[j].q;
+      
+      if( control->virial == 0 ) {
+	rvec_ScaledAdd( workspace->f[i], -(CEvd + CEclmb), nbr_pj->dvec );
+	rvec_ScaledAdd( workspace->f[j], +(CEvd + CEclmb), nbr_pj->dvec );
+      }
+      else { // NPT, iNPT or sNPT
+	/* for pressure coupling, terms not related to bond order derivatives
+	   are added directly into pressure vector/tensor */
+	rvec_Scale( temp, CEvd + CEclmb, nbr_pj->dvec );
+	      
+	rvec_ScaledAdd( workspace->f[i], -1., temp );
+	rvec_Add( workspace->f[j], temp );
+	      
+	rvec_iMultiply( ext_press, nbr_pj->rel_box, temp );
+	rvec_Add( data->my_ext_press, ext_press );
+      }
+
+#ifdef TEST_ENERGY
+      //fprintf( out_control->evdw, "%6d%6d%24.15e%24.15e%24.15e\n",
+      fprintf( out_control->evdw, "%6d%6d%12.4f%12.4f%12.4f\n",
+	       system->my_atoms[i].orig_id, system->my_atoms[j].orig_id, 
+	       r_ij, e_vdW, data->my_en.e_vdW );
+      //fprintf(out_control->ecou,"%6d%6d%24.15e%24.15e%24.15e%24.15e%24.15e\n",
+      fprintf( out_control->ecou, "%6d%6d%12.4f%12.4f%12.4f%12.4f%12.4f\n",
+	       system->my_atoms[i].orig_id, system->my_atoms[j].orig_id,
+	       r_ij, system->my_atoms[i].q, system->my_atoms[j].q, 
+	       e_ele, data->my_en.e_ele );
+#endif
+#ifdef TEST_FORCES
+      rvec_ScaledAdd( workspace->f_vdw[i], -CEvd, nbr_pj->dvec );
+      rvec_ScaledAdd( workspace->f_vdw[j], +CEvd, nbr_pj->dvec );
+      rvec_ScaledAdd( workspace->f_ele[i], -CEclmb, nbr_pj->dvec );
+      rvec_ScaledAdd( workspace->f_ele[j], +CEclmb, nbr_pj->dvec );
+#endif
+      }
+    }
+  }
+
+  Compute_Polarization_Energy( system, data );
+}
+
+
+
+void Compute_Polarization_Energy( reax_system *system, simulation_data *data )
+{
+  int  i, type_i;
+  real q;
+
+  data->my_en.e_pol = 0.0;
+  for( i = 0; i < system->n; i++ ) {
+    q = system->my_atoms[i].q;
+    type_i = system->my_atoms[i].type;
+      
+    data->my_en.e_pol += 
+      KCALpMOL_to_EV * (system->reax_param.sbp[type_i].chi * q + 
+			(system->reax_param.sbp[type_i].eta / 2.) * SQR(q));
+  }
+}
+
+
+void LR_vdW_Coulomb( reax_system *system, storage *workspace, 
+		     int i, int j, real r_ij, LR_data *lr )
+{
+  real p_vdW1 = system->reax_param.gp.l[28];
+  real p_vdW1i = 1.0 / p_vdW1;
+  real powr_vdW1, powgi_vdW1;
+  real tmp, fn13, exp1, exp2;
+  real Tap, dTap, dfn13;
+  real dr3gamij_1, dr3gamij_3;
+  real e_core, de_core;
+  two_body_parameters *twbp;
+
+  twbp = &(system->reax_param.tbp[i][j]);
+  e_core = 0;
+  de_core = 0;
+
+  /* calculate taper and its derivative */
+  Tap = workspace->Tap[7] * r_ij + workspace->Tap[6];
+  Tap = Tap * r_ij + workspace->Tap[5];
+  Tap = Tap * r_ij + workspace->Tap[4];
+  Tap = Tap * r_ij + workspace->Tap[3];
+  Tap = Tap * r_ij + workspace->Tap[2];
+  Tap = Tap * r_ij + workspace->Tap[1];
+  Tap = Tap * r_ij + workspace->Tap[0];
+	  
+  dTap = 7*workspace->Tap[7] * r_ij + 6*workspace->Tap[6];
+  dTap = dTap * r_ij + 5*workspace->Tap[5];
+  dTap = dTap * r_ij + 4*workspace->Tap[4];
+  dTap = dTap * r_ij + 3*workspace->Tap[3];
+  dTap = dTap * r_ij + 2*workspace->Tap[2];
+  dTap += workspace->Tap[1]/r_ij;
+
+  /*vdWaals Calculations*/
+  if(system->reax_param.gp.vdw_type==1 || system->reax_param.gp.vdw_type==3)
+    { // shielding
+      powr_vdW1 = pow(r_ij, p_vdW1);
+      powgi_vdW1 = pow( 1.0 / twbp->gamma_w, p_vdW1);
+	
+      fn13 = pow( powr_vdW1 + powgi_vdW1, p_vdW1i );
+      exp1 = exp( twbp->alpha * (1.0 - fn13 / twbp->r_vdW) );
+      exp2 = exp( 0.5 * twbp->alpha * (1.0 - fn13 / twbp->r_vdW) );
+
+      lr->e_vdW = Tap * twbp->D * (exp1 - 2.0 * exp2);
+	
+      dfn13 = pow( powr_vdW1 + powgi_vdW1, p_vdW1i-1.0) * pow(r_ij, p_vdW1-2.0);
+	  
+      lr->CEvd = dTap * twbp->D * (exp1 - 2.0 * exp2) - 
+	Tap * twbp->D * (twbp->alpha / twbp->r_vdW) * (exp1 - exp2) * dfn13;
+    }
+  else{ // no shielding
+    exp1 = exp( twbp->alpha * (1.0 - r_ij / twbp->r_vdW) );
+    exp2 = exp( 0.5 * twbp->alpha * (1.0 - r_ij / twbp->r_vdW) );
+	
+    lr->e_vdW = Tap * twbp->D * (exp1 - 2.0 * exp2);
+    lr->CEvd = dTap * twbp->D * (exp1 - 2.0 * exp2) -
+      Tap * twbp->D * (twbp->alpha / twbp->r_vdW) * (exp1 - exp2);
+  }
+
+  if(system->reax_param.gp.vdw_type==2 || system->reax_param.gp.vdw_type==3)
+    { // innner wall
+      e_core = twbp->ecore * exp(twbp->acore * (1.0-(r_ij/twbp->rcore)));
+      lr->e_vdW += Tap * e_core;
+      
+      de_core = -(twbp->acore/twbp->rcore) * e_core;
+      lr->CEvd += dTap * e_core + Tap * de_core;
+    }
+
+  
+  /* Coulomb calculations */
+  dr3gamij_1 = ( r_ij * r_ij * r_ij + twbp->gamma );
+  dr3gamij_3 = pow( dr3gamij_1 , 0.33333333333333 );
+
+  tmp = Tap / dr3gamij_3;
+  lr->H = EV_to_KCALpMOL * tmp;
+  lr->e_ele = C_ele * tmp;
+  // fprintf( stderr,
+  //    "i:%d(%d), j:%d(%d), gamma:%f, Tap:%f, dr3gamij_3:%f, qi: %f, qj: %f\n",
+  //    i, system->my_atoms[i].type, j, system->my_atoms[j].type, 
+  //    twbp->gamma, Tap, dr3gamij_3, 
+  //    system->my_atoms[i].q, system->my_atoms[j].q );
+		
+  lr->CEclmb = C_ele * ( dTap -  Tap * r_ij / dr3gamij_1 ) / dr3gamij_3;
+  // fprintf( stdout, "%d %d\t%g\t%g  %g\t%g  %g\t%g  %g\n",
+  //    i+1, j+1, r_ij, e_vdW, CEvd * r_ij,
+  //    system->my_atoms[i].q, system->my_atoms[j].q, e_ele, CEclmb * r_ij );
+
+  // fprintf(stderr,"LR_Lookup: %3d %3d %5.3f-%8.5f %8.5f %8.5f %8.5f %8.5f\n",
+  //   i, j, r_ij, lr->H, lr->e_vdW, lr->CEvd, lr->e_ele, lr->CEclmb ); */
+}
diff --git a/src/USER-REAXC/reaxc_nonbonded.h b/src/USER-REAXC/reaxc_nonbonded.h
new file mode 100644
index 0000000000..7e418d43e1
--- /dev/null
+++ b/src/USER-REAXC/reaxc_nonbonded.h
@@ -0,0 +1,37 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#ifndef __NONBONDED_H_
+#define __NONBONDED_H_
+
+#include "reaxc_types.h"
+
+void vdW_Coulomb_Energy( reax_system*, control_params*, simulation_data*,
+			 storage*, reax_list**, output_controls* );
+
+void Tabulated_vdW_Coulomb_Energy( reax_system*, control_params*, 
+				   simulation_data*, storage*, 
+				   reax_list**, output_controls* );
+
+void Compute_Polarization_Energy( reax_system*, simulation_data* );
+
+void LR_vdW_Coulomb( reax_system*, storage*, int, int, real, LR_data* );
+#endif
diff --git a/src/USER-REAXC/reaxc_reset_tools.cpp b/src/USER-REAXC/reaxc_reset_tools.cpp
new file mode 100644
index 0000000000..7b7141f5a5
--- /dev/null
+++ b/src/USER-REAXC/reaxc_reset_tools.cpp
@@ -0,0 +1,254 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#include "reaxc_types.h"
+#if defined(PURE_REAX)
+#include "reset_tools.h"
+#include "list.h"
+#include "tool_box.h"
+#include "vector.h"
+#elif defined(LAMMPS_REAX)
+#include "reaxc_reset_tools.h"
+#include "reaxc_list.h"
+#include "reaxc_tool_box.h"
+#include "reaxc_vector.h"
+#endif
+
+
+void Reset_Atoms( reax_system* system, control_params *control )
+{
+  int i;
+  reax_atom *atom;
+
+  system->numH = 0;
+  if( control->hbond_cut > 0 )
+    for( i = 0; i < system->n; ++i ) {
+      atom = &(system->my_atoms[i]);
+      if( system->reax_param.sbp[ atom->type ].p_hbond == 1 )
+	atom->Hindex = system->numH++;
+      else atom->Hindex = -1;
+    }
+}
+
+
+void Reset_Energies( energy_data *en )
+{
+  en->e_bond = 0;
+  en->e_ov = 0;
+  en->e_un = 0;
+  en->e_lp = 0;
+  en->e_ang = 0;
+  en->e_pen = 0;
+  en->e_coa = 0;
+  en->e_hb = 0;
+  en->e_tor = 0;
+  en->e_con = 0;
+  en->e_vdW = 0;
+  en->e_ele = 0;
+  en->e_pol = 0;
+
+  en->e_pot = 0;
+  en->e_kin = 0;
+  en->e_tot = 0;
+}
+
+
+void Reset_Temperatures( simulation_data *data )
+{
+  data->therm.T = 0;
+}
+
+
+void Reset_Pressures( simulation_data *data )
+{
+  data->flex_bar.P_scalar = 0;
+  rtensor_MakeZero( data->flex_bar.P );
+  
+  data->iso_bar.P = 0;
+  rvec_MakeZero( data->int_press );
+  rvec_MakeZero( data->my_ext_press );
+  rvec_MakeZero( data->ext_press );
+}
+
+
+void Reset_Simulation_Data( simulation_data* data, int virial )
+{
+  Reset_Energies( &data->my_en );
+  Reset_Energies( &data->sys_en );
+  Reset_Temperatures( data );
+  //if( virial )
+  Reset_Pressures( data );
+}
+
+
+void Reset_Timing( reax_timing *rt )
+{
+  rt->total = Get_Time();
+  rt->comm = 0;
+  rt->nbrs = 0;
+  rt->init_forces = 0;
+  rt->bonded = 0;
+  rt->nonb = 0;
+  rt->qEq = 0;
+  rt->s_matvecs = 0;
+  rt->t_matvecs = 0;
+}
+
+#ifdef TEST_FORCES
+void Reset_Test_Forces( reax_system *system, storage *workspace )
+{
+  memset( workspace->f_ele, 0, system->total_cap * sizeof(rvec) );
+  memset( workspace->f_vdw, 0, system->total_cap * sizeof(rvec) );
+  memset( workspace->f_bo, 0, system->total_cap * sizeof(rvec) );
+  memset( workspace->f_be, 0, system->total_cap * sizeof(rvec) );
+  memset( workspace->f_lp, 0, system->total_cap * sizeof(rvec) );
+  memset( workspace->f_ov, 0, system->total_cap * sizeof(rvec) );
+  memset( workspace->f_un, 0, system->total_cap * sizeof(rvec) );
+  memset( workspace->f_ang, 0, system->total_cap * sizeof(rvec) );
+  memset( workspace->f_coa, 0, system->total_cap * sizeof(rvec) );
+  memset( workspace->f_pen, 0, system->total_cap * sizeof(rvec) );
+  memset( workspace->f_hb, 0, system->total_cap * sizeof(rvec) );
+  memset( workspace->f_tor, 0, system->total_cap * sizeof(rvec) );
+  memset( workspace->f_con, 0, system->total_cap * sizeof(rvec) );
+}
+#endif
+
+
+void Reset_Workspace( reax_system *system, storage *workspace )
+{
+  memset( workspace->total_bond_order, 0, system->total_cap * sizeof( real ) );
+  memset( workspace->dDeltap_self, 0, system->total_cap * sizeof( rvec ) );
+  memset( workspace->CdDelta, 0, system->total_cap * sizeof( real ) );
+  memset( workspace->f, 0, system->total_cap * sizeof( rvec ) );
+
+#ifdef TEST_FORCES
+  memset( workspace->dDelta, 0, sizeof(rvec) * system->total_cap );
+  Reset_Test_Forces( system, workspace );
+#endif
+}
+
+
+void Reset_Grid( grid *g )
+{
+  int i, j, k;
+
+  for( i = 0; i < g->ncells[0]; i++ )
+    for( j = 0; j < g->ncells[1]; j++ ) 
+      for( k = 0; k < g->ncells[2]; k++ ) {
+	g->cells[i][j][k].top = 0;
+	g->cells[i][j][k].str = 0;
+	g->cells[i][j][k].end = 0;
+      }
+}
+
+
+void Reset_Out_Buffers( mpi_out_data *out_buf, int n )
+{
+  int i;
+
+  for( i = 0; i < n; ++i )
+    out_buf[i].cnt = 0;
+}
+
+
+void Reset_Neighbor_Lists( reax_system *system, control_params *control,
+			   storage *workspace, reax_list **lists, 
+			   MPI_Comm comm )
+{
+  int i, total_bonds, Hindex, total_hbonds;
+  reax_list *bonds, *hbonds;
+
+  /* bonds list */
+  if( system->N > 0 ){
+    bonds = (*lists) + BONDS;
+    total_bonds = 0;
+
+    /* reset start-end indexes */
+    for( i = 0; i < system->N; ++i ) {
+      Set_Start_Index( i, total_bonds, bonds );
+      Set_End_Index( i, total_bonds, bonds );
+      total_bonds += system->my_atoms[i].num_bonds;
+    }
+
+    /* is reallocation needed? */
+    if( total_bonds >= bonds->num_intrs * DANGER_ZONE ) {
+      workspace->realloc.bonds = 1;
+      if( total_bonds >= bonds->num_intrs ) {
+	fprintf(stderr, 
+		"p%d: not enough space for bonds! total=%d allocated=%d\n", 
+		system->my_rank, total_bonds, bonds->num_intrs );
+	MPI_Abort( comm, INSUFFICIENT_MEMORY );
+      }
+    }
+  }
+
+  // fprintf( stderr, "p%d: n:%d num_intrs:%d  num_H:%d\n",
+  //   system->my_rank, hbonds->n, hbonds->num_intrs, workspace->num_H );
+  // MPI_Barrier( comm );
+  /* hbonds list */
+  if( control->hbond_cut > 0 && system->numH > 0 ) { 
+    hbonds = (*lists) + HBONDS;
+    total_hbonds = 0;
+    
+    /* reset start-end indexes */
+    for( i = 0; i < system->n; ++i ) {
+      Hindex = system->my_atoms[i].Hindex;
+      if( Hindex > -1 ) {
+	Set_Start_Index( Hindex, total_hbonds, hbonds );
+	Set_End_Index( Hindex, total_hbonds, hbonds );
+	total_hbonds += system->my_atoms[i].num_hbonds;
+      }
+    }
+    
+    /* is reallocation needed? */
+    if( total_hbonds >= hbonds->num_intrs * 0.90/*DANGER_ZONE*/ ) {
+      workspace->realloc.hbonds = 1;
+      if( total_hbonds >= hbonds->num_intrs ) {
+	fprintf(stderr, 
+		"p%d: not enough space for hbonds! total=%d allocated=%d\n", 
+		system->my_rank, total_hbonds, hbonds->num_intrs );
+	MPI_Abort( comm, INSUFFICIENT_MEMORY );
+      }
+    }
+  }
+  // fprintf( stderr, "p%d: cleared hbonds\n", system->my_rank );
+  // MPI_Barrier( comm );
+}
+
+
+void Reset( reax_system *system, control_params *control, simulation_data *data,
+	    storage *workspace, reax_list **lists, MPI_Comm comm )
+{
+  Reset_Atoms( system, control );
+  
+  Reset_Simulation_Data( data, control->virial );
+
+  Reset_Workspace( system, workspace );  
+
+  Reset_Neighbor_Lists( system, control, workspace, lists, comm );
+
+#if defined(DEBUG_FOCUS) 
+  fprintf( stderr, "p%d @ step%d: reset done\n", system->my_rank, data->step );
+  MPI_Barrier( comm );
+#endif
+
+}
+
diff --git a/src/USER-REAXC/reaxc_reset_tools.h b/src/USER-REAXC/reaxc_reset_tools.h
new file mode 100644
index 0000000000..988883dfe7
--- /dev/null
+++ b/src/USER-REAXC/reaxc_reset_tools.h
@@ -0,0 +1,40 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#ifndef __RESET_TOOLS_H_
+#define __RESET_TOOLS_H_
+
+#include "reaxc_types.h"
+
+void Reset_Pressures( simulation_data* );
+void Reset_Simulation_Data( simulation_data*, int );
+void Reset_Timing( reax_timing* );
+void Reset_Workspace( reax_system*, storage* );
+void Reset_Grid( grid* );
+void Reset_Out_Buffers( mpi_out_data*, int );
+void Reset_Neighbor_Lists( reax_system*, control_params*, storage*, 
+			   reax_list**, MPI_Comm );
+void Reset( reax_system*, control_params*, simulation_data*, storage*,
+	    reax_list**, MPI_Comm );
+#ifdef TEST_FORCES
+void Reset_Test_Forces( reax_system*, storage* );
+#endif
+#endif
diff --git a/src/USER-REAXC/reaxc_system_props.cpp b/src/USER-REAXC/reaxc_system_props.cpp
new file mode 100644
index 0000000000..9997394afa
--- /dev/null
+++ b/src/USER-REAXC/reaxc_system_props.cpp
@@ -0,0 +1,411 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#include "reaxc_types.h"
+#if defined(PURE_REAX)
+#include "system_props.h"
+#include "tool_box.h"
+#include "vector.h"
+#elif defined(LAMMPS_REAX)
+#include "reaxc_system_props.h"
+#include "reaxc_tool_box.h"
+#include "reaxc_vector.h"
+#endif
+
+
+void Temperature_Control( control_params *control, simulation_data *data )
+{
+  real tmp;
+
+  if( control->T_mode == 1 ) {// step-wise temperature control 
+    if((data->step-data->prev_steps) % ((int)(control->T_freq/control->dt))==0){
+      if( fabs( control->T - control->T_final ) >= fabs( control->T_rate ) )
+	control->T += control->T_rate;
+      else control->T = control->T_final;	 
+    }
+  }
+  else if( control->T_mode == 2 ) { // constant slope control
+    tmp = control->T_rate * control->dt / control->T_freq;
+    
+    if( fabs( control->T - control->T_final ) >= fabs( tmp ) )
+      control->T += tmp;       
+  }
+}
+
+
+
+void Compute_Kinetic_Energy( reax_system* system, simulation_data* data, 
+			     MPI_Comm comm )
+{
+  int i;
+  rvec p;
+  real m;
+
+  data->my_en.e_kin = 0.0;
+  data->sys_en.e_kin = 0.0;
+  data->therm.T = 0;
+
+  for( i = 0; i < system->n; i++ ) {
+    m = system->reax_param.sbp[system->my_atoms[i].type].mass;
+    
+    rvec_Scale( p, m, system->my_atoms[i].v );
+    data->my_en.e_kin += 0.5 * rvec_Dot( p, system->my_atoms[i].v );
+  }
+  
+  MPI_Allreduce( &data->my_en.e_kin,  &data->sys_en.e_kin,  
+		 1, MPI_DOUBLE, MPI_SUM, comm );
+
+  data->therm.T = (2. * data->sys_en.e_kin) / (data->N_f * K_B);
+
+  // avoid T being an absolute zero, might cause F.P.E!
+  if( fabs(data->therm.T) < ALMOST_ZERO ) 
+    data->therm.T = ALMOST_ZERO;
+}
+
+
+void Compute_System_Energy( reax_system *system, simulation_data *data, 
+			    MPI_Comm comm )
+{
+  real my_en[15], sys_en[15];
+  
+  my_en[0] = data->my_en.e_bond;
+  my_en[1] = data->my_en.e_ov;
+  my_en[2] = data->my_en.e_un;
+  my_en[3] = data->my_en.e_lp;
+  my_en[4] = data->my_en.e_ang;
+  my_en[5] = data->my_en.e_pen;
+  my_en[6] = data->my_en.e_coa;
+  my_en[7] = data->my_en.e_hb;
+  my_en[8] = data->my_en.e_tor;
+  my_en[9] = data->my_en.e_con;
+  my_en[10] = data->my_en.e_vdW;
+  my_en[11] = data->my_en.e_ele;
+  my_en[12] = data->my_en.e_pol;
+  my_en[13] = data->my_en.e_kin;
+  MPI_Reduce( my_en, sys_en, 14, MPI_DOUBLE, MPI_SUM, MASTER_NODE, comm );
+
+  data->my_en.e_pot = data->my_en.e_bond + 
+    data->my_en.e_ov + data->my_en.e_un  + data->my_en.e_lp +
+    data->my_en.e_ang + data->my_en.e_pen + data->my_en.e_coa + 
+    data->my_en.e_hb + 
+    data->my_en.e_tor + data->my_en.e_con + 
+    data->my_en.e_vdW + data->my_en.e_ele + data->my_en.e_pol;
+  
+  data->my_en.e_tot = data->my_en.e_pot + E_CONV * data->my_en.e_kin;
+
+  if( system->my_rank == MASTER_NODE ) {
+    data->sys_en.e_bond = sys_en[0];
+    data->sys_en.e_ov = sys_en[1];
+    data->sys_en.e_un = sys_en[2];
+    data->sys_en.e_lp = sys_en[3];
+    data->sys_en.e_ang = sys_en[4];
+    data->sys_en.e_pen = sys_en[5];
+    data->sys_en.e_coa = sys_en[6];
+    data->sys_en.e_hb = sys_en[7];
+    data->sys_en.e_tor = sys_en[8];
+    data->sys_en.e_con = sys_en[9];
+    data->sys_en.e_vdW = sys_en[10];
+    data->sys_en.e_ele = sys_en[11];
+    data->sys_en.e_pol = sys_en[12];
+    data->sys_en.e_kin = sys_en[13];
+
+    data->sys_en.e_pot = data->sys_en.e_bond + 
+      data->sys_en.e_ov + data->sys_en.e_un  + data->sys_en.e_lp +
+      data->sys_en.e_ang + data->sys_en.e_pen + data->sys_en.e_coa + 
+      data->sys_en.e_hb + 
+      data->sys_en.e_tor + data->sys_en.e_con + 
+      data->sys_en.e_vdW + data->sys_en.e_ele + data->sys_en.e_pol;
+    
+    data->sys_en.e_tot = data->sys_en.e_pot + E_CONV * data->sys_en.e_kin;
+  }
+}
+
+
+void Compute_Total_Mass( reax_system *system, simulation_data *data, 
+			 MPI_Comm comm  )
+{
+  int  i;
+  real tmp;
+  
+  tmp = 0;
+  for( i = 0; i < system->n; i++ )
+    tmp += system->reax_param.sbp[ system->my_atoms[i].type ].mass;
+
+  MPI_Allreduce( &tmp, &data->M, 1, MPI_DOUBLE, MPI_SUM, comm );
+
+  data->inv_M = 1. / data->M;
+}
+
+
+
+void Compute_Center_of_Mass( reax_system *system, simulation_data *data, 
+			     mpi_datatypes *mpi_data, MPI_Comm comm )
+{
+  int i;
+  real m, det; //xx, xy, xz, yy, yz, zz;
+  real tmp_mat[6], tot_mat[6];
+  rvec my_xcm, my_vcm, my_amcm, my_avcm;
+  rvec tvec, diff;
+  rtensor mat, inv;
+
+  rvec_MakeZero( my_xcm );  // position of CoM
+  rvec_MakeZero( my_vcm );  // velocity of CoM
+  rvec_MakeZero( my_amcm ); // angular momentum of CoM
+  rvec_MakeZero( my_avcm ); // angular velocity of CoM
+
+  /* Compute the position, vel. and ang. momentum about the centre of mass */
+  for( i = 0; i < system->n; ++i ) {
+    m = system->reax_param.sbp[ system->my_atoms[i].type ].mass;
+
+    rvec_ScaledAdd( my_xcm, m, system->my_atoms[i].x );
+    rvec_ScaledAdd( my_vcm, m, system->my_atoms[i].v );
+    
+    rvec_Cross( tvec, system->my_atoms[i].x, system->my_atoms[i].v );
+    rvec_ScaledAdd( my_amcm, m, tvec );
+  }
+  
+  MPI_Allreduce( my_xcm, data->xcm, 3, MPI_DOUBLE, MPI_SUM, comm );
+  MPI_Allreduce( my_vcm, data->vcm, 3, MPI_DOUBLE, MPI_SUM, comm );
+  MPI_Allreduce( my_amcm, data->amcm, 3, MPI_DOUBLE, MPI_SUM, comm );
+
+  rvec_Scale( data->xcm, data->inv_M, data->xcm );
+  rvec_Scale( data->vcm, data->inv_M, data->vcm );
+  rvec_Cross( tvec, data->xcm, data->vcm );
+  rvec_ScaledAdd( data->amcm, -data->M, tvec );
+  data->etran_cm = 0.5 * data->M * rvec_Norm_Sqr( data->vcm );
+
+  /* Calculate and then invert the inertial tensor */
+  for( i = 0; i < 6; ++i )
+    tmp_mat[i] = 0;
+  //my_xx = my_xy = my_xz = my_yy = my_yz = my_zz = 0;
+
+  for( i = 0; i < system->n; ++i ){
+    m = system->reax_param.sbp[ system->my_atoms[i].type ].mass;
+    rvec_ScaledSum( diff, 1., system->my_atoms[i].x, -1., data->xcm );
+
+    tmp_mat[0]/*my_xx*/ += diff[0] * diff[0] * m;
+    tmp_mat[1]/*my_xy*/ += diff[0] * diff[1] * m;
+    tmp_mat[2]/*my_xz*/ += diff[0] * diff[2] * m;
+    tmp_mat[3]/*my_yy*/ += diff[1] * diff[1] * m;
+    tmp_mat[4]/*my_yz*/ += diff[1] * diff[2] * m;
+    tmp_mat[5]/*my_zz*/ += diff[2] * diff[2] * m;      
+  }
+  
+  MPI_Reduce( tmp_mat, tot_mat, 6, MPI_DOUBLE, MPI_SUM, MASTER_NODE, comm );
+
+  if( system->my_rank == MASTER_NODE ) {
+    mat[0][0] = tot_mat[3] + tot_mat[5];  // yy + zz;
+    mat[0][1] = mat[1][0] = -tot_mat[1];  // -xy;
+    mat[0][2] = mat[2][0] = -tot_mat[2];  // -xz;
+    mat[1][1] = tot_mat[0] + tot_mat[5];  // xx + zz;
+    mat[2][1] = mat[1][2] = -tot_mat[4];  // -yz;
+    mat[2][2] = tot_mat[0] + tot_mat[3];  // xx + yy;
+    
+    /* invert the inertial tensor */
+    det = ( mat[0][0] * mat[1][1] * mat[2][2] + 
+	    mat[0][1] * mat[1][2] * mat[2][0] + 
+	    mat[0][2] * mat[1][0] * mat[2][1] ) -
+      ( mat[0][0] * mat[1][2] * mat[2][1] + 
+	mat[0][1] * mat[1][0] * mat[2][2] + 
+	mat[0][2] * mat[1][1] * mat[2][0] );
+    
+    inv[0][0] = mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1];
+    inv[0][1] = mat[0][2] * mat[2][1] - mat[0][1] * mat[2][2];
+    inv[0][2] = mat[0][1] * mat[1][2] - mat[0][2] * mat[1][1];
+    inv[1][0] = mat[1][2] * mat[2][0] - mat[1][0] * mat[2][2];
+    inv[1][1] = mat[0][0] * mat[2][2] - mat[0][2] * mat[2][0];
+    inv[1][2] = mat[0][2] * mat[1][0] - mat[0][0] * mat[1][2];
+    inv[2][0] = mat[1][0] * mat[2][1] - mat[2][0] * mat[1][1];
+    inv[2][1] = mat[2][0] * mat[0][1] - mat[0][0] * mat[2][1];
+    inv[2][2] = mat[0][0] * mat[1][1] - mat[1][0] * mat[0][1];
+    
+    if( det > ALMOST_ZERO )
+      rtensor_Scale( inv, 1./det, inv );
+    else rtensor_MakeZero( inv );
+
+    /* Compute the angular velocity about the centre of mass */
+    rtensor_MatVec( data->avcm, inv, data->amcm );
+  }
+
+  MPI_Bcast( data->avcm, 3, MPI_DOUBLE, MASTER_NODE, comm );
+
+  /* Compute the rotational energy */
+  data->erot_cm = 0.5 * E_CONV * rvec_Dot( data->avcm, data->amcm );
+
+#if defined(DEBUG)
+  fprintf( stderr, "xcm:  %24.15e %24.15e %24.15e\n", 
+	   data->xcm[0], data->xcm[1], data->xcm[2] );
+  fprintf( stderr, "vcm:  %24.15e %24.15e %24.15e\n", 
+	   data->vcm[0], data->vcm[1], data->vcm[2] );  
+  fprintf( stderr, "amcm: %24.15e %24.15e %24.15e\n", 
+	   data->amcm[0], data->amcm[1], data->amcm[2] );
+  /* fprintf( stderr, "mat:  %f %f %f\n     %f %f %f\n     %f %f %f\n",
+     mat[0][0], mat[0][1], mat[0][2], 
+     mat[1][0], mat[1][1], mat[1][2], 
+     mat[2][0], mat[2][1], mat[2][2] );
+     fprintf( stderr, "inv:  %g %g %g\n     %g %g %g\n     %g %g %g\n",
+     inv[0][0], inv[0][1], inv[0][2], 
+     inv[1][0], inv[1][1], inv[1][2], 
+     inv[2][0], inv[2][1], inv[2][2] ); */
+  fprintf( stderr, "avcm: %24.15e %24.15e %24.15e\n", 
+	   data->avcm[0], data->avcm[1], data->avcm[2] );
+#endif
+}
+
+
+
+/* IMPORTANT: This function assumes that current kinetic energy
+ * the system is already computed
+ *
+ * IMPORTANT: In Klein's paper, it is stated that a dU/dV term needs 
+ *  to be added when there are long-range interactions or long-range 
+ *  corrections to short-range interactions present.
+ *  We may want to add that for more accuracy. 
+ */
+void Compute_Pressure(reax_system* system, control_params *control, 
+		      simulation_data* data, mpi_datatypes *mpi_data)
+{
+  int i;
+  reax_atom *p_atom;
+  rvec tmp, tx, int_press;
+  simulation_box *big_box = &(system->big_box);
+
+  /* Calculate internal pressure */
+  rvec_MakeZero( int_press );
+
+  // 0: both int and ext, 1: ext only, 2: int only
+  if( control->press_mode == 0 || control->press_mode == 2 ) {
+    for( i = 0; i < system->n; ++i ) {
+      p_atom = &( system->my_atoms[i] );
+      
+      /* transform x into unitbox coordinates */
+      Transform_to_UnitBox( p_atom->x, big_box, 1, tx );
+      
+      /* this atom's contribution to internal pressure */
+      rvec_Multiply( tmp, p_atom->f, tx );
+      rvec_Add( int_press, tmp );
+      
+#if defined(DEBUG)
+      fprintf( stderr, "%8d%8.2f%8.2f%8.2f", 
+	       i+1, p_atom->x[0], p_atom->x[1], p_atom->x[2] );
+      fprintf( stderr, "%8.2f%8.2f%8.2f", 
+	       p_atom->f[0], p_atom->f[1], p_atom->f[2] );
+      fprintf( stderr, "%8.2f%8.2f%8.2f\n", 
+	       int_press[0], int_press[1], int_press[2] );
+#endif
+    }
+  }
+
+  /* sum up internal and external pressure */
+#if defined(DEBUG)  
+  fprintf(stderr,"p%d:p_int(%10.5f %10.5f %10.5f)p_ext(%10.5f %10.5f %10.5f)\n",
+	  system->my_rank, int_press[0], int_press[1], int_press[2],
+	  data->my_ext_press[0], data->my_ext_press[1], data->my_ext_press[2] );
+#endif
+  MPI_Allreduce( int_press, data->int_press, 
+		 3, MPI_DOUBLE, MPI_SUM, mpi_data->comm_mesh3D );
+  MPI_Allreduce( data->my_ext_press, data->ext_press, 
+		 3, MPI_DOUBLE, MPI_SUM, mpi_data->comm_mesh3D );
+#if defined(DEBUG)  
+  fprintf( stderr, "p%d: %10.5f %10.5f %10.5f\n", 
+	   system->my_rank, 
+	   data->int_press[0], data->int_press[1], data->int_press[2] );
+  fprintf( stderr, "p%d: %10.5f %10.5f %10.5f\n", 
+	   system->my_rank,
+	   data->ext_press[0], data->ext_press[1], data->ext_press[2] );
+#endif
+
+  /* kinetic contribution */
+  data->kin_press = 2.*(E_CONV*data->sys_en.e_kin) / (3.*big_box->V*P_CONV);
+
+  /* Calculate total pressure in each direction */  
+  data->tot_press[0] = data->kin_press - 
+    (( data->int_press[0] + data->ext_press[0] ) / 
+     ( big_box->box_norms[1] * big_box->box_norms[2] * P_CONV ));
+
+  data->tot_press[1] = data->kin_press - 
+    (( data->int_press[1] + data->ext_press[1] ) / 
+     ( big_box->box_norms[0] * big_box->box_norms[2] * P_CONV ));
+
+  data->tot_press[2] = data->kin_press - 
+    (( data->int_press[2] + data->ext_press[2] ) / 
+     ( big_box->box_norms[0] * big_box->box_norms[1] * P_CONV ));
+
+  /* Average pressure for the whole box */
+  data->iso_bar.P = 
+    ( data->tot_press[0] + data->tot_press[1] + data->tot_press[2] ) / 3.;
+}
+
+
+
+/*
+void Compute_Pressure_Isotropic_Klein( reax_system* system, 
+				       simulation_data* data )
+{
+  int i;
+  reax_atom *p_atom;
+  rvec dx;
+
+  // IMPORTANT: This function assumes that current kinetic energy and 
+  // the center of mass of the system is already computed before.
+  data->iso_bar.P = 2.0 * data->my_en.e_kin;
+
+  for( i = 0; i < system->N; ++i ) {
+    p_atom = &( system->my_atoms[i] );
+    rvec_ScaledSum(dx,1.0,p_atom->x,-1.0,data->xcm);
+    data->iso_bar.P += ( -F_CONV * rvec_Dot(p_atom->f, dx) );
+  }
+  
+  data->iso_bar.P /= (3.0 * system->my_box.V);
+  
+  // IMPORTANT: In Klein's paper, it is stated that a dU/dV term needs 
+  // to be added when there are long-range interactions or long-range 
+  // corrections to short-range interactions present.
+  // We may want to add that for more accuracy.
+}
+
+
+void Compute_Pressure( reax_system* system, simulation_data* data )
+{
+  int i;
+  reax_atom *p_atom;
+  rtensor temp;
+
+  rtensor_MakeZero( data->flex_bar.P );
+  
+  for( i = 0; i < system->N; ++i ) {
+    p_atom = &( system->my_atoms[i] );
+    
+    // Distance_on_T3_Gen( data->rcm, p_atom->x, &(system->my_box), &dx );
+    
+    rvec_OuterProduct( temp, p_atom->v, p_atom->v );
+    rtensor_ScaledAdd( data->flex_bar.P, 
+		       system->reax_param.sbp[ p_atom->type ].mass, temp );
+    
+    // rvec_OuterProduct(temp,workspace->virial_forces[i],p_atom->x); //dx);
+    rtensor_ScaledAdd( data->flex_bar.P, -F_CONV, temp );
+  }
+  
+  rtensor_Scale( data->flex_bar.P, 1.0 / system->my_box.V, data->flex_bar.P );
+  
+  data->iso_bar.P = rtensor_Trace( data->flex_bar.P ) / 3.0;
+}
+*/
diff --git a/src/USER-REAXC/reaxc_system_props.h b/src/USER-REAXC/reaxc_system_props.h
new file mode 100644
index 0000000000..712a6f679f
--- /dev/null
+++ b/src/USER-REAXC/reaxc_system_props.h
@@ -0,0 +1,41 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#ifndef __SYSTEM_PROP_H_
+#define __SYSTEM_PROP_H_
+
+#include "reaxc_types.h"
+
+void Temperature_Control( control_params*, simulation_data* );
+
+void Compute_Kinetic_Energy( reax_system*, simulation_data*, MPI_Comm );
+
+void Compute_System_Energy( reax_system*, simulation_data*, MPI_Comm );
+
+void Compute_Total_Mass( reax_system*, simulation_data*, MPI_Comm );
+
+void Compute_Center_of_Mass( reax_system*, simulation_data*, 
+			     mpi_datatypes*, MPI_Comm );
+
+void Compute_Pressure( reax_system*, control_params*, 
+		       simulation_data*, mpi_datatypes* );
+//void Compute_Pressure( reax_system*, simulation_data* );
+#endif
diff --git a/src/USER-REAXC/reaxc_tool_box.cpp b/src/USER-REAXC/reaxc_tool_box.cpp
new file mode 100644
index 0000000000..074921248c
--- /dev/null
+++ b/src/USER-REAXC/reaxc_tool_box.cpp
@@ -0,0 +1,467 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#include "reaxc_types.h"
+#if defined(PURE_REAX)
+#include "tool_box.h"
+#elif defined(LAMMPS_REAX)
+#include "reaxc_tool_box.h"
+#endif
+
+
+#if defined(PURE_REAX)
+/************** taken from comm_tools.c **************/
+int SumScan( int n, int me, int root, MPI_Comm comm )
+{
+  int  i, my_order, wsize;;
+  int *nbuf = NULL;
+
+  if( me == root ) {
+    MPI_Comm_size( comm, &wsize );
+    nbuf = (int *) calloc( wsize, sizeof(int) );
+    
+    MPI_Gather( &n, 1, MPI_INT, nbuf, 1, MPI_INT, root, comm );
+    
+    for( i = 0; i < wsize-1; ++i ) {
+      nbuf[i+1] += nbuf[i];
+    }
+    
+    MPI_Scatter( nbuf, 1, MPI_INT, &my_order, 1, MPI_INT, root, comm );
+    
+    free( nbuf );
+  }
+  else {
+    MPI_Gather( &n, 1, MPI_INT, nbuf, 1, MPI_INT, root, comm );
+    MPI_Scatter( nbuf, 1, MPI_INT, &my_order, 1, MPI_INT, root, comm );
+  }
+  
+  return my_order;
+}
+
+
+void SumScanB( int n, int me, int wsize, int root, MPI_Comm comm, int *nbuf )
+{
+  int  i;
+
+  MPI_Gather( &n, 1, MPI_INT, nbuf, 1, MPI_INT, root, comm );
+
+  if( me == root ) {
+    for( i = 0; i < wsize-1; ++i )
+      nbuf[i+1] += nbuf[i];
+  }
+ 
+  MPI_Bcast( nbuf, wsize, MPI_INT, root, comm );
+}
+#endif
+
+
+/************** taken from box.c **************/
+void Transform( rvec x1, simulation_box *box, char flag, rvec x2 )
+{
+  int i, j;
+  real tmp;
+
+  //  printf(">x1: (%lf, %lf, %lf)\n",x1[0],x1[1],x1[2]);
+	  
+  if (flag > 0) {
+    for (i=0; i < 3; i++) {
+      tmp = 0.0;
+      for (j=0; j < 3; j++)
+	tmp += box->trans[i][j]*x1[j]; 
+      x2[i] = tmp;
+    }
+  }
+  else {
+    for (i=0; i < 3; i++) {
+      tmp = 0.0;
+      for (j=0; j < 3; j++)
+	tmp += box->trans_inv[i][j]*x1[j]; 
+      x2[i] = tmp;
+    }
+  }
+  //  printf(">x2: (%lf, %lf, %lf)\n", x2[0], x2[1], x2[2]);  
+}
+
+
+void Transform_to_UnitBox( rvec x1, simulation_box *box, char flag, rvec x2 )
+{
+  Transform( x1, box, flag, x2 );
+  
+  x2[0] /= box->box_norms[0];
+  x2[1] /= box->box_norms[1];
+  x2[2] /= box->box_norms[2];
+}
+
+
+/* determine whether point p is inside the box */
+void Fit_to_Periodic_Box( simulation_box *box, rvec *p )
+{
+  int i;
+
+  for( i = 0; i < 3; ++i ) {
+    if( (*p)[i] < box->min[i] ) { 
+      /* handle lower coords */
+      while( (*p)[i] < box->min[i] )
+	(*p)[i] += box->box_norms[i];
+    }
+    else if( (*p)[i] >= box->max[i] ) {
+      /* handle higher coords */
+      while( (*p)[i] >= box->max[i] )
+	(*p)[i] -= box->box_norms[i];
+    }
+  }
+}
+
+#if defined(PURE_REAX)
+/* determine the touch point, tp, of a box to 
+   its neighbor denoted by the relative coordinate rl */
+inline void Box_Touch_Point( simulation_box *box, ivec rl, rvec tp )
+{
+  int d;
+
+  for( d = 0; d < 3; ++d )
+    if( rl[d] == -1 )
+      tp[d] = box->min[d];
+    else if( rl[d] == 0 )
+      tp[d] = NEG_INF - 1.;
+    else
+      tp[d] = box->max[d];
+}
+
+
+/* determine whether point p is inside the box */
+/* assumes orthogonal box */
+inline int is_Inside_Box( simulation_box *box, rvec p )
+{
+  if( p[0] < box->min[0] || p[0] >= box->max[0] || 
+      p[1] < box->min[1] || p[1] >= box->max[1] || 
+      p[2] < box->min[2] || p[2] >= box->max[2] )
+     return 0;
+
+  return 1;
+}
+
+
+inline int iown_midpoint( simulation_box *box, rvec p1, rvec p2 )
+{
+  rvec midp;
+
+  midp[0] = (p1[0] + p2[0]) / 2;
+  midp[1] = (p1[1] + p2[1]) / 2;
+  midp[2] = (p1[2] + p2[2]) / 2;
+
+  if( midp[0] < box->min[0] || midp[0] >= box->max[0] || 
+      midp[1] < box->min[1] || midp[1] >= box->max[1] || 
+      midp[2] < box->min[2] || midp[2] >= box->max[2] )
+     return 0;
+  
+  return 1;
+}
+
+
+
+/**************** from grid.c ****************/
+/* finds the closest point of grid cell cj to ci.
+   no need to consider periodic boundary conditions as in the serial case 
+   because the box of a process is not periodic in itself */
+inline void GridCell_Closest_Point( grid_cell *gci, grid_cell *gcj,
+				    ivec ci, ivec cj, rvec cp )
+{
+  int  d;
+  
+  for( d = 0; d < 3; d++ )
+    if( cj[d] > ci[d] )
+      cp[d] = gcj->min[d];
+    else if ( cj[d] == ci[d] )
+      cp[d] = NEG_INF - 1.;
+    else
+      cp[d] = gcj->max[d];
+}
+
+
+
+inline void GridCell_to_Box_Points( grid_cell *gc, ivec rl, rvec cp, rvec fp )
+{
+  int d;
+ 
+  for( d = 0; d < 3; ++d )
+    if( rl[d] == -1 ) {
+      cp[d] = gc->min[d];
+      fp[d] = gc->max[d];
+    }
+    else if( rl[d] == 0 ) {
+      cp[d] = fp[d] = NEG_INF - 1.;
+    }
+    else{
+      cp[d] = gc->max[d];
+      fp[d] = gc->min[d];
+    }  
+}
+
+
+inline real DistSqr_between_Special_Points( rvec sp1, rvec sp2 )
+{
+  int  i;
+  real d_sqr = 0;
+
+  for( i = 0; i < 3; ++i )
+    if( sp1[i] > NEG_INF && sp2[i] > NEG_INF )
+      d_sqr += SQR( sp1[i] - sp2[i] );
+
+  return d_sqr;
+}
+
+
+inline real DistSqr_to_Special_Point( rvec cp, rvec x )
+{
+  int  i;
+  real d_sqr = 0;
+
+  for( i = 0; i < 3; ++i )
+    if( cp[i] > NEG_INF )
+      d_sqr += SQR( cp[i] - x[i] );
+
+  return d_sqr;
+}
+
+
+inline int Relative_Coord_Encoding( ivec c )
+{
+  return 9 * (c[0] + 1) + 3 * (c[1] + 1) + (c[2] + 1);
+}
+#endif
+
+
+/************** from geo_tools.c *****************/
+void Make_Point( real x, real y, real z, rvec* p )
+{
+  (*p)[0] = x;
+  (*p)[1] = y;
+  (*p)[2] = z;
+}
+
+
+
+int is_Valid_Serial( storage *workspace, int serial )
+{
+  // if( workspace->map_serials[ serial ] < 0 )
+  // {
+  // fprintf( stderr, "CONECT line includes invalid pdb serial number %d.\n", 
+  // serial );
+  // fprintf( stderr, "Please correct the input file.Terminating...\n" );
+  //  MPI_Abort( MPI_COMM_WORLD, INVALID_INPUT );
+  // }
+  
+  return SUCCESS;
+}
+
+
+
+int Check_Input_Range( int val, int lo, int hi, char *message, MPI_Comm comm )
+{
+  if( val < lo || val > hi ) {
+    fprintf( stderr, "%s\nInput %d - Out of range %d-%d. Terminating...\n", 
+	     message, val, lo, hi );
+    MPI_Abort( comm, INVALID_INPUT );
+  }
+  
+  return 1;
+}
+
+
+void Trim_Spaces( char *element )
+{
+  int i, j;
+
+  for( i = 0; element[i] == ' '; ++i ); // skip initial space chars
+  
+  for( j = i; j < (int)(strlen(element)) && element[j] != ' '; ++j )
+    element[j-i] = toupper( element[j] ); // make uppercase, offset to 0
+  element[j-i] = 0; // finalize the string
+}
+
+
+/************ from system_props.c *************/
+struct timeval tim;
+real t_end;
+ 
+real Get_Time( )
+{
+  gettimeofday(&tim, NULL );
+  return( tim.tv_sec + (tim.tv_usec / 1000000.0) );
+}
+
+
+real Get_Timing_Info( real t_start )
+{ 
+  gettimeofday(&tim, NULL );
+  t_end = tim.tv_sec + (tim.tv_usec / 1000000.0);
+  return (t_end - t_start);
+}
+
+
+void Update_Timing_Info( real *t_start, real *timing )
+{
+  gettimeofday(&tim, NULL );
+  t_end = tim.tv_sec + (tim.tv_usec / 1000000.0);
+  *timing += (t_end - *t_start);
+  *t_start = t_end;
+}
+
+
+/*********** from io_tools.c **************/
+int Get_Atom_Type( reax_interaction *reax_param, char *s, MPI_Comm comm )
+{
+  int i;
+
+  for( i = 0; i < reax_param->num_atom_types; ++i )
+    if( !strcmp( reax_param->sbp[i].name, s ) )
+      return i;
+
+  fprintf( stderr, "Unknown atom type %s. Terminating...\n", s );
+  MPI_Abort( comm, UNKNOWN_ATOM_TYPE );
+  
+  return -1;
+}
+
+
+
+char *Get_Element( reax_system *system, int i )
+{
+  return &( system->reax_param.sbp[system->my_atoms[i].type].name[0] );
+}
+
+
+
+char *Get_Atom_Name( reax_system *system, int i )
+{
+  return &(system->my_atoms[i].name[0]);
+}
+
+
+
+int Allocate_Tokenizer_Space( char **line, char **backup, char ***tokens )
+{
+  int i;
+
+  if( (*line = (char*) malloc( sizeof(char) * MAX_LINE )) == NULL )
+    return FAILURE;
+
+  if( (*backup = (char*) malloc( sizeof(char) * MAX_LINE )) == NULL )
+    return FAILURE;
+
+  if( (*tokens = (char**) malloc( sizeof(char*) * MAX_TOKENS )) == NULL )
+    return FAILURE;
+
+  for( i = 0; i < MAX_TOKENS; i++ )
+    if( ((*tokens)[i] = (char*) malloc(sizeof(char) * MAX_TOKEN_LEN)) == NULL )
+      return FAILURE;
+
+  return SUCCESS;
+}
+
+
+
+int Tokenize( char* s, char*** tok )
+{
+  char test[MAX_LINE];
+  char *sep = "\t \n!=";
+  char *word;
+  int count=0;
+
+  strncpy( test, s, MAX_LINE );
+  
+  for( word = strtok(test, sep); word; word = strtok(NULL, sep) ) {
+    strncpy( (*tok)[count], word, MAX_LINE );
+    count++;
+  }
+
+  return count;
+}
+
+
+/***************** taken from lammps ************************/
+/* safe malloc */
+void *smalloc( long n, char *name, MPI_Comm comm )
+{
+  void *ptr;
+
+  if( n <= 0 ) {
+    fprintf( stderr, "WARNING: trying to allocate %ld bytes for array %s. ",
+	     n, name );
+    fprintf( stderr, "returning NULL.\n" );
+    return NULL;
+  }
+
+  ptr = malloc( n );
+  if( ptr == NULL ) {
+    fprintf( stderr, "ERROR: failed to allocate %ld bytes for array %s", 
+	     n, name );
+    MPI_Abort( comm, INSUFFICIENT_MEMORY );
+  }
+
+  return ptr;
+}
+
+
+/* safe calloc */
+void *scalloc( int n, int size, char *name, MPI_Comm comm )
+{
+  void *ptr;
+
+  if( n <= 0 ) {
+    fprintf( stderr, "WARNING: trying to allocate %d elements for array %s. ",
+	     n, name );
+    fprintf( stderr, "returning NULL.\n" );
+    return NULL;
+  }
+
+  if( size <= 0 ) {
+    fprintf( stderr, "WARNING: elements size for array %s is %d. ",
+	     name, size );
+    fprintf( stderr, "returning NULL.\n" );
+    return NULL;
+  }
+
+  ptr = calloc( n, size );
+  if( ptr == NULL ) {
+    fprintf( stderr, "ERROR: failed to allocate %d bytes for array %s", 
+	     n*size, name );
+    MPI_Abort( comm, INSUFFICIENT_MEMORY );
+  }
+
+  return ptr;
+}
+
+
+/* safe free */
+void sfree( void *ptr, char *name )
+{
+  if( ptr == NULL ) {
+    fprintf( stderr, "WARNING: trying to free the already NULL pointer %s!\n",
+	     name );
+    return;
+  }
+  
+  free( ptr );
+  ptr = NULL;
+}
+
diff --git a/src/USER-REAXC/reaxc_tool_box.h b/src/USER-REAXC/reaxc_tool_box.h
new file mode 100644
index 0000000000..9a0b60247b
--- /dev/null
+++ b/src/USER-REAXC/reaxc_tool_box.h
@@ -0,0 +1,69 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#ifndef __TOOL_BOX_H_
+#define __TOOL_BOX_H_
+
+#include "reaxc_types.h"
+#include "reaxc_defs.h"
+
+/* from comm_tools.h */
+int SumScan( int, int, int, MPI_Comm );
+void SumScanB( int, int, int, int, MPI_Comm, int* );
+
+/* from box.h */
+void Transform_to_UnitBox( rvec, simulation_box*, char, rvec );
+void Fit_to_Periodic_Box( simulation_box*, rvec* );
+void Box_Touch_Point( simulation_box*, ivec, rvec );
+int  is_Inside_Box( simulation_box*, rvec );
+int  iown_midpoint( simulation_box*, rvec, rvec );
+
+/* from grid.h */
+void GridCell_Closest_Point( grid_cell*, grid_cell*, ivec, ivec, rvec );
+void GridCell_to_Box_Points( grid_cell*, ivec, rvec, rvec );
+real DistSqr_between_Special_Points( rvec, rvec );
+real DistSqr_to_Special_Point( rvec, rvec );
+int Relative_Coord_Encoding( ivec );
+
+/* from geo_tools.h */
+void Make_Point( real, real, real, rvec* );
+int is_Valid_Serial( storage*, int );
+int Check_Input_Range( int, int, int, char*, MPI_Comm );
+void Trim_Spaces( char* );
+
+/* from system_props.h */
+real Get_Time( );
+real Get_Timing_Info( real );
+void Update_Timing_Info( real*, real* );
+
+/* from io_tools.h */
+int   Get_Atom_Type( reax_interaction*, char*, MPI_Comm );
+char *Get_Element( reax_system*, int );
+char *Get_Atom_Name( reax_system*, int );
+int   Allocate_Tokenizer_Space( char**, char**, char*** );
+int   Tokenize( char*, char*** );
+
+/* from lammps */
+void *smalloc( long, char*, MPI_Comm );
+void *scalloc( int, int, char*, MPI_Comm );
+void sfree( void*, char* );
+
+#endif
diff --git a/src/USER-REAXC/reaxc_torsion_angles.cpp b/src/USER-REAXC/reaxc_torsion_angles.cpp
new file mode 100644
index 0000000000..f1afe3c3a6
--- /dev/null
+++ b/src/USER-REAXC/reaxc_torsion_angles.cpp
@@ -0,0 +1,590 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#include "reaxc_types.h"
+#if defined(PURE_REAX)
+#include "torsion_angles.h"
+#include "bond_orders.h"
+#include "list.h"
+#include "tool_box.h"
+#include "vector.h"
+#elif defined(LAMMPS_REAX)
+#include "reaxc_torsion_angles.h"
+#include "reaxc_bond_orders.h"
+#include "reaxc_list.h"
+#include "reaxc_tool_box.h"
+#include "reaxc_vector.h"
+#endif
+
+#define MIN_SINE 1e-10
+
+real Calculate_Omega( rvec dvec_ij, real r_ij,
+		      rvec dvec_jk, real r_jk,
+		      rvec dvec_kl, real r_kl,
+		      rvec dvec_li, real r_li,
+		      three_body_interaction_data *p_ijk, 
+		      three_body_interaction_data *p_jkl, 
+		      rvec dcos_omega_di, rvec dcos_omega_dj, 
+		      rvec dcos_omega_dk, rvec dcos_omega_dl, 
+		      output_controls *out_control )
+{
+  real unnorm_cos_omega, unnorm_sin_omega, omega;
+  real sin_ijk, cos_ijk, sin_jkl, cos_jkl;
+  real htra, htrb, htrc, hthd, hthe, hnra, hnrc, hnhd, hnhe;
+  real arg, poem, tel;
+  rvec cross_jk_kl;
+
+  sin_ijk = sin( p_ijk->theta );
+  cos_ijk = cos( p_ijk->theta );
+  sin_jkl = sin( p_jkl->theta );
+  cos_jkl = cos( p_jkl->theta );
+
+  /* omega */
+  unnorm_cos_omega = -rvec_Dot(dvec_ij, dvec_jk) * rvec_Dot(dvec_jk, dvec_kl) + 
+    SQR( r_jk ) *  rvec_Dot( dvec_ij, dvec_kl );
+
+  rvec_Cross( cross_jk_kl, dvec_jk, dvec_kl );
+  unnorm_sin_omega = -r_jk * rvec_Dot( dvec_ij, cross_jk_kl );
+
+  omega = atan2( unnorm_sin_omega, unnorm_cos_omega ); 
+
+
+  /* derivatives */
+  /* coef for adjusments to cos_theta's */
+  /* rla = r_ij, rlb = r_jk, rlc = r_kl, r4 = r_li;
+     coshd = cos_ijk, coshe = cos_jkl;
+     sinhd = sin_ijk, sinhe = sin_jkl; */
+  htra = r_ij + cos_ijk * ( r_kl * cos_jkl - r_jk );
+  htrb = r_jk - r_ij * cos_ijk - r_kl * cos_jkl;
+  htrc = r_kl + cos_jkl * ( r_ij * cos_ijk - r_jk );
+  hthd = r_ij * sin_ijk * ( r_jk - r_kl * cos_jkl );
+  hthe = r_kl * sin_jkl * ( r_jk - r_ij * cos_ijk );
+  hnra = r_kl * sin_ijk * sin_jkl;
+  hnrc = r_ij * sin_ijk * sin_jkl;
+  hnhd = r_ij * r_kl * cos_ijk * sin_jkl;
+  hnhe = r_ij * r_kl * sin_ijk * cos_jkl;
+
+
+  poem = 2.0 * r_ij * r_kl * sin_ijk * sin_jkl;
+  if( poem < 1e-20 ) poem = 1e-20;
+
+  tel  = SQR( r_ij ) + SQR( r_jk ) + SQR( r_kl ) - SQR( r_li ) - 
+    2.0 * ( r_ij * r_jk * cos_ijk - r_ij * r_kl * cos_ijk * cos_jkl + 
+	    r_jk * r_kl * cos_jkl );
+				  
+  arg  = tel / poem;
+  if( arg >  1.0 ) arg =  1.0;
+  if( arg < -1.0 ) arg = -1.0;
+
+
+  /* fprintf( out_control->etor, 
+     "%12.6f%12.6f%12.6f%12.6f%12.6f%12.6f%12.6f%12.6f%12.6f\n",
+     htra, htrb, htrc, hthd, hthe, hnra, hnrc, hnhd, hnhe );
+     fprintf( out_control->etor, "%12.6f%12.6f%12.6f\n",
+     dvec_ij[0]/r_ij, dvec_ij[1]/r_ij, dvec_ij[2]/r_ij );
+     fprintf( out_control->etor, "%12.6f%12.6f%12.6f\n",
+     -dvec_jk[0]/r_jk, -dvec_jk[1]/r_jk, -dvec_jk[2]/r_jk );
+     fprintf( out_control->etor, "%12.6f%12.6f%12.6f\n",
+     -dvec_kl[0]/r_kl, -dvec_kl[1]/r_kl, -dvec_kl[2]/r_kl );
+     fprintf( out_control->etor, "%12.6f%12.6f%12.6f%12.6f\n",
+     r_li, dvec_li[0], dvec_li[1], dvec_li[2] );
+     fprintf( out_control->etor, "%12.6f%12.6f%12.6f\n",
+     poem, tel, arg ); */
+  /* fprintf( out_control->etor, "%12.6f%12.6f%12.6f\n",
+     -p_ijk->dcos_dk[0]/sin_ijk, -p_ijk->dcos_dk[1]/sin_ijk, 
+     -p_ijk->dcos_dk[2]/sin_ijk );
+     fprintf( out_control->etor, "%12.6f%12.6f%12.6f\n",
+     -p_jkl->dcos_dk[0]/sin_jkl, -p_jkl->dcos_dk[1]/sin_jkl, 
+     -p_jkl->dcos_dk[2]/sin_jkl );*/
+
+  if( sin_ijk >= 0 && sin_ijk <= MIN_SINE ) sin_ijk = MIN_SINE;
+  else if( sin_ijk <= 0 && sin_ijk >= -MIN_SINE ) sin_ijk = -MIN_SINE;
+  if( sin_jkl >= 0 && sin_jkl <= MIN_SINE ) sin_jkl = MIN_SINE;
+  else if( sin_jkl <= 0 && sin_jkl >= -MIN_SINE ) sin_jkl = -MIN_SINE;
+
+  // dcos_omega_di
+  rvec_ScaledSum( dcos_omega_di, (htra-arg*hnra)/r_ij, dvec_ij, -1., dvec_li );
+  rvec_ScaledAdd( dcos_omega_di,-(hthd-arg*hnhd)/sin_ijk, p_ijk->dcos_dk );
+  rvec_Scale( dcos_omega_di, 2.0 / poem, dcos_omega_di );
+
+  // dcos_omega_dj
+  rvec_ScaledSum( dcos_omega_dj,-(htra-arg*hnra)/r_ij, dvec_ij, 
+		  -htrb / r_jk, dvec_jk );
+  rvec_ScaledAdd( dcos_omega_dj,-(hthd-arg*hnhd)/sin_ijk, p_ijk->dcos_dj );
+  rvec_ScaledAdd( dcos_omega_dj,-(hthe-arg*hnhe)/sin_jkl, p_jkl->dcos_di );
+  rvec_Scale( dcos_omega_dj, 2.0 / poem, dcos_omega_dj );
+
+  // dcos_omega_dk
+  rvec_ScaledSum( dcos_omega_dk,-(htrc-arg*hnrc)/r_kl, dvec_kl,  
+		  htrb / r_jk, dvec_jk );
+  rvec_ScaledAdd( dcos_omega_dk,-(hthd-arg*hnhd)/sin_ijk, p_ijk->dcos_di );
+  rvec_ScaledAdd( dcos_omega_dk,-(hthe-arg*hnhe)/sin_jkl, p_jkl->dcos_dj );
+  rvec_Scale( dcos_omega_dk, 2.0 / poem, dcos_omega_dk );
+
+  // dcos_omega_dl
+  rvec_ScaledSum( dcos_omega_dl, (htrc-arg*hnrc)/r_kl, dvec_kl, 1., dvec_li );
+  rvec_ScaledAdd( dcos_omega_dl,-(hthe-arg*hnhe)/sin_jkl, p_jkl->dcos_dk );
+  rvec_Scale( dcos_omega_dl, 2.0 / poem, dcos_omega_dl );
+
+  return omega;  
+}
+
+
+
+void Torsion_Angles( reax_system *system, control_params *control, 
+		     simulation_data *data, storage *workspace, 
+		     reax_list **lists, output_controls *out_control )
+{
+  int i, j, k, l, pi, pj, pk, pl, pij, plk, natoms;
+  int type_i, type_j, type_k, type_l;
+  int start_j, end_j, start_k, end_k;
+  int start_pj, end_pj, start_pk, end_pk;
+  int num_frb_intrs = 0;
+
+  real Delta_j, Delta_k;
+  real r_ij, r_jk, r_kl, r_li;
+  real BOA_ij, BOA_jk, BOA_kl;
+
+  real exp_tor2_ij, exp_tor2_jk, exp_tor2_kl;
+  real exp_tor1, exp_tor3_DjDk, exp_tor4_DjDk, exp_tor34_inv;
+  real exp_cot2_jk, exp_cot2_ij, exp_cot2_kl;
+  real fn10, f11_DjDk, dfn11, fn12;
+  real theta_ijk, theta_jkl;
+  real sin_ijk, sin_jkl;
+  real cos_ijk, cos_jkl;
+  real tan_ijk_i, tan_jkl_i;
+  real omega, cos_omega, cos2omega, cos3omega;
+  rvec dcos_omega_di, dcos_omega_dj, dcos_omega_dk, dcos_omega_dl;
+  real CV, cmn, CEtors1, CEtors2, CEtors3, CEtors4;
+  real CEtors5, CEtors6, CEtors7, CEtors8, CEtors9;
+  real Cconj, CEconj1, CEconj2, CEconj3;
+  real CEconj4, CEconj5, CEconj6;
+  real e_tor, e_con;
+  rvec dvec_li;
+  rvec force, ext_press;
+  ivec rel_box_jl;
+  // rtensor total_rtensor, temp_rtensor;
+  four_body_header *fbh;
+  four_body_parameters *fbp;
+  bond_data *pbond_ij, *pbond_jk, *pbond_kl;
+  bond_order_data *bo_ij, *bo_jk, *bo_kl;
+  three_body_interaction_data *p_ijk, *p_jkl;
+  real p_tor2 = system->reax_param.gp.l[23];
+  real p_tor3 = system->reax_param.gp.l[24];
+  real p_tor4 = system->reax_param.gp.l[25];
+  real p_cot2 = system->reax_param.gp.l[27];
+  reax_list *bonds = (*lists) + BONDS;
+  reax_list *thb_intrs = (*lists) + THREE_BODIES;
+  // char  fname[100];
+  // FILE *ftor;
+
+  // sprintf( fname, "tor%d.out", system->my_rank );
+  // ftor = fopen( fname, "w" );
+
+  natoms = system->n;
+
+  for( j = 0; j < natoms; ++j ) {
+    type_j = system->my_atoms[j].type;
+    Delta_j = workspace->Delta_boc[j];
+    start_j = Start_Index(j, bonds);
+    end_j = End_Index(j, bonds);
+        
+    for( pk = start_j; pk < end_j; ++pk ) {
+      pbond_jk = &( bonds->select.bond_list[pk] );
+      k = pbond_jk->nbr;
+      bo_jk = &( pbond_jk->bo_data );
+      BOA_jk = bo_jk->BO - control->thb_cut;
+	
+      /* see if there are any 3-body interactions involving j&k
+	 where j is the central atom. Otherwise there is no point in
+	 trying to form a 4-body interaction out of this neighborhood */
+      if( system->my_atoms[j].orig_id < system->my_atoms[k].orig_id && 
+	  bo_jk->BO > control->thb_cut/*0*/ && Num_Entries(pk, thb_intrs) ) {
+	start_k = Start_Index(k, bonds);
+	end_k = End_Index(k, bonds);	    	       
+	pj = pbond_jk->sym_index; // pj points to j on k's list
+	  
+	/* do the same check as above: 
+	   are there any 3-body interactions involving k&j 
+	   where k is the central atom */
+	if( Num_Entries(pj, thb_intrs) ) {
+	  type_k = system->my_atoms[k].type;
+	  Delta_k = workspace->Delta_boc[k];
+	  r_jk = pbond_jk->d;
+	    
+	  start_pk = Start_Index(pk, thb_intrs );
+	  end_pk = End_Index(pk, thb_intrs );
+	  start_pj = Start_Index(pj, thb_intrs );
+	  end_pj = End_Index(pj, thb_intrs );		
+	    
+	  exp_tor2_jk = exp( -p_tor2 * BOA_jk );
+	  exp_cot2_jk = exp( -p_cot2 * SQR(BOA_jk - 1.5) );
+	  exp_tor3_DjDk = exp( -p_tor3 * (Delta_j + Delta_k) );
+	  exp_tor4_DjDk = exp( p_tor4  * (Delta_j + Delta_k) );
+	  exp_tor34_inv = 1.0 / (1.0 + exp_tor3_DjDk + exp_tor4_DjDk);
+	  f11_DjDk = (2.0 + exp_tor3_DjDk) * exp_tor34_inv;
+	    
+	    
+	  /* pick i up from j-k interaction where j is the central atom */
+	  for( pi = start_pk; pi < end_pk; ++pi ) {
+	    p_ijk = &( thb_intrs->select.three_body_list[pi] );
+	    pij = p_ijk->pthb; // pij is pointer to i on j's bond_list
+	    pbond_ij = &( bonds->select.bond_list[pij] );
+	    bo_ij = &( pbond_ij->bo_data );
+	      
+	      
+	    if( bo_ij->BO > control->thb_cut/*0*/ ) {
+	      i = p_ijk->thb;
+	      type_i = system->my_atoms[i].type;
+	      r_ij = pbond_ij->d;
+	      BOA_ij = bo_ij->BO - control->thb_cut;
+		
+	      theta_ijk = p_ijk->theta;
+	      sin_ijk = sin( theta_ijk );
+	      cos_ijk = cos( theta_ijk );
+	      //tan_ijk_i = 1. / tan( theta_ijk );
+	      if( sin_ijk >= 0 && sin_ijk <= MIN_SINE ) 
+		tan_ijk_i = cos_ijk / MIN_SINE;
+	      else if( sin_ijk <= 0 && sin_ijk >= -MIN_SINE ) 
+		tan_ijk_i = cos_ijk / -MIN_SINE;
+	      else tan_ijk_i = cos_ijk / sin_ijk;
+		
+	      exp_tor2_ij = exp( -p_tor2 * BOA_ij );
+	      exp_cot2_ij = exp( -p_cot2 * SQR(BOA_ij -1.5) );
+		
+		
+	      /* pick l up from j-k interaction where k is the central atom */
+	      for( pl = start_pj; pl < end_pj; ++pl ) {
+		p_jkl = &( thb_intrs->select.three_body_list[pl] );
+		l = p_jkl->thb;
+		plk = p_jkl->pthb; //pointer to l on k's bond_list!
+		pbond_kl = &( bonds->select.bond_list[plk] );
+		bo_kl = &( pbond_kl->bo_data );
+		type_l = system->my_atoms[l].type;
+		fbh = &(system->reax_param.fbp[type_i][type_j]
+			[type_k][type_l]);
+		fbp = &(system->reax_param.fbp[type_i][type_j]
+			[type_k][type_l].prm[0]);
+
+		  
+		if( i != l && fbh->cnt && 
+		    bo_kl->BO > control->thb_cut/*0*/ &&
+		    bo_ij->BO * bo_jk->BO * bo_kl->BO > control->thb_cut/*0*/ ){
+		  ++num_frb_intrs;
+		  r_kl = pbond_kl->d;
+		  BOA_kl = bo_kl->BO - control->thb_cut;
+		    
+		  theta_jkl = p_jkl->theta;
+		  sin_jkl = sin( theta_jkl );
+		  cos_jkl = cos( theta_jkl );
+		  //tan_jkl_i = 1. / tan( theta_jkl );
+		  if( sin_jkl >= 0 && sin_jkl <= MIN_SINE ) 
+		    tan_jkl_i = cos_jkl / MIN_SINE;
+		  else if( sin_jkl <= 0 && sin_jkl >= -MIN_SINE ) 
+		    tan_jkl_i = cos_jkl / -MIN_SINE;
+		  else tan_jkl_i = cos_jkl /sin_jkl;
+		    
+		  rvec_ScaledSum( dvec_li, 1., system->my_atoms[i].x, 
+				  -1., system->my_atoms[l].x );
+		  r_li = rvec_Norm( dvec_li );				 
+		    
+		    
+		  /* omega and its derivative */
+		  omega = Calculate_Omega( pbond_ij->dvec, r_ij, 
+					   pbond_jk->dvec, r_jk, 
+					   pbond_kl->dvec, r_kl,
+					   dvec_li, r_li,
+					   p_ijk, p_jkl,
+					   dcos_omega_di, dcos_omega_dj,
+					   dcos_omega_dk, dcos_omega_dl,
+					   out_control );
+		    
+		  cos_omega = cos( omega );
+		  cos2omega = cos( 2. * omega );
+		  cos3omega = cos( 3. * omega );
+		  /* end omega calculations */
+		    
+		  /* torsion energy */
+		  exp_tor1 = exp( fbp->p_tor1 * 
+				  SQR(2.0 - bo_jk->BO_pi - f11_DjDk) );
+		  exp_tor2_kl = exp( -p_tor2 * BOA_kl );
+		  exp_cot2_kl = exp( -p_cot2 * SQR(BOA_kl - 1.5) );
+		  fn10 = (1.0 - exp_tor2_ij) * (1.0 - exp_tor2_jk) * 
+		    (1.0 - exp_tor2_kl);
+		    
+		  CV = 0.5 * ( fbp->V1 * (1.0 + cos_omega) + 
+			       fbp->V2 * exp_tor1 * (1.0 - cos2omega) +
+			       fbp->V3 * (1.0 + cos3omega) );
+		    
+		  data->my_en.e_tor += e_tor = fn10 * sin_ijk * sin_jkl * CV;
+		    
+		  dfn11 = (-p_tor3 * exp_tor3_DjDk +
+			   (p_tor3 * exp_tor3_DjDk - p_tor4 * exp_tor4_DjDk) *
+			   (2.0 + exp_tor3_DjDk) * exp_tor34_inv) * 
+		    exp_tor34_inv;
+		    
+		  CEtors1 = sin_ijk * sin_jkl * CV;
+		    
+		  CEtors2 = -fn10 * 2.0 * fbp->p_tor1 * fbp->V2 * exp_tor1 *
+		    (2.0 - bo_jk->BO_pi - f11_DjDk) * (1.0 - SQR(cos_omega)) *
+		    sin_ijk * sin_jkl; 
+		  CEtors3 = CEtors2 * dfn11;
+		    
+		  CEtors4 = CEtors1 * p_tor2 * exp_tor2_ij * 
+		    (1.0 - exp_tor2_jk) * (1.0 - exp_tor2_kl);
+		  CEtors5 = CEtors1 * p_tor2 * 
+		    (1.0 - exp_tor2_ij) * exp_tor2_jk * (1.0 - exp_tor2_kl);
+		  CEtors6 = CEtors1 * p_tor2 * 
+		    (1.0 - exp_tor2_ij) * (1.0 - exp_tor2_jk) * exp_tor2_kl;
+		    
+		  cmn = -fn10 * CV;
+		  CEtors7 = cmn * sin_jkl * tan_ijk_i;
+		  CEtors8 = cmn * sin_ijk * tan_jkl_i;
+		    
+		  CEtors9 = fn10 * sin_ijk * sin_jkl * 
+		    (0.5 * fbp->V1 - 2.0 * fbp->V2 * exp_tor1 * cos_omega +
+		     1.5 * fbp->V3 * (cos2omega + 2.0 * SQR(cos_omega)));
+		  /* end  of torsion energy */
+				  
+
+		  /* 4-body conjugation energy */
+		  fn12 = exp_cot2_ij * exp_cot2_jk * exp_cot2_kl;
+		  data->my_en.e_con += e_con =
+		    fbp->p_cot1 * fn12 * 
+		    (1.0 + (SQR(cos_omega) - 1.0) * sin_ijk * sin_jkl);
+		    
+		  Cconj = -2.0 * fn12 * fbp->p_cot1 * p_cot2 * 
+		    (1.0 + (SQR(cos_omega) - 1.0) * sin_ijk * sin_jkl);
+		    
+		  CEconj1 = Cconj * (BOA_ij - 1.5e0);
+		  CEconj2 = Cconj * (BOA_jk - 1.5e0);
+		  CEconj3 = Cconj * (BOA_kl - 1.5e0);
+		    
+		  CEconj4 = -fbp->p_cot1 * fn12 * 
+		    (SQR(cos_omega) - 1.0) * sin_jkl * tan_ijk_i;
+		  CEconj5 = -fbp->p_cot1 * fn12 * 
+		    (SQR(cos_omega) - 1.0) * sin_ijk * tan_jkl_i;
+		  CEconj6 = 2.0 * fbp->p_cot1 * fn12 * 
+		    cos_omega * sin_ijk * sin_jkl;
+		  /* end 4-body conjugation energy */
+		  
+		  /* forces */
+		  bo_jk->Cdbopi += CEtors2;
+		  workspace->CdDelta[j] += CEtors3;
+		  workspace->CdDelta[k] += CEtors3;
+		  bo_ij->Cdbo += (CEtors4 + CEconj1);
+		  bo_jk->Cdbo += (CEtors5 + CEconj2);
+		  bo_kl->Cdbo += (CEtors6 + CEconj3);
+		    
+		  if( control->virial == 0 ) {
+		    /* dcos_theta_ijk */
+		    rvec_ScaledAdd( workspace->f[i], 
+				    CEtors7 + CEconj4, p_ijk->dcos_dk );
+		    rvec_ScaledAdd( workspace->f[j], 
+				    CEtors7 + CEconj4, p_ijk->dcos_dj );
+		    rvec_ScaledAdd( workspace->f[k], 
+				    CEtors7 + CEconj4, p_ijk->dcos_di );
+		      
+		    /* dcos_theta_jkl */
+		    rvec_ScaledAdd( workspace->f[j], 
+				    CEtors8 + CEconj5, p_jkl->dcos_di );
+		    rvec_ScaledAdd( workspace->f[k], 
+				    CEtors8 + CEconj5, p_jkl->dcos_dj );
+		    rvec_ScaledAdd( workspace->f[l], 
+				    CEtors8 + CEconj5, p_jkl->dcos_dk );
+		      
+		    /* dcos_omega */
+		    rvec_ScaledAdd( workspace->f[i], 
+				    CEtors9 + CEconj6, dcos_omega_di );
+		    rvec_ScaledAdd( workspace->f[j], 
+				    CEtors9 + CEconj6, dcos_omega_dj );
+		    rvec_ScaledAdd( workspace->f[k], 
+				    CEtors9 + CEconj6, dcos_omega_dk );
+		    rvec_ScaledAdd( workspace->f[l], 
+				    CEtors9 + CEconj6, dcos_omega_dl );
+		  }
+		  else {
+		    ivec_Sum(rel_box_jl, pbond_jk->rel_box, pbond_kl->rel_box);
+		      
+		    /* dcos_theta_ijk */
+		    rvec_Scale( force, CEtors7 + CEconj4, p_ijk->dcos_dk );
+		    rvec_Add( workspace->f[i], force );
+		    rvec_iMultiply( ext_press, pbond_ij->rel_box, force );
+		    rvec_Add( data->my_ext_press, ext_press );
+			
+		    rvec_ScaledAdd( workspace->f[j], 
+				    CEtors7 + CEconj4, p_ijk->dcos_dj );
+			
+		    rvec_Scale( force, CEtors7 + CEconj4, p_ijk->dcos_di );
+		    rvec_Add( workspace->f[k], force );
+		    rvec_iMultiply( ext_press, pbond_jk->rel_box, force );
+		    rvec_Add( data->my_ext_press, ext_press );
+		      
+		      
+		    /* dcos_theta_jkl */
+		    rvec_ScaledAdd( workspace->f[j], 
+				    CEtors8 + CEconj5, p_jkl->dcos_di );
+			
+		    rvec_Scale( force, CEtors8 + CEconj5, p_jkl->dcos_dj );
+		    rvec_Add( workspace->f[k], force );
+		    rvec_iMultiply( ext_press, pbond_jk->rel_box, force );
+		    rvec_Add( data->my_ext_press, ext_press );
+		      
+		    rvec_Scale( force, CEtors8 + CEconj5, p_jkl->dcos_dk );
+		    rvec_Add( workspace->f[l], force );
+		    rvec_iMultiply( ext_press, rel_box_jl, force );
+		    rvec_Add( data->my_ext_press, ext_press );
+		      
+		      
+		    /* dcos_omega */				      
+		    rvec_Scale( force, CEtors9 + CEconj6, dcos_omega_di );
+		    rvec_Add( workspace->f[i], force );
+		    rvec_iMultiply( ext_press, pbond_ij->rel_box, force );
+		    rvec_Add( data->my_ext_press, ext_press );
+		      
+		    rvec_ScaledAdd( workspace->f[j], 
+				    CEtors9 + CEconj6, dcos_omega_dj );
+		      
+		    rvec_Scale( force, CEtors9 + CEconj6, dcos_omega_dk );
+		    rvec_Add( workspace->f[k], force );
+		    rvec_iMultiply( ext_press, pbond_jk->rel_box, force );
+		    rvec_Add( data->my_ext_press, ext_press );
+		      
+		    rvec_Scale( force, CEtors9 + CEconj6, dcos_omega_dl );
+		    rvec_Add( workspace->f[l], force );
+		    rvec_iMultiply( ext_press, rel_box_jl, force );
+		    rvec_Add( data->my_ext_press, ext_press );
+		  }
+
+#ifdef TEST_ENERGY
+		  /* fprintf( out_control->etor, 
+		     "%12.8f%12.8f%12.8f%12.8f%12.8f%12.8f%12.8f\n",
+		     r_ij, r_jk, r_kl, cos_ijk, cos_jkl, sin_ijk, sin_jkl );
+		     fprintf( out_control->etor, "%12.8f\n", dfn11 ); */
+		  /* fprintf( out_control->etor, 
+		     "%12.8f%12.8f%12.8f%12.8f%12.8f%12.8f%12.8f%12.8f\n",
+		     CEtors2, CEtors3, CEtors4, CEtors5, CEtors6, 
+		     CEtors7, CEtors8, CEtors9 ); */
+		  /* fprintf( out_control->etor, 
+		     "%12.8f%12.8f%12.8f%12.8f%12.8f%12.8f%12.8f%12.8f\n",
+		     htra, htrb, htrc, hthd, hthe, hnra, hnrc, hnhd, hnhe ); */
+		  /* fprintf( out_control->etor, 
+		     "%12.8f%12.8f%12.8f%12.8f%12.8f%12.8f\n",
+		     CEconj1, CEconj2, CEconj3, CEconj4, CEconj5, CEconj6 ); */
+				  
+		  /* fprintf( out_control->etor, "%12.6f%12.6f%12.6f%12.6f\n",
+		     fbp->V1, fbp->V2, fbp->V3, fbp->p_tor1 );*/
+		  
+		  fprintf(out_control->etor, 
+			  //"%6d%6d%6d%6d%24.15e%24.15e%24.15e%24.15e\n", 
+			  "%6d%6d%6d%6d%12.4f%12.4f%12.4f%12.4f\n", 
+			  system->my_atoms[i].orig_id,system->my_atoms[j].orig_id, 
+			  system->my_atoms[k].orig_id,system->my_atoms[l].orig_id, 
+			   RAD2DEG(omega), BOA_jk, e_tor, data->my_en.e_tor );
+		  
+		  fprintf(out_control->econ, 
+			  //"%6d%6d%6d%6d%24.15e%24.15e%24.15e%24.15e%24.15e%24.15e\n", 
+			  "%6d%6d%6d%6d%12.4f%12.4f%12.4f%12.4f%12.4f%12.4f\n", 
+			  system->my_atoms[i].orig_id,system->my_atoms[j].orig_id, 
+			  system->my_atoms[k].orig_id,system->my_atoms[l].orig_id, 
+			  RAD2DEG(omega), BOA_ij, BOA_jk, BOA_kl, 
+			  e_con, data->my_en.e_con );
+#endif
+		    
+#ifdef TEST_FORCES
+		  /* Torsion Forces */
+		  Add_dBOpinpi2( system, lists, j, pk, CEtors2, 0.0, 
+				 workspace->f_tor, workspace->f_tor );
+		  Add_dDelta( system, lists, j, CEtors3, workspace->f_tor );
+		  Add_dDelta( system, lists, k, CEtors3, workspace->f_tor );
+		  Add_dBO( system, lists, j, pij, CEtors4, workspace->f_tor );
+		  Add_dBO( system, lists, j, pk, CEtors5, workspace->f_tor );
+		  Add_dBO( system, lists, k, plk, CEtors6, workspace->f_tor );
+		    
+		  rvec_ScaledAdd( workspace->f_tor[i], 
+				  CEtors7, p_ijk->dcos_dk );
+		  rvec_ScaledAdd( workspace->f_tor[j], 
+				  CEtors7, p_ijk->dcos_dj );
+		  rvec_ScaledAdd( workspace->f_tor[k], 
+				  CEtors7, p_ijk->dcos_di );
+			  
+		  rvec_ScaledAdd( workspace->f_tor[j], 
+				  CEtors8, p_jkl->dcos_di );
+		  rvec_ScaledAdd( workspace->f_tor[k], 
+				  CEtors8, p_jkl->dcos_dj );
+		  rvec_ScaledAdd( workspace->f_tor[l], 
+				  CEtors8, p_jkl->dcos_dk );
+			  
+		  rvec_ScaledAdd( workspace->f_tor[i], 
+				  CEtors9, dcos_omega_di );
+		  rvec_ScaledAdd( workspace->f_tor[j], 
+				  CEtors9, dcos_omega_dj );
+		  rvec_ScaledAdd( workspace->f_tor[k], 
+				  CEtors9, dcos_omega_dk );
+		  rvec_ScaledAdd( workspace->f_tor[l], 
+				  CEtors9, dcos_omega_dl );
+		    
+		  /* Conjugation Forces */
+		  Add_dBO( system, lists, j, pij, CEconj1, workspace->f_con );
+		  Add_dBO( system, lists, j, pk, CEconj2, workspace->f_con );
+		  Add_dBO( system, lists, k, plk, CEconj3, workspace->f_con );
+		    
+		  rvec_ScaledAdd( workspace->f_con[i], 
+				  CEconj4, p_ijk->dcos_dk );
+		  rvec_ScaledAdd( workspace->f_con[j], 
+				  CEconj4, p_ijk->dcos_dj );
+		  rvec_ScaledAdd( workspace->f_con[k], 
+				  CEconj4, p_ijk->dcos_di );
+		    
+		  rvec_ScaledAdd( workspace->f_con[j], 
+				  CEconj5, p_jkl->dcos_di );
+		  rvec_ScaledAdd( workspace->f_con[k], 
+				  CEconj5, p_jkl->dcos_dj );
+		  rvec_ScaledAdd( workspace->f_con[l], 
+				  CEconj5, p_jkl->dcos_dk );
+		    
+		  rvec_ScaledAdd( workspace->f_con[i], 
+				  CEconj6, dcos_omega_di );
+		  rvec_ScaledAdd( workspace->f_con[j], 
+				  CEconj6, dcos_omega_dj );
+		  rvec_ScaledAdd( workspace->f_con[k], 
+				  CEconj6, dcos_omega_dk );
+		  rvec_ScaledAdd( workspace->f_con[l], 
+				  CEconj6, dcos_omega_dl );
+#endif
+		} // pl check ends
+	      } // pl loop ends
+	    } // pi check ends
+	  } // pi loop ends
+	} // k-j neighbor check ends
+      } // j<k && j-k neighbor check ends
+    } // pk loop ends
+  } // j loop
+  
+#if defined(DEBUG)
+  fprintf( stderr, "Number of torsion angles: %d\n", num_frb_intrs );
+  fprintf( stderr, "Torsion Energy: %g\t Conjugation Energy: %g\n", 
+	   data->my_en.e_tor, data->my_en.e_con );
+
+  fprintf( stderr, "4body: ext_press (%12.6f %12.6f %12.6f)\n",
+	   data->ext_press[0], data->ext_press[1], data->ext_press[2] );
+#endif
+}
diff --git a/src/USER-REAXC/reaxc_torsion_angles.h b/src/USER-REAXC/reaxc_torsion_angles.h
new file mode 100644
index 0000000000..d3c25501e6
--- /dev/null
+++ b/src/USER-REAXC/reaxc_torsion_angles.h
@@ -0,0 +1,30 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#ifndef __TORSION_ANGLES_H_
+#define __TORSION_ANGLES_H_
+
+#include "reaxc_types.h"
+
+void Torsion_Angles( reax_system*, control_params*, simulation_data*,
+		     storage*, reax_list**, output_controls* );
+
+#endif
diff --git a/src/USER-REAXC/reaxc_traj.cpp b/src/USER-REAXC/reaxc_traj.cpp
new file mode 100644
index 0000000000..0aaa413156
--- /dev/null
+++ b/src/USER-REAXC/reaxc_traj.cpp
@@ -0,0 +1,1072 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#include "reaxc_types.h"
+#if defined(PURE_REAX)
+#include "traj.h"
+#include "list.h"
+#include "tool_box.h"
+#elif defined(LAMMPS_REAX)
+#include "reaxc_traj.h"
+#include "reaxc_list.h"
+#include "reaxc_tool_box.h"
+#endif
+
+
+#if defined(PURE_REAX)
+int Set_My_Trajectory_View( MPI_File trj, int offset, MPI_Datatype etype,
+			    MPI_Comm comm, int my_rank, int my_n, int big_n )
+{
+  int my_disp;
+  int length[3];
+  MPI_Aint line_len;
+  MPI_Aint disp[3];
+  MPI_Datatype type[3];
+  MPI_Datatype view;
+
+  /* line length inferred from etype */
+  MPI_Type_extent( etype, &line_len );
+  line_len /= sizeof(char);
+
+  /* determine where to start writing into the mpi file */
+  my_disp = SumScan( my_n, my_rank, MASTER_NODE, comm );
+  my_disp -= my_n;
+
+  /* create atom_info_view */
+  length[0] = 1;
+  length[1] = my_n;
+  length[2] = 1;
+  disp[0] = 0;
+  disp[1] = line_len * my_disp;
+  disp[2] = line_len * big_n;
+  type[0] = MPI_LB;
+  type[1] = etype;
+  type[2] = MPI_UB;
+
+  MPI_Type_struct( 3, length, disp, type, &view );
+  MPI_Type_commit( &view );
+
+  MPI_File_set_view( trj, offset, etype, view, "native", MPI_INFO_NULL );
+  
+  return my_disp;
+}
+#endif
+
+
+int Reallocate_Output_Buffer( output_controls *out_control, int req_space, 
+			      MPI_Comm comm )
+{
+  if( out_control->buffer_len > 0 ) 
+    free( out_control->buffer );
+
+  out_control->buffer_len = (int)(req_space*SAFE_ZONE);
+  out_control->buffer = (char*) malloc(out_control->buffer_len*sizeof(char));
+  if( out_control->buffer == NULL ) {
+    fprintf( stderr, 
+	     "insufficient memory for required buffer size %d. terminating!\n",
+	     (int) (req_space*SAFE_ZONE) );
+    MPI_Abort( comm, INSUFFICIENT_MEMORY );
+  }
+  
+  return SUCCESS;
+}
+
+
+void Write_Skip_Line( output_controls *out_control, mpi_datatypes *mpi_data, 
+		      int my_rank, int skip, int num_section )
+{
+#if defined(PURE_REAX)
+  MPI_Status status;
+
+  if( out_control->traj_method == MPI_TRAJ ) {
+    MPI_File_set_view( out_control->trj, out_control->trj_offset, 
+		       mpi_data->header_line, mpi_data->header_line, 
+		       "native", MPI_INFO_NULL );
+    if( my_rank == MASTER_NODE ) {
+      sprintf( out_control->line, INT2_LINE, "chars_to_skip_section:", 
+	       skip, num_section );
+      MPI_File_write( out_control->trj, out_control->line, 1, 
+		      mpi_data->header_line, &status );
+    }
+    out_control->trj_offset += HEADER_LINE_LEN;
+  }
+  else {
+    if( my_rank == MASTER_NODE )
+      fprintf( out_control->strj, INT2_LINE, 
+	       "chars_to_skip_section:", skip, num_section );
+  }
+#elif defined(LAMMPS_REAX)
+  if( my_rank == MASTER_NODE )
+    fprintf( out_control->strj, INT2_LINE, 
+	     "chars_to_skip_section:", skip, num_section );
+#endif
+
+}
+
+
+int Write_Header( reax_system *system, control_params *control, 
+		  output_controls *out_control, mpi_datatypes *mpi_data )
+{
+  int  num_hdr_lines, my_hdr_lines, buffer_req;
+  MPI_Status status;
+  char ensembles[ens_N][25] =  { "NVE", "NVT", "fully flexible NPT", 
+				 "semi isotropic NPT", "isotropic NPT" };
+  char reposition[3][25] = { "fit to periodic box", "CoM to center of box", 
+			     "CoM to origin" };
+  char t_regime[3][25] = { "T-coupling only", "step-wise", "constant slope" };
+
+  char traj_methods[TF_N][10] = { "custom", "xyz" };
+  char atom_formats[8][40] =  { "none", "invalid", "invalid", "invalid", 
+				"xyz_q", 
+				"xyz_q_fxfyfz", 
+				"xyz_q_vxvyvz", 
+				"detailed_atom_info" };
+  char bond_formats[3][30] = { "none", 
+			       "basic_bond_info", 
+			       "detailed_bond_info" };
+  char angle_formats[2][30] = { "none", "basic_angle_info" };
+
+  /* set header lengths */
+  num_hdr_lines = NUM_HEADER_LINES;
+  my_hdr_lines = num_hdr_lines * ( system->my_rank == MASTER_NODE );
+  buffer_req = my_hdr_lines * HEADER_LINE_LEN;
+  if( buffer_req > out_control->buffer_len * DANGER_ZONE )
+    Reallocate_Output_Buffer( out_control, buffer_req, mpi_data->world );
+
+  /* only the master node writes into trajectory header */
+  if( system->my_rank == MASTER_NODE ) {
+    /* clear the contents of line & buffer */
+    out_control->line[0] = 0;
+    out_control->buffer[0] = 0;
+    
+    /* to skip the header */
+    sprintf( out_control->line, INT_LINE, "chars_to_skip_header:", 
+	     (num_hdr_lines-1) * HEADER_LINE_LEN );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    /* general simulation info */
+    sprintf( out_control->line, STR_LINE, "simulation_name:", 
+	     out_control->traj_title );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, INT_LINE, "number_of_atoms:", system->bigN );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, STR_LINE, "ensemble_type:", 
+	     ensembles[ control->ensemble ] );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, INT_LINE, "number_of_steps:", 
+	     control->nsteps );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, REAL_LINE, "timestep_length_(in_fs):", 
+	     control->dt * 1000 );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    /* restart info */
+    sprintf( out_control->line, STR_LINE, "is_this_a_restart?:", 
+	     (control->restart ? "yes" : "no") );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    //sprintf( out_control->line, STR_LINE, "restarted_from_file:", 
+    //     (control->restart ? control->restart_from : "NA") );
+    //strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    //sprintf( out_control->line, STR_LINE, "kept_restart_velocities?:", 
+    //     (control->restart ? (control->random_vel ? "no":"yes"):"NA") );
+    //strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, STR_LINE, "write_restart_files?:", 
+	     ((out_control->restart_freq > 0) ? "yes" : "no") );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, INT_LINE, "frequency_to_write_restarts:", 
+	     out_control->restart_freq );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    /* preferences */
+    sprintf( out_control->line, STR_LINE, "tabulate_long_range_intrs?:", 
+	     (control->tabulate ? "yes" : "no") );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, INT_LINE, "table_size:", control->tabulate );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, STR_LINE, "restrict_bonds?:", 
+	     (control->restrict_bonds ? "yes" : "no") );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, INT_LINE, "bond_restriction_length:",
+	     control->restrict_bonds );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, STR_LINE, "reposition_atoms?:", 
+	     reposition[control->reposition_atoms] );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, INT_LINE, "remove_CoM_velocity?:", 
+	     (control->ensemble==NVE) ? 0 : control->remove_CoM_vel);
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    
+    /* cut-off values */
+    sprintf( out_control->line, REAL_LINE, "bonded_intr_dist_cutoff:", 
+	     control->bond_cut );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, REAL_LINE, "nonbonded_intr_dist_cutoff:", 
+	     control->nonb_cut );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, REAL_LINE, "hbond_dist_cutoff:", 
+	     control->hbond_cut );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, REAL_LINE, "reax_bond_threshold:", 
+	     control->bo_cut );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, REAL_LINE, "physical_bond_threshold:", 
+	     control->bg_cut );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, REAL_LINE, "valence_angle_threshold:", 
+	     control->thb_cut );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, SCI_LINE, "QEq_tolerance:", control->q_err );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    /* temperature controls */
+    sprintf( out_control->line, REAL_LINE, "initial_temperature:",
+	     control->T_init );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, REAL_LINE, "target_temperature:", 
+	     control->T_final );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, REAL_LINE, "thermal_inertia:", 
+	     control->Tau_T );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, STR_LINE, "temperature_regime:", 
+	     t_regime[ control->T_mode ] );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, REAL_LINE, "temperature_change_rate_(K/ps):", 
+	     control->T_rate / control->T_freq );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    /* pressure controls */
+    sprintf( out_control->line, REAL3_LINE, "target_pressure_(GPa):", 
+	     control->P[0], control->P[1], control->P[2] );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, REAL3_LINE, "virial_inertia:", 
+	     control->Tau_P[0], control->Tau_P[1], control->Tau_P[2] );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    /* trajectory */
+    sprintf( out_control->line, INT_LINE, "energy_dumping_freq:", 
+	     out_control->energy_update_freq );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, INT_LINE, "trajectory_dumping_freq:", 
+	     out_control->write_steps );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, STR_LINE, "compress_trajectory_output?:", 
+	     (out_control->traj_compress ? "yes" : "no") );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, STR_LINE, "trajectory_format:", 
+	     traj_methods[ out_control->traj_method ] );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, STR_LINE, "atom_info:", 
+	     atom_formats[ out_control->atom_info ] );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, STR_LINE, "bond_info:", 
+	     bond_formats[ out_control->bond_info ] );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, STR_LINE, "angle_info:", 
+	     angle_formats[ out_control->angle_info ] );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+      
+    /* analysis */
+    //sprintf( out_control->line, STR_LINE, "molecular_analysis:", 
+    //     (control->molec_anal ? "yes" : "no") );
+    //strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, INT_LINE, "molecular_analysis_frequency:", 
+	     control->molecular_analysis );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+  }
+
+  /* dump out the buffer */
+#if defined(PURE_REAX)
+  if( out_control->traj_method == MPI_TRAJ ) {
+    out_control->trj_offset = 0;
+    Set_My_Trajectory_View( out_control->trj, 
+			    out_control->trj_offset, mpi_data->header_line,
+			    mpi_data->world, system->my_rank, 
+			    my_hdr_lines, num_hdr_lines );
+    MPI_File_write_all( out_control->trj, out_control->buffer, 
+			num_hdr_lines, mpi_data->header_line, &status );
+    out_control->trj_offset = (num_hdr_lines) * HEADER_LINE_LEN;
+  }
+  else {
+    if( system->my_rank == MASTER_NODE )
+      fprintf( out_control->strj, "%s", out_control->buffer );
+  }
+#elif defined(LAMMPS_REAX)
+  if( system->my_rank == MASTER_NODE )
+    fprintf( out_control->strj, "%s", out_control->buffer );
+#endif
+  
+  return SUCCESS;
+}
+
+
+int Write_Init_Desc( reax_system *system, control_params *control,
+		     output_controls *out_control, mpi_datatypes *mpi_data )
+{
+  int i, me, np, cnt, buffer_len, buffer_req;
+  reax_atom *p_atom;
+  //MPI_Request request;
+  MPI_Status status;
+
+  me = system->my_rank;
+  np = system->wsize;
+
+  /* skip info */
+  Write_Skip_Line( out_control, mpi_data, me, 
+		   system->bigN * INIT_DESC_LEN, system->bigN );
+  
+  if( out_control->traj_method == REG_TRAJ && me == MASTER_NODE )
+    buffer_req = system->bigN * INIT_DESC_LEN + 1;
+  else buffer_req = system->n * INIT_DESC_LEN + 1;
+
+  if( buffer_req > out_control->buffer_len * DANGER_ZONE )
+    Reallocate_Output_Buffer( out_control, buffer_req, mpi_data->world );
+
+  out_control->line[0] = 0;
+  out_control->buffer[0] = 0;
+  for( i = 0; i < system->n; ++i ) {
+    p_atom = &( system->my_atoms[i] );
+    sprintf( out_control->line, INIT_DESC, 
+	     p_atom->orig_id, p_atom->type, p_atom->name, 
+	     system->reax_param.sbp[ p_atom->type ].mass );
+    strncpy( out_control->buffer + i*INIT_DESC_LEN, 
+	     out_control->line, INIT_DESC_LEN+1 );
+  }
+
+#if defined(PURE_REAX)
+  if( out_control->traj_method == MPI_TRAJ ) {
+    Set_My_Trajectory_View( out_control->trj, out_control->trj_offset, 
+			    mpi_data->init_desc_line, mpi_data->world, 
+			    me, system->n, system->bigN );
+    MPI_File_write( out_control->trj, out_control->buffer, system->n, 
+		    mpi_data->init_desc_line, &status );
+    out_control->trj_offset += system->bigN * INIT_DESC_LEN;
+  }
+  else{
+    if( me != MASTER_NODE )
+      MPI_Send( out_control->buffer, buffer_req-1, MPI_CHAR, MASTER_NODE, 
+		np * INIT_DESCS + me, mpi_data->world );
+    else{
+      buffer_len = system->n * INIT_DESC_LEN;
+      for( i = 0; i < np; ++i )
+	if( i != MASTER_NODE ) {
+	  MPI_Recv( out_control->buffer + buffer_len, buffer_req - buffer_len,
+		    MPI_CHAR, i, np*INIT_DESCS+i, mpi_data->world, &status );
+	  MPI_Get_count( &status, MPI_CHAR, &cnt );
+	  buffer_len += cnt;
+	}
+      out_control->buffer[buffer_len] = 0;
+      fprintf( out_control->strj, "%s", out_control->buffer );
+    }
+  }
+#elif defined(LAMMPS_REAX)
+  if( me != MASTER_NODE )
+    MPI_Send( out_control->buffer, buffer_req-1, MPI_CHAR, MASTER_NODE, 
+	      np * INIT_DESCS + me, mpi_data->world );
+  else{
+    buffer_len = system->n * INIT_DESC_LEN;
+    for( i = 0; i < np; ++i )
+      if( i != MASTER_NODE ) {
+	MPI_Recv( out_control->buffer + buffer_len, buffer_req - buffer_len,
+		  MPI_CHAR, i, np*INIT_DESCS+i, mpi_data->world, &status );
+	MPI_Get_count( &status, MPI_CHAR, &cnt );
+	buffer_len += cnt;
+      }
+    out_control->buffer[buffer_len] = 0;
+    fprintf( out_control->strj, "%s", out_control->buffer );
+  }
+#endif
+
+  return SUCCESS;
+}
+
+
+int Init_Traj( reax_system *system, control_params *control, 
+	       output_controls *out_control, mpi_datatypes *mpi_data, 
+	       char *msg )
+{
+  char fname[MAX_STR];
+  int  atom_line_len[ NR_OPT_ATOM ] = { 0, 0, 0, 0, 
+					ATOM_BASIC_LEN, ATOM_wV_LEN, 
+					ATOM_wF_LEN, ATOM_FULL_LEN };
+  int  bond_line_len[ NR_OPT_BOND ] = { 0, BOND_BASIC_LEN, BOND_FULL_LEN };
+  int  angle_line_len[ NR_OPT_ANGLE ] = { 0, ANGLE_BASIC_LEN };
+
+  /* generate trajectory name */
+  sprintf( fname, "%s.trj", control->sim_name );
+
+  /* how should I write atoms? */
+  out_control->atom_line_len = atom_line_len[ out_control->atom_info ];
+  out_control->write_atoms = ( out_control->atom_line_len ? 1 : 0 );
+  /* bonds? */
+  out_control->bond_line_len = bond_line_len[ out_control->bond_info ];
+  out_control->write_bonds = ( out_control->bond_line_len ? 1 : 0 );
+  /* angles? */
+  out_control->angle_line_len = angle_line_len[ out_control->angle_info ];
+  out_control->write_angles = ( out_control->angle_line_len ? 1 : 0 );
+  
+  /* allocate line & buffer space */
+  out_control->line = (char*) calloc( MAX_TRJ_LINE_LEN + 1, sizeof(char) );
+  out_control->buffer_len = 0;
+  out_control->buffer = NULL;
+  
+  /* fprintf( stderr, "p%d: init_traj: atom_line_len = %d "		\
+     "bond_line_len = %d, angle_line_len = %d\n"			\
+     "max_line = %d, max_buffer_size = %d\n", 
+     system->my_rank, out_control->atom_line_len, 
+     out_control->bond_line_len, out_control->angle_line_len,
+     MAX_TRJ_LINE_LEN, MAX_TRJ_BUFFER_SIZE ); */
+  
+  /* write trajectory header and atom info, if applicable */
+#if defined(PURE_REAX)
+  if( out_control->traj_method == MPI_TRAJ ) {
+    /* attemp to delete the file to get rid of remnants of previous runs */
+    if( system->my_rank == MASTER_NODE ) {
+      MPI_File_delete( fname, MPI_INFO_NULL );
+    }
+      
+    /* open a fresh trajectory file */
+    if( MPI_File_open( mpi_data->world, fname, 
+		       MPI_MODE_CREATE | MPI_MODE_WRONLY, MPI_INFO_NULL, 
+		       &(out_control->trj) ) ) {
+      strcpy( msg, "init_traj: unable to open trajectory file" );
+      return FAILURE;
+    }
+    
+    /* build the mpi structs for trajectory */
+    /* header_line */
+    MPI_Type_contiguous( HEADER_LINE_LEN, MPI_CHAR, &(mpi_data->header_line) );
+    MPI_Type_commit( &(mpi_data->header_line) );
+    /* init_desc_line */
+    MPI_Type_contiguous( INIT_DESC_LEN, MPI_CHAR, &(mpi_data->init_desc_line) );
+    MPI_Type_commit( &(mpi_data->init_desc_line) );
+    /* atom */
+    MPI_Type_contiguous( out_control->atom_line_len, MPI_CHAR, 
+			 &(mpi_data->atom_line) );
+    MPI_Type_commit( &(mpi_data->atom_line) );
+    /* bonds */
+    MPI_Type_contiguous( out_control->bond_line_len, MPI_CHAR, 
+			 &(mpi_data->bond_line) );
+    MPI_Type_commit( &(mpi_data->bond_line) );
+    /* angles */
+    MPI_Type_contiguous( out_control->angle_line_len, MPI_CHAR, 
+			 &(mpi_data->angle_line) );
+    MPI_Type_commit( &(mpi_data->angle_line) );
+  }
+  else if( out_control->traj_method == REG_TRAJ) {
+    if( system->my_rank == MASTER_NODE )
+      out_control->strj = fopen( fname, "w" );
+  }
+  else {
+    strcpy( msg, "init_traj: unknown trajectory option" );   
+    return FAILURE;
+  }
+#elif defined(LAMMPS_REAX)
+  if( out_control->traj_method == REG_TRAJ) {
+    if( system->my_rank == MASTER_NODE )
+      out_control->strj = fopen( fname, "w" );
+  }
+  else {
+    strcpy( msg, "init_traj: unknown trajectory option" );   
+    return FAILURE;
+  }
+#endif
+
+
+#if defined(DEBUG_FOCUS)
+  fprintf( stderr, "p%d: initiated trajectory\n", system->my_rank );
+#endif
+  Write_Header( system, control, out_control, mpi_data );
+#if defined(DEBUG_FOCUS)
+  fprintf( stderr, "p%d: header written\n", system->my_rank );
+#endif
+  Write_Init_Desc( system, control, out_control, mpi_data );
+#if defined(DEBUG_FOCUS)
+  fprintf( stderr, "p%d: atom descriptions written\n", system->my_rank );
+#endif
+  
+  return SUCCESS;
+}
+
+
+int Write_Frame_Header( reax_system *system, control_params *control, 
+			simulation_data *data, output_controls *out_control, 
+			mpi_datatypes *mpi_data )
+{
+  int me, num_frm_hdr_lines, my_frm_hdr_lines, buffer_req;
+  MPI_Status status;
+
+  me = system->my_rank;
+  /* frame header lengths */
+  num_frm_hdr_lines = 22;
+  my_frm_hdr_lines = num_frm_hdr_lines * ( me == MASTER_NODE );
+  buffer_req = my_frm_hdr_lines * HEADER_LINE_LEN;
+  if( buffer_req > out_control->buffer_len * DANGER_ZONE )
+    Reallocate_Output_Buffer( out_control, buffer_req, mpi_data->world );  
+
+  /* only the master node writes into trajectory header */
+  if( me == MASTER_NODE ) {
+    /* clear the contents of line & buffer */
+    out_control->line[0] = 0;
+    out_control->buffer[0] = 0;
+
+    /* skip info */
+    sprintf( out_control->line, INT_LINE, "chars_to_skip_frame_header:", 
+	     (num_frm_hdr_lines - 1) * HEADER_LINE_LEN );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+
+    /* step & time */
+    sprintf( out_control->line, INT_LINE, "step:", data->step );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, REAL_LINE, "time_in_ps:", 
+	     data->step * control->dt );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    
+    /* box info */
+    sprintf( out_control->line, REAL_LINE, "volume:", system->big_box.V );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, REAL3_LINE, "box_dimensions:", 
+	     system->big_box.box_norms[0], 
+	     system->big_box.box_norms[1], 
+	     system->big_box.box_norms[2] );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, REAL3_LINE, 
+	     "coordinate_angles:", 90.0, 90.0, 90.0 );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    
+    /* system T and P */
+    sprintf( out_control->line, REAL_LINE, "temperature:", data->therm.T );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, REAL_LINE, "pressure:", 
+	     (control->ensemble==iNPT) ?  
+	     data->iso_bar.P : data->flex_bar.P_scalar );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    
+    /* energies */
+    sprintf( out_control->line, REAL_LINE, "total_energy:", 
+	     data->sys_en.e_tot );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, REAL_LINE, "total_kinetic:", 
+	     data->sys_en.e_kin );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, REAL_LINE, "total_potential:", 
+	     data->sys_en.e_pot );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, REAL_LINE, "bond_energy:", 
+	     data->sys_en.e_bond );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, REAL_LINE, "atom_energy:", 
+	     data->sys_en.e_ov + data->sys_en.e_un  );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, REAL_LINE, "lone_pair_energy:", 
+	     data->sys_en.e_lp  );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, REAL_LINE, "valence_angle_energy:", 
+	     data->sys_en.e_ang + data->sys_en.e_pen );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, REAL_LINE, "3-body_conjugation:", 
+	     data->sys_en.e_coa );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, REAL_LINE, "hydrogen_bond_energy:", 
+	     data->sys_en.e_hb );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, REAL_LINE, "torsion_angle_energy:", 
+	     data->sys_en.e_tor );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, REAL_LINE, "4-body_conjugation:", 
+	     data->sys_en.e_con );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, REAL_LINE, "vdWaals_energy:", 
+	     data->sys_en.e_vdW );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, REAL_LINE, "electrostatics_energy:", 
+	     data->sys_en.e_ele );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+    
+    sprintf( out_control->line, REAL_LINE, "polarization_energy:", 
+	     data->sys_en.e_pol );
+    strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN+1 );
+  }
+
+  /* dump out the buffer */
+#if defined(PURE_REAX)
+  if( out_control->traj_method == MPI_TRAJ ) {  
+    Set_My_Trajectory_View( out_control->trj, out_control->trj_offset, 
+			    mpi_data->header_line, mpi_data->world, 
+			    me, my_frm_hdr_lines, num_frm_hdr_lines );
+    
+    MPI_File_write_all(out_control->trj, out_control->buffer, my_frm_hdr_lines,
+		       mpi_data->header_line, &status);
+    out_control->trj_offset += (num_frm_hdr_lines) * HEADER_LINE_LEN;
+  }
+  else {
+    if( system->my_rank == MASTER_NODE )
+      fprintf( out_control->strj, "%s", out_control->buffer );
+  }
+#elif defined(LAMMPS_REAX)
+  if( system->my_rank == MASTER_NODE )
+    fprintf( out_control->strj, "%s", out_control->buffer );
+#endif
+
+  return SUCCESS;
+}
+
+
+
+int Write_Atoms( reax_system *system, control_params *control,
+		 output_controls *out_control, mpi_datatypes *mpi_data )
+{
+  int i, me, np, line_len, buffer_len, buffer_req, cnt;
+  MPI_Status  status;
+  reax_atom  *p_atom;
+
+  me = system->my_rank;
+  np = system->wsize;
+  line_len = out_control->atom_line_len;
+
+  Write_Skip_Line( out_control, mpi_data, me, 
+		   system->bigN*line_len, system->bigN );
+
+  if( out_control->traj_method == REG_TRAJ && me == MASTER_NODE )
+    buffer_req = system->bigN * line_len + 1;
+  else buffer_req = system->n * line_len + 1;
+
+  if( buffer_req > out_control->buffer_len * DANGER_ZONE )
+    Reallocate_Output_Buffer( out_control, buffer_req, mpi_data->world );
+
+  /* fill in buffer */
+  out_control->line[0] = 0;
+  out_control->buffer[0] = 0;
+  for( i = 0; i < system->n; ++i ) {
+    p_atom = &( system->my_atoms[i] );
+
+    switch( out_control->atom_info ) {
+    case OPT_ATOM_BASIC: 
+      sprintf( out_control->line, ATOM_BASIC, 
+	       p_atom->orig_id, p_atom->x[0], p_atom->x[1], p_atom->x[2], 
+	       p_atom->q );
+      break;
+    case OPT_ATOM_wF:
+      sprintf( out_control->line, ATOM_wF, 
+	       p_atom->orig_id, p_atom->x[0], p_atom->x[1], p_atom->x[2],
+	       p_atom->f[0], p_atom->f[1], p_atom->f[2], p_atom->q );
+      break;
+    case OPT_ATOM_wV:
+      sprintf( out_control->line, ATOM_wV, 
+	       p_atom->orig_id, p_atom->x[0], p_atom->x[1], p_atom->x[2],
+	       p_atom->v[0], p_atom->v[1], p_atom->v[2], p_atom->q );
+      break;
+    case OPT_ATOM_FULL:
+      sprintf( out_control->line, ATOM_FULL,
+	       p_atom->orig_id, p_atom->x[0], p_atom->x[1], p_atom->x[2],
+	       p_atom->v[0], p_atom->v[1], p_atom->v[2],
+	       p_atom->f[0], p_atom->f[1], p_atom->f[2], p_atom->q );
+      break;
+    default:
+      fprintf( stderr, 
+	       "write_traj_atoms: unknown atom trajectroy format!\n");
+      MPI_Abort( mpi_data->world, UNKNOWN_OPTION );
+    }
+
+    strncpy( out_control->buffer + i*line_len, out_control->line, line_len+1 );
+  }
+
+#if defined(PURE_REAX)
+  if( out_control->traj_method == MPI_TRAJ ) {
+    Set_My_Trajectory_View( out_control->trj, out_control->trj_offset, 
+			    mpi_data->atom_line, mpi_data->world, 
+			    me, system->n, system->bigN );  
+    MPI_File_write( out_control->trj, out_control->buffer, system->n, 
+		    mpi_data->atom_line, &status );
+    out_control->trj_offset += (system->bigN) * out_control->atom_line_len;
+  }
+  else{
+    if( me != MASTER_NODE )
+      MPI_Send( out_control->buffer, buffer_req-1, MPI_CHAR, MASTER_NODE, 
+		np*ATOM_LINES+me, mpi_data->world );
+    else{
+      buffer_len = system->n * line_len;
+      for( i = 0; i < np; ++i )
+	if( i != MASTER_NODE ) {
+	  MPI_Recv( out_control->buffer + buffer_len, buffer_req - buffer_len,
+		    MPI_CHAR, i, np*ATOM_LINES+i, mpi_data->world, &status );
+	  MPI_Get_count( &status, MPI_CHAR, &cnt );
+	  buffer_len += cnt;
+	}
+      out_control->buffer[buffer_len] = 0;
+      fprintf( out_control->strj, "%s", out_control->buffer );
+    }    
+  }
+#elif defined(LAMMPS_REAX)
+  if( me != MASTER_NODE )
+    MPI_Send( out_control->buffer, buffer_req-1, MPI_CHAR, MASTER_NODE, 
+	      np*ATOM_LINES+me, mpi_data->world );
+  else{
+    buffer_len = system->n * line_len;
+    for( i = 0; i < np; ++i )
+      if( i != MASTER_NODE ) {
+	MPI_Recv( out_control->buffer + buffer_len, buffer_req - buffer_len,
+		  MPI_CHAR, i, np*ATOM_LINES+i, mpi_data->world, &status );
+	MPI_Get_count( &status, MPI_CHAR, &cnt );
+	buffer_len += cnt;
+      }
+    out_control->buffer[buffer_len] = 0;
+    fprintf( out_control->strj, "%s", out_control->buffer );
+  }
+#endif
+  
+  return SUCCESS;
+}
+
+
+int Write_Bonds(reax_system *system, control_params *control, reax_list *bonds, 
+		output_controls *out_control, mpi_datatypes *mpi_data)
+{
+  int i, j, pj, me, np; 
+  int my_bonds, num_bonds;
+  int line_len, buffer_len, buffer_req, cnt;
+  MPI_Status  status;
+  bond_data  *bo_ij;
+
+  me = system->my_rank;
+  np = system->wsize;
+  line_len = out_control->bond_line_len;  
+
+  /* count the number of bonds I will write */
+  my_bonds = 0;
+  for( i=0; i < system->n; ++i )
+    for( pj = Start_Index(i, bonds); pj < End_Index(i, bonds); ++pj ) {
+      j = bonds->select.bond_list[pj].nbr;
+      if( system->my_atoms[i].orig_id <= system->my_atoms[j].orig_id && 
+	  bonds->select.bond_list[pj].bo_data.BO >= control->bg_cut )
+	++my_bonds;
+    }
+  /* allreduce - total number of bonds */
+  MPI_Allreduce( &my_bonds, &num_bonds, 1, MPI_INT, MPI_SUM, mpi_data->world );
+
+  Write_Skip_Line( out_control, mpi_data, me, num_bonds*line_len, num_bonds );
+
+  if( out_control->traj_method == REG_TRAJ && me == MASTER_NODE )
+    buffer_req = num_bonds * line_len + 1;
+  else buffer_req = my_bonds * line_len + 1;
+
+  if( buffer_req > out_control->buffer_len * DANGER_ZONE )
+    Reallocate_Output_Buffer( out_control, buffer_req, mpi_data->world );
+  
+  /* fill in the buffer */
+  my_bonds = 0;
+  out_control->line[0] = 0;
+  out_control->buffer[0] = 0;
+  for( i=0; i < system->n; ++i )
+    for( pj = Start_Index(i, bonds); pj < End_Index(i, bonds); ++pj ) {
+      bo_ij = &( bonds->select.bond_list[pj] );
+      j = bo_ij->nbr;
+	
+      if( system->my_atoms[i].orig_id <= system->my_atoms[j].orig_id && 
+	  bo_ij->bo_data.BO >= control->bg_cut ) {
+	switch( out_control->bond_info ) {
+	case OPT_BOND_BASIC:
+	  sprintf( out_control->line, BOND_BASIC, 
+		   system->my_atoms[i].orig_id, system->my_atoms[j].orig_id, 
+		   bo_ij->d, bo_ij->bo_data.BO );
+	  break;
+	case OPT_BOND_FULL:
+	  sprintf( out_control->line, BOND_FULL,
+		   system->my_atoms[i].orig_id, system->my_atoms[j].orig_id, 
+		   bo_ij->d, bo_ij->bo_data.BO, bo_ij->bo_data.BO_s, 
+		   bo_ij->bo_data.BO_pi, bo_ij->bo_data.BO_pi2 );
+	  break;
+	default:
+	  fprintf(stderr, "write_traj_bonds: FATAL! invalid bond_info option");
+	  MPI_Abort( mpi_data->world, UNKNOWN_OPTION );
+	}
+	    
+	strncpy( out_control->buffer + my_bonds*line_len, 
+		 out_control->line, line_len+1 );
+	++my_bonds;
+      }
+    }
+
+#if defined(PURE_REAX)
+  if( out_control->traj_method == MPI_TRAJ ) {
+    Set_My_Trajectory_View( out_control->trj, out_control->trj_offset, 
+			    mpi_data->bond_line, mpi_data->world, 
+			    me, my_bonds, num_bonds );
+    MPI_File_write( out_control->trj, out_control->buffer, my_bonds, 
+		    mpi_data->bond_line, &status );
+    out_control->trj_offset += num_bonds * line_len;
+  }
+  else{
+    if( me != MASTER_NODE )
+      MPI_Send( out_control->buffer, buffer_req-1, MPI_CHAR, MASTER_NODE, 
+		np*BOND_LINES+me, mpi_data->world );
+    else{
+      buffer_len = my_bonds * line_len;
+      for( i = 0; i < np; ++i )
+	if( i != MASTER_NODE ) {
+	  MPI_Recv( out_control->buffer + buffer_len, buffer_req - buffer_len,
+		    MPI_CHAR, i, np*BOND_LINES+i, mpi_data->world, &status );
+	  MPI_Get_count( &status, MPI_CHAR, &cnt );
+	  buffer_len += cnt;
+	}
+      out_control->buffer[buffer_len] = 0;
+      fprintf( out_control->strj, "%s", out_control->buffer );
+    }    
+  }
+#elif defined(LAMMPS_REAX)
+  if( me != MASTER_NODE )
+    MPI_Send( out_control->buffer, buffer_req-1, MPI_CHAR, MASTER_NODE, 
+	      np*BOND_LINES+me, mpi_data->world );
+  else{
+    buffer_len = my_bonds * line_len;
+    for( i = 0; i < np; ++i )
+      if( i != MASTER_NODE ) {
+	MPI_Recv( out_control->buffer + buffer_len, buffer_req - buffer_len,
+		  MPI_CHAR, i, np*BOND_LINES+i, mpi_data->world, &status );
+	MPI_Get_count( &status, MPI_CHAR, &cnt );
+	buffer_len += cnt;
+      }
+    out_control->buffer[buffer_len] = 0;
+    fprintf( out_control->strj, "%s", out_control->buffer );
+  } 
+#endif
+  
+  return SUCCESS;
+}
+
+
+int Write_Angles( reax_system *system, control_params *control, 
+		  reax_list *bonds, reax_list *thb_intrs, 
+		  output_controls *out_control, mpi_datatypes *mpi_data )
+{
+  int i, j, k, pi, pk, me, np;
+  int my_angles, num_angles;
+  int line_len, buffer_len, buffer_req, cnt;
+  bond_data  *bo_ij, *bo_jk;  
+  three_body_interaction_data *angle_ijk;
+  MPI_Status  status;
+  
+  me = system->my_rank;
+  np = system->wsize;
+  line_len = out_control->angle_line_len;  
+
+  /* count the number of valence angles I will output */
+  my_angles = 0;
+  for( j = 0; j < system->n; ++j )
+    for( pi = Start_Index(j, bonds); pi < End_Index(j, bonds); ++pi ) {
+      bo_ij = &(bonds->select.bond_list[pi]);
+      i     = bo_ij->nbr;
+      
+      if( bo_ij->bo_data.BO >= control->bg_cut ) // physical j&i bond
+	for( pk = Start_Index( pi, thb_intrs ); 
+	     pk < End_Index( pi, thb_intrs ); ++pk ) {
+	  angle_ijk = &(thb_intrs->select.three_body_list[pk]);
+	  k       = angle_ijk->thb;
+	  bo_jk   = &(bonds->select.bond_list[ angle_ijk->pthb ]); 
+
+	  if( system->my_atoms[i].orig_id < system->my_atoms[k].orig_id && 
+	      bo_jk->bo_data.BO >= control->bg_cut ) // physical j&k bond
+	    ++my_angles;   	
+	}
+    }
+  /* total number of valences */
+  MPI_Allreduce(&my_angles, &num_angles, 1, MPI_INT, MPI_SUM,  mpi_data->world);
+
+  Write_Skip_Line( out_control, mpi_data, me, num_angles*line_len, num_angles );
+
+  if( out_control->traj_method == REG_TRAJ && me == MASTER_NODE )
+    buffer_req = num_angles * line_len + 1;
+  else buffer_req = my_angles * line_len + 1;
+
+  if( buffer_req > out_control->buffer_len * DANGER_ZONE )
+    Reallocate_Output_Buffer( out_control, buffer_req, mpi_data->world );
+
+  /* fill in the buffer */
+  my_angles = 0;
+  out_control->line[0] = 0;
+  out_control->buffer[0] = 0;
+  for( j = 0; j < system->n; ++j )
+    for( pi = Start_Index(j, bonds); pi < End_Index(j, bonds); ++pi ) {
+      bo_ij = &(bonds->select.bond_list[pi]);
+      i     = bo_ij->nbr;
+      
+      if( bo_ij->bo_data.BO >= control->bg_cut ) // physical j&i bond
+	for( pk = Start_Index( pi, thb_intrs ); 
+	     pk < End_Index( pi, thb_intrs ); ++pk ) {
+	  angle_ijk = &(thb_intrs->select.three_body_list[pk]);
+	  k       = angle_ijk->thb;
+	  bo_jk   = &(bonds->select.bond_list[ angle_ijk->pthb ]); 
+	  
+	  if( system->my_atoms[i].orig_id < system->my_atoms[k].orig_id && 
+	      bo_jk->bo_data.BO >= control->bg_cut ) { // physical j&k bond
+	    sprintf( out_control->line, ANGLE_BASIC,
+		     system->my_atoms[i].orig_id, system->my_atoms[j].orig_id, 
+		     system->my_atoms[k].orig_id, RAD2DEG( angle_ijk->theta ) );
+	    
+	    strncpy( out_control->buffer + my_angles*line_len, 
+		     out_control->line, line_len+1 );
+	    ++my_angles;
+	  }
+	}
+    }
+
+#if defined(PURE_REAX)
+  if( out_control->traj_method == MPI_TRAJ ){
+    Set_My_Trajectory_View( out_control->trj, out_control->trj_offset, 
+			    mpi_data->angle_line, mpi_data->world, 
+			    me, my_angles, num_angles );  
+    MPI_File_write( out_control->trj, out_control->buffer, my_angles, 
+		    mpi_data->angle_line, &status );
+    out_control->trj_offset += num_angles * line_len;
+  }
+  else{
+    if( me != MASTER_NODE )
+      MPI_Send( out_control->buffer, buffer_req-1, MPI_CHAR, MASTER_NODE, 
+		np*ANGLE_LINES+me, mpi_data->world );
+    else{
+      buffer_len = my_angles * line_len;
+      for( i = 0; i < np; ++i )
+	if( i != MASTER_NODE ) {
+	  MPI_Recv( out_control->buffer + buffer_len, buffer_req - buffer_len,
+		    MPI_CHAR, i, np*ANGLE_LINES+i, mpi_data->world, &status );
+	  MPI_Get_count( &status, MPI_CHAR, &cnt );
+	  buffer_len += cnt;
+	}
+      out_control->buffer[buffer_len] = 0;
+      fprintf( out_control->strj, "%s", out_control->buffer );
+    }
+  }
+#elif defined(LAMMPS_REAX)
+  if( me != MASTER_NODE )
+    MPI_Send( out_control->buffer, buffer_req-1, MPI_CHAR, MASTER_NODE, 
+	      np*ANGLE_LINES+me, mpi_data->world );
+  else{
+    buffer_len = my_angles * line_len;
+    for( i = 0; i < np; ++i )
+      if( i != MASTER_NODE ) {
+	MPI_Recv( out_control->buffer + buffer_len, buffer_req - buffer_len,
+		  MPI_CHAR, i, np*ANGLE_LINES+i, mpi_data->world, &status );
+	MPI_Get_count( &status, MPI_CHAR, &cnt );
+	buffer_len += cnt;
+      }
+    out_control->buffer[buffer_len] = 0;
+    fprintf( out_control->strj, "%s", out_control->buffer );
+  }
+#endif
+  
+  return SUCCESS;
+}
+
+
+int Append_Frame( reax_system *system, control_params *control, 
+		  simulation_data *data, reax_list **lists, 
+		  output_controls *out_control, mpi_datatypes *mpi_data )
+{
+#if defined(DEBUG_FOCUS)
+  fprintf( stderr, "p%d: appending frame %d\n", system->my_rank, data->step );
+#endif
+  Write_Frame_Header( system, control, data, out_control, mpi_data );
+
+  if( out_control->write_atoms )
+    Write_Atoms( system, control, out_control, mpi_data );
+
+  if( out_control->write_bonds )
+    Write_Bonds( system, control, (*lists + BONDS), out_control, mpi_data );
+
+  if( out_control->write_angles )
+    Write_Angles( system, control, (*lists + BONDS), (*lists + THREE_BODIES), 
+		  out_control, mpi_data );
+#if defined(DEBUG_FOCUS)
+  fprintf( stderr, "p%d: appended frame %d\n", system->my_rank, data->step );
+#endif
+
+  return SUCCESS;
+}
+
+
+int End_Traj( int my_rank, output_controls *out_control )
+{
+#if defined(PURE_REAX)
+  if( out_control->traj_method == MPI_TRAJ )
+    MPI_File_close( &(out_control->trj) );
+  else if( my_rank == MASTER_NODE )
+    fclose( out_control->strj );
+#elif defined(LAMMPS_REAX)
+  if( my_rank == MASTER_NODE )
+    fclose( out_control->strj );
+#endif  
+
+  free( out_control->buffer );
+  free( out_control->line );
+  
+  return SUCCESS;
+}
diff --git a/src/USER-REAXC/reaxc_traj.h b/src/USER-REAXC/reaxc_traj.h
new file mode 100644
index 0000000000..99e0c5223a
--- /dev/null
+++ b/src/USER-REAXC/reaxc_traj.h
@@ -0,0 +1,77 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#ifndef __TRAJ_H__
+#define __TRAJ_H__
+
+#include "reaxc_types.h"
+
+#define MAX_TRJ_LINE_LEN     120
+#define MAX_TRJ_BUFFER_SIZE  (MAX_TRJ_LINE_LEN * 100)
+
+#define NUM_HEADER_LINES 37
+#define HEADER_LINE_LEN 62
+#define STR_LINE  "%-37s%-24s\n"
+#define INT_LINE  "%-37s%-24d\n"
+#define INT2_LINE  "%-36s%-12d,%-12d\n"
+#define REAL_LINE "%-37s%-24.3f\n"
+#define SCI_LINE  "%-37s%-24g\n"
+#define REAL3_LINE "%-32s%9.3f,%9.3f,%9.3f\n"
+
+#define INIT_DESC "%9d%3d%9s%10.3f\n" //AtomID - AtomType, AtomName, AtomMass
+#define INIT_DESC_LEN 32
+
+#define SIZE_INFO_LINE2 "%-10d%-10d\n"
+#define SIZE_INFO_LEN2 21
+
+#define SIZE_INFO_LINE3 "%-10d%-10d%-10d\n"
+#define SIZE_INFO_LEN3 31
+
+#define ATOM_BASIC "%9d%10.3f%10.3f%10.3f%10.3f\n" //AtomID AtomType (X Y Z) Charge
+#define ATOM_BASIC_LEN 50
+#define ATOM_wV    "%9d%10.3f%10.3f%10.3f%10.3f%10.3f%10.3f%10.3f\n" //AtomID (X Y Z) (Vx Vy Vz) Charge
+#define ATOM_wV_LEN 80
+#define ATOM_wF    "%9d%10.3f%10.3f%10.3f%10.3f%10.3f%10.3f%10.3f\n" //AtomID (X Y Z) (Fx Fy Fz) Charge
+#define ATOM_wF_LEN 80
+#define ATOM_FULL  "%9d%10.3f%10.3f%10.3f%10.3f%10.3f%10.3f%10.3f%10.3f%10.3f%10.3f\n" //AtomID (X Y Z) (Vx Vy Vz) (Fx Fy Fz) Charge
+#define ATOM_FULL_LEN 110
+
+#define BOND_BASIC "%9d%9d%10.3f%10.3f\n" // Atom1 Atom2 Dist Total_BO
+#define BOND_BASIC_LEN 39
+#define BOND_FULL  "%9d%9d%10.3f%10.3f%10.3f%10.3f%10.3f\n" // Atom1 Atom2 Dist Total_BO BOs BOpi BOpi2
+#define BOND_FULL_LEN 69
+
+#define ANGLE_BASIC "%9d%9d%9d%10.3f\n" // Atom1 Atom2 Atom3 Theta
+#define ANGLE_BASIC_LEN 38
+
+enum ATOM_LINE_OPTS  { OPT_NOATOM = 0, OPT_ATOM_BASIC = 4, OPT_ATOM_wF = 5, OPT_ATOM_wV = 6, OPT_ATOM_FULL = 7, NR_OPT_ATOM = 8 };
+enum BOND_LINE_OPTS  { OPT_NOBOND, OPT_BOND_BASIC, OPT_BOND_FULL, NR_OPT_BOND };
+enum ANGLE_LINE_OPTS { OPT_NOANGLE, OPT_ANGLE_BASIC, NR_OPT_ANGLE };
+
+
+int  Init_Traj( reax_system*, control_params*, output_controls*, 
+		mpi_datatypes*, char* );
+int  End_Traj( int, output_controls* );
+
+int  Append_Frame( reax_system*, control_params*, simulation_data*, 
+		   reax_list**, output_controls*, mpi_datatypes* );
+
+#endif
diff --git a/src/USER-REAXC/reaxc_types.h b/src/USER-REAXC/reaxc_types.h
new file mode 100644
index 0000000000..7c4dfc3c5b
--- /dev/null
+++ b/src/USER-REAXC/reaxc_types.h
@@ -0,0 +1,977 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#ifndef __REAX_TYPES_H_
+#define __REAX_TYPES_H_
+
+#include "ctype.h"
+#include "math.h"
+#include "mpi.h"
+#include "stdio.h"
+#include "stdlib.h"
+#include "string.h"
+#include "sys/time.h"
+#include "time.h"
+#include "zlib.h"
+
+/************* SOME DEFS - crucial for reax_types.h *********/
+
+//#define PURE_REAX
+#define LAMMPS_REAX
+
+//#define DEBUG
+//#define DEBUG_FOCUS
+//#define TEST_ENERGY
+//#define TEST_FORCES
+//#define CG_PERFORMANCE
+#define LOG_PERFORMANCE
+#define STANDARD_BOUNDARIES
+//#define OLD_BOUNDARIES
+//#define MIDPOINT_BOUNDARIES
+
+#define REAX_MAX_STR            1024
+#define REAX_MAX_NBRS           6    
+#define REAX_MAX_3BODY_PARAM    5
+#define REAX_MAX_4BODY_PARAM    5
+#define REAX_MAX_ATOM_TYPES     25
+#define REAX_MAX_MOLECULE_SIZE  20
+
+/********************** TYPE DEFINITIONS ********************/
+typedef int  ivec[3];
+typedef double real;
+typedef real rvec[3];
+typedef real rtensor[3][3];
+typedef real rvec2[2];
+typedef real rvec4[4];
+
+
+typedef struct {
+  int step, bigN;
+  real T, xi, v_xi, v_xi_old, G_xi;
+  rtensor box;
+} restart_header;
+
+typedef struct {
+  int orig_id, type;
+  char name[8];
+  rvec x, v;
+} restart_atom;
+
+typedef struct
+{
+  int  orig_id;
+  int  imprt_id;
+  int  type;
+  int  num_bonds;
+  int  num_hbonds;
+  //int  pad;  // pad to 8-byte address boundary   
+  char name[8];
+  rvec x;     // position 
+  rvec v;     // velocity 
+  rvec f_old; // old force 
+  rvec4 s, t;  // for calculating q 
+} mpi_atom;
+
+
+typedef struct
+{
+  int  orig_id;
+  int  imprt_id;
+  int  type;
+  int  num_bonds;
+  int  num_hbonds;  
+  //int  pad;
+  rvec x;     // position 
+} boundary_atom;
+
+
+typedef struct
+{
+  //int  ncells;
+  //int *cnt_by_gcell;
+
+  int  cnt;
+  //int *block;
+  int *index;
+  //MPI_Datatype out_dtype;
+  void *out_atoms;
+} mpi_out_data;
+
+
+typedef struct
+{
+  MPI_Comm     world;
+  MPI_Comm     comm_mesh3D;
+
+  MPI_Datatype sys_info;
+  MPI_Datatype mpi_atom_type;
+  MPI_Datatype boundary_atom_type;
+  MPI_Datatype mpi_rvec, mpi_rvec2;
+  MPI_Datatype restart_atom_type;
+
+  MPI_Datatype header_line;
+  MPI_Datatype header_view;
+  MPI_Datatype init_desc_line;
+  MPI_Datatype init_desc_view;
+  MPI_Datatype atom_line;
+  MPI_Datatype atom_view;
+  MPI_Datatype bond_line;
+  MPI_Datatype bond_view;
+  MPI_Datatype angle_line;
+  MPI_Datatype angle_view;
+
+  //MPI_Request  send_req1[REAX_MAX_NBRS];
+  //MPI_Request  send_req2[REAX_MAX_NBRS];
+  //MPI_Status   send_stat1[REAX_MAX_NBRS];
+  //MPI_Status   send_stat2[REAX_MAX_NBRS];
+  //MPI_Status   recv_stat1[REAX_MAX_NBRS];
+  //MPI_Status   recv_stat2[REAX_MAX_NBRS];
+
+  mpi_out_data out_buffers[REAX_MAX_NBRS];
+  void *in1_buffer;
+  void *in2_buffer;
+} mpi_datatypes;
+
+
+/* Global params mapping */
+/* 
+l[0]  = p_boc1
+l[1]  = p_boc2
+l[2]  = p_coa2
+l[3]  = N/A
+l[4]  = N/A
+l[5]  = N/A
+l[6]  = p_ovun6
+l[7]  = N/A
+l[8]  = p_ovun7
+l[9]  = p_ovun8
+l[10] = N/A
+l[11] = swa
+l[12] = swb
+l[13] = N/A
+l[14] = p_val6
+l[15] = p_lp1
+l[16] = p_val9
+l[17] = p_val10
+l[18] = N/A
+l[19] = p_pen2
+l[20] = p_pen3
+l[21] = p_pen4
+l[22] = N/A
+l[23] = p_tor2
+l[24] = p_tor3
+l[25] = p_tor4
+l[26] = N/A
+l[27] = p_cot2
+l[28] = p_vdW1
+l[29] = v_par30
+l[30] = p_coa4
+l[31] = p_ovun4
+l[32] = p_ovun3
+l[33] = p_val8
+l[34] = N/A
+l[35] = N/A
+l[36] = N/A
+l[37] = version number
+l[38] = p_coa3
+*/
+
+typedef struct
+{      
+  int n_global;
+  real* l;
+  int vdw_type;
+} global_parameters;
+
+
+
+typedef struct
+{
+  /* Line one in field file */
+  char name[15]; // Two character atom name
+
+  real r_s;
+  real valency;  // Valency of the atom
+  real mass;     // Mass of atom
+  real r_vdw;
+  real epsilon;
+  real gamma;
+  real r_pi;
+  real valency_e;
+  real nlp_opt;
+  
+  /* Line two in field file */
+  real alpha;
+  real gamma_w;
+  real valency_boc;
+  real p_ovun5;
+  real chi;
+  real eta;
+  int  p_hbond; // 1 for H, 2 for hbonding atoms (O,S,P,N), 0 for others
+
+  /* Line three in field file */
+  real r_pi_pi;
+  real p_lp2;
+  real b_o_131;
+  real b_o_132;
+  real b_o_133;
+  
+  /* Line four in the field file */
+  real p_ovun2;
+  real p_val3;
+  real valency_val;
+  real p_val5;
+  real rcore2;
+  real ecore2;
+  real acore2;
+} single_body_parameters;
+
+
+
+/* Two Body Parameters */
+typedef struct {
+  /* Bond Order parameters */
+  real p_bo1,p_bo2,p_bo3,p_bo4,p_bo5,p_bo6;
+  real r_s, r_p, r_pp;  // r_o distances in BO formula
+  real p_boc3, p_boc4, p_boc5;
+
+  /* Bond Energy parameters */
+  real p_be1, p_be2;
+  real De_s, De_p, De_pp;
+
+  /* Over/Under coordination parameters */
+  real p_ovun1;
+
+  /* Van der Waal interaction parameters */
+  real D;
+  real alpha;
+  real r_vdW;
+  real gamma_w;
+  real rcore, ecore, acore;
+
+  /* electrostatic parameters */
+  real gamma; // note: this parameter is gamma^-3 and not gamma.
+
+  real v13cor, ovc;
+} two_body_parameters;
+
+
+
+/* 3-body parameters */
+typedef struct {
+  /* valence angle */
+  real theta_00;
+  real p_val1, p_val2, p_val4, p_val7;
+
+  /* penalty */
+  real p_pen1;
+
+  /* 3-body conjugation */
+  real p_coa1;
+} three_body_parameters;
+
+
+typedef struct{
+  int cnt;
+  three_body_parameters prm[REAX_MAX_3BODY_PARAM];
+} three_body_header;
+
+
+
+/* hydrogen-bond parameters */
+typedef struct{
+  real r0_hb, p_hb1, p_hb2, p_hb3;
+} hbond_parameters;
+
+
+
+/* 4-body parameters */
+typedef struct {
+  real V1, V2, V3;
+
+  /* torsion angle */
+  real p_tor1;
+
+  /* 4-body conjugation */
+  real p_cot1;
+} four_body_parameters;
+
+
+typedef struct
+{
+  int cnt;
+  four_body_parameters prm[REAX_MAX_4BODY_PARAM];
+} four_body_header;
+
+
+typedef struct
+{
+  int num_atom_types;
+  global_parameters gp;
+  single_body_parameters *sbp;
+  two_body_parameters **tbp;
+  three_body_header ***thbp;
+  hbond_parameters ***hbp;
+  four_body_header ****fbp;
+} reax_interaction;
+
+
+
+typedef struct
+{
+  int  orig_id;
+  int  imprt_id;
+  int  type;
+  char name[8];
+
+  rvec x; // position 
+  rvec v; // velocity 
+  rvec f; // force    
+  rvec f_old;
+
+  real q; // charge   
+  rvec4 s; // they take part in 
+  rvec4 t; // computing q 
+
+  int Hindex;
+  int num_bonds;
+  int num_hbonds;
+  int renumber;
+} reax_atom;
+
+
+
+typedef struct
+{
+  real V;
+  rvec min, max, box_norms;
+  
+  rtensor box, box_inv;
+  rtensor trans, trans_inv;
+  rtensor g;
+} simulation_box;
+
+
+
+struct grid_cell
+{
+  real cutoff;
+  rvec min, max;
+  ivec rel_box;
+
+  int  mark;
+  int  type;
+  int  str;
+  int  end;
+  int  top;
+  int* atoms;
+  struct grid_cell** nbrs;
+  ivec* nbrs_x;
+  rvec* nbrs_cp;
+};
+  
+typedef struct grid_cell grid_cell;
+
+
+typedef struct
+{
+  int  total, max_atoms, max_nbrs;
+  ivec ncells;
+  rvec cell_len;
+  rvec inv_len; 
+
+  ivec bond_span;
+  ivec nonb_span;
+  ivec vlist_span;
+
+  ivec native_cells;
+  ivec native_str;
+  ivec native_end;
+
+  real ghost_cut;
+  ivec ghost_span;
+  ivec ghost_nonb_span;
+  ivec ghost_hbond_span;
+  ivec ghost_bond_span;
+
+  grid_cell*** cells;
+  ivec *order;
+} grid;
+
+
+typedef struct
+{
+  int  rank;
+  int  est_send, est_recv;
+  int  atoms_str, atoms_cnt;
+  ivec rltv, prdc;
+  rvec bndry_min, bndry_max;
+
+  int  send_type;
+  int  recv_type;
+  ivec str_send;
+  ivec end_send;
+  ivec str_recv;
+  ivec end_recv;
+} neighbor_proc;
+
+
+
+typedef struct
+{
+  int N;
+  int exc_gcells;
+  int exc_atoms;
+} bound_estimate;
+
+
+
+typedef struct
+{
+  real ghost_nonb;
+  real ghost_hbond;
+  real ghost_bond;
+  real ghost_cutoff;
+} boundary_cutoff;
+
+
+
+typedef struct
+{
+  reax_interaction reax_param;
+
+  int              n, N, bigN, numH;
+  int              local_cap, total_cap, gcell_cap, Hcap;
+  int              est_recv, est_trans, max_recved;
+  int              wsize, my_rank, num_nbrs;
+  ivec             my_coords;
+  neighbor_proc    my_nbrs[REAX_MAX_NBRS];
+  int             *global_offset;
+  simulation_box   big_box, my_box, my_ext_box;
+  grid             my_grid;
+  boundary_cutoff  bndry_cuts;
+
+  reax_atom       *my_atoms;
+} reax_system;
+
+
+
+/* system control parameters */
+typedef struct
+{
+  char sim_name[REAX_MAX_STR];
+  int  nprocs;
+  ivec procs_by_dim;
+  /* ensemble values:
+     0 : NVE
+     1 : bNVT (Berendsen) 
+     2 : nhNVT (Nose-Hoover)
+     3 : sNPT (Parrinello-Rehman-Nose-Hoover) semiisotropic
+     4 : iNPT (Parrinello-Rehman-Nose-Hoover) isotropic 
+     5 : NPT  (Parrinello-Rehman-Nose-Hoover) Anisotropic*/
+  int  ensemble;
+  int  nsteps;
+  real dt;
+  int  geo_format;
+  int  restart;
+
+  int  restrict_bonds;
+  int  remove_CoM_vel;
+  int  random_vel;
+  int  reposition_atoms;
+  
+  int  reneighbor;
+  real vlist_cut;
+  real bond_cut;
+  real nonb_cut, nonb_low;
+  real hbond_cut;
+  real user_ghost_cut;
+
+  real bg_cut;
+  real bo_cut;
+  real thb_cut;
+
+  int tabulate;
+
+  int qeq_freq;
+  real q_err;
+  int refactor;
+  real droptol;  
+
+  real T_init, T_final, T;
+  real Tau_T;
+  int  T_mode;
+  real T_rate, T_freq;
+  
+  int  virial;  
+  rvec P, Tau_P, Tau_PT;
+  int  press_mode;
+  real compressibility;
+
+  int  molecular_analysis;
+  int  num_ignored;
+  int  ignore[REAX_MAX_ATOM_TYPES];
+
+  int  dipole_anal;
+  int  freq_dipole_anal;
+  int  diffusion_coef;
+  int  freq_diffusion_coef;
+  int  restrict_type;
+} control_params;
+
+
+typedef struct
+{
+  real T;
+  real xi;
+  real v_xi;
+  real v_xi_old;
+  real G_xi;
+
+} thermostat;
+
+
+typedef struct
+{
+  real P;
+  real eps;
+  real v_eps;
+  real v_eps_old;
+  real a_eps;
+
+} isotropic_barostat;
+
+
+typedef struct
+{
+  rtensor P;
+  real P_scalar;
+  
+  real eps;
+  real v_eps;
+  real v_eps_old;
+  real a_eps;
+
+  rtensor h0;
+  rtensor v_g0;
+  rtensor v_g0_old;
+  rtensor a_g0;
+
+} flexible_barostat;
+
+
+typedef struct
+{
+  real start;
+  real end;
+  real elapsed;
+
+  real total;
+  real comm;
+  real nbrs;
+  real init_forces;
+  real bonded;
+  real nonb;
+  real qEq;
+  int  s_matvecs;
+  int  t_matvecs;
+} reax_timing;
+
+
+typedef struct
+{
+  real e_tot;
+  real e_kin;                      // Total kinetic energy 
+  real e_pot;
+
+  real e_bond;                     // Total bond energy 
+  real e_ov;                       // Total over coordination 
+  real e_un;                       // Total under coordination energy 
+  real e_lp;                       // Total under coordination energy 
+  real e_ang;                      // Total valance angle energy 
+  real e_pen;                      // Total penalty energy 
+  real e_coa;                      // Total three body conjgation energy 
+  real e_hb;                       // Total Hydrogen bond energy 
+  real e_tor;                      // Total torsional energy 
+  real e_con;                      // Total four body conjugation energy  
+  real e_vdW;                      // Total van der Waals energy 
+  real e_ele;                      // Total electrostatics energy 
+  real e_pol;                      // Polarization energy 
+} energy_data;
+
+typedef struct
+{
+  int  step;
+  int  prev_steps;
+  real time;
+
+  real M;			   // Total Mass 
+  real inv_M;                      // 1 / Total Mass 
+
+  rvec xcm;                        // Center of mass 
+  rvec vcm;                        // Center of mass velocity 
+  rvec fcm;                        // Center of mass force 
+  rvec amcm;                       // Angular momentum of CoM 
+  rvec avcm;                       // Angular velocity of CoM 
+  real etran_cm;                   // Translational kinetic energy of CoM 
+  real erot_cm;                    // Rotational kinetic energy of CoM 
+
+  rtensor kinetic;                 // Kinetic energy tensor 
+  rtensor virial;                  // Hydrodynamic virial 
+
+  energy_data my_en;
+  energy_data sys_en;
+
+  real               N_f;          //Number of degrees of freedom 
+  rvec               t_scale;
+  rtensor            p_scale;
+  thermostat         therm;        // Used in Nose_Hoover method 
+  isotropic_barostat iso_bar;
+  flexible_barostat  flex_bar;
+  real               inv_W;
+
+  real kin_press;
+  rvec int_press;
+  rvec my_ext_press;
+  rvec ext_press;
+  rvec tot_press;
+
+  reax_timing timing;  
+} simulation_data;
+
+
+typedef struct{
+  int thb;
+  int pthb; // pointer to the third body on the central atom's nbrlist 
+  real theta, cos_theta;
+  rvec dcos_di, dcos_dj, dcos_dk;
+} three_body_interaction_data;
+
+
+typedef struct {
+  int nbr;
+  ivec rel_box;
+  real d;
+  rvec dvec;
+} far_neighbor_data;
+
+
+typedef struct {
+  int nbr;
+  int scl;
+  far_neighbor_data *ptr;
+} hbond_data;
+
+
+typedef struct{
+  int wrt;
+  rvec dVal;
+} dDelta_data;
+
+
+typedef struct{
+  int wrt;
+  rvec dBO, dBOpi, dBOpi2;
+} dbond_data;
+
+typedef struct{
+  real BO, BO_s, BO_pi, BO_pi2;
+  real Cdbo, Cdbopi, Cdbopi2;
+  real C1dbo, C2dbo, C3dbo;
+  real C1dbopi, C2dbopi, C3dbopi, C4dbopi;
+  real C1dbopi2, C2dbopi2, C3dbopi2, C4dbopi2;
+  rvec dBOp, dln_BOp_s, dln_BOp_pi, dln_BOp_pi2;
+} bond_order_data;
+
+typedef struct {
+  int nbr;
+  int sym_index;
+  int dbond_index;
+  ivec rel_box;
+  //  rvec ext_factor;
+  real d;
+  rvec dvec;
+  bond_order_data bo_data;
+} bond_data;
+
+
+typedef struct {
+  int j;
+  real val;
+} sparse_matrix_entry;
+
+typedef struct {
+  int cap, n, m;
+  int *start, *end;
+  sparse_matrix_entry *entries;
+} sparse_matrix;
+
+
+typedef struct { 
+  int num_far;
+  int H, Htop;
+  int hbonds, num_hbonds;
+  int bonds, num_bonds;
+  int num_3body;
+  int gcell_atoms;
+} reallocate_data;
+
+
+typedef struct
+{
+  int allocated;
+
+  /* communication storage */
+  real *tmp_dbl[REAX_MAX_NBRS];
+  rvec *tmp_rvec[REAX_MAX_NBRS];
+  rvec2 *tmp_rvec2[REAX_MAX_NBRS];
+  int  *within_bond_box;
+
+  /* bond order related storage */
+  real *total_bond_order;
+  real *Deltap, *Deltap_boc;
+  real *Delta, *Delta_lp, *Delta_lp_temp, *Delta_e, *Delta_boc;
+  real *dDelta_lp, *dDelta_lp_temp;
+  real *nlp, *nlp_temp, *Clp, *vlpex;
+  rvec *dDeltap_self;
+  int *bond_mark, *done_after;
+
+  /* QEq storage */
+  sparse_matrix *H, *L, *U;
+  real *Hdia_inv, *b_s, *b_t, *b_prc, *b_prm, *s, *t;
+  real *droptol;
+  rvec2 *b, *x;
+  
+  /* GMRES storage */
+  real *y, *z, *g;
+  real *hc, *hs;
+  real **h, **v;
+  /* CG storage */
+  real *r, *d, *q, *p;
+  rvec2 *r2, *d2, *q2, *p2;
+  /* Taper */
+  real Tap[8]; //Tap7, Tap6, Tap5, Tap4, Tap3, Tap2, Tap1, Tap0;
+
+  /* storage for analysis */
+  int  *mark, *old_mark;
+  rvec *x_old;
+  
+  /* storage space for bond restrictions */
+  int  *restricted;
+  int **restricted_list;  
+
+  /* integrator */
+  rvec *v_const;
+
+  /* force calculations */
+  real *CdDelta;  // coefficient of dDelta 
+  rvec *f;
+#ifdef TEST_FORCES
+  rvec *f_ele;
+  rvec *f_vdw;
+  rvec *f_bo;
+  rvec *f_be;
+  rvec *f_lp;
+  rvec *f_ov;
+  rvec *f_un;
+  rvec *f_ang;
+  rvec *f_coa;
+  rvec *f_pen;
+  rvec *f_hb;
+  rvec *f_tor;
+  rvec *f_con;
+  rvec *f_tot;
+  rvec *dDelta;   // calculated on the fly in bond_orders.c together with bo' 
+
+  int  *rcounts;
+  int  *displs;
+  int  *id_all;
+  rvec *f_all;
+#endif
+
+  reallocate_data realloc;
+  //int *num_bonds;
+  /* hydrogen bonds */
+  //int   num_H, Hcap;
+  //int  *Hindex;
+  //int *num_hbonds;
+  //int *hash;
+  //int *rev_hash;
+} storage;
+
+
+typedef union
+{
+  void *v;
+  three_body_interaction_data *three_body_list;
+  bond_data          *bond_list;
+  dbond_data         *dbo_list;
+  dDelta_data        *dDelta_list;
+  far_neighbor_data  *far_nbr_list;
+  hbond_data         *hbond_list;
+} list_type;
+
+
+typedef struct
+{
+  int allocated;
+
+  int n;
+  int num_intrs;
+
+  int *index;
+  int *end_index;
+
+  int type;
+  list_type select;
+} reax_list;
+
+
+typedef struct
+{
+#if defined(PURE_REAX)
+  MPI_File trj;
+#endif
+  FILE *strj;
+  int   trj_offset;
+  int   atom_line_len;
+  int   bond_line_len;
+  int   angle_line_len;
+  int   write_atoms;
+  int   write_bonds;
+  int   write_angles;
+  char *line;
+  int   buffer_len;
+  char *buffer;
+
+  FILE *out;
+  FILE *pot;
+  FILE *log;
+  FILE *mol, *ign;
+  FILE *dpl;
+  FILE *drft;
+  FILE *pdb;
+  FILE *prs;
+
+  int   write_steps;
+  int   traj_compress;
+  int   traj_method;
+  char  traj_title[81];
+  int   atom_info;
+  int   bond_info;
+  int   angle_info;
+
+  int   restart_format;
+  int   restart_freq;
+  int   debug_level;
+  int   energy_update_freq;
+
+#ifdef TEST_ENERGY
+  FILE *ebond;
+  FILE *elp, *eov, *eun;
+  FILE *eval, *epen, *ecoa;
+  FILE *ehb;
+  FILE *etor, *econ;
+  FILE *evdw, *ecou;
+#endif
+
+#ifdef TEST_FORCES
+  FILE *fbo, *fdbo;
+  FILE *fbond;
+  FILE *flp, *fov, *fun;
+  FILE *fang, *fcoa, *fpen;
+  FILE *fhb;
+  FILE *ftor, *fcon;
+  FILE *fvdw, *fele;
+  FILE *ftot, *fcomp;
+#endif
+
+#if defined(TEST_ENERGY) || defined(TEST_FORCES)
+  FILE *flist; // far neighbor list
+  FILE *blist; // bond list
+  FILE *nlist; // near neighbor list
+#endif
+} output_controls;
+
+
+typedef struct
+{
+  int atom_count;
+  int atom_list[REAX_MAX_MOLECULE_SIZE];
+  int mtypes[REAX_MAX_ATOM_TYPES];
+} molecule; 
+
+
+typedef struct
+{
+  real H;
+  real e_vdW, CEvd;
+  real e_ele, CEclmb;
+} LR_data;
+
+
+typedef struct
+{
+  real a, b, c, d;
+} cubic_spline_coef;
+
+
+
+typedef struct
+{
+  real xmin, xmax;
+  int n;
+  real dx, inv_dx;
+  real a;
+  real m;
+  real c;
+
+  LR_data *y;
+  cubic_spline_coef *H;
+  cubic_spline_coef *vdW, *CEvd;
+  cubic_spline_coef *ele, *CEclmb;
+} LR_lookup_table;
+extern LR_lookup_table **LR;
+
+/* function pointer defs */
+typedef void (*evolve_function)(reax_system*, control_params*, 
+				simulation_data*, storage*, reax_list**, 
+				output_controls*, mpi_datatypes* );
+#if defined(PURE_REAX)
+evolve_function  Evolve;
+#endif
+
+typedef void (*interaction_function) (reax_system*, control_params*, 
+				      simulation_data*, storage*, 
+				      reax_list**, output_controls*);
+
+typedef void (*print_interaction)(reax_system*, control_params*, 
+				  simulation_data*, storage*, 
+				  reax_list**, output_controls*);
+
+typedef real (*lookup_function)(real);
+
+typedef void (*message_sorter) (reax_system*, int, int, int, mpi_out_data*);
+typedef void (*unpacker) ( reax_system*, int, void*, int, neighbor_proc*, int );
+
+typedef void (*dist_packer) (void*, mpi_out_data*);
+typedef void (*coll_unpacker) (void*, void*, mpi_out_data*);
+#endif
diff --git a/src/USER-REAXC/reaxc_valence_angles.cpp b/src/USER-REAXC/reaxc_valence_angles.cpp
new file mode 100644
index 0000000000..84b41ba5fc
--- /dev/null
+++ b/src/USER-REAXC/reaxc_valence_angles.cpp
@@ -0,0 +1,535 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#include "reaxc_types.h"
+#if defined(PURE_REAX)
+#include "valence_angles.h"
+#include "bond_orders.h"
+#include "list.h"
+#include "vector.h"
+#elif defined(LAMMPS_REAX)
+#include "reaxc_valence_angles.h"
+#include "reaxc_bond_orders.h"
+#include "reaxc_list.h"
+#include "reaxc_vector.h"
+#endif
+
+
+/* calculates the theta angle between i-j-k */
+void Calculate_Theta( rvec dvec_ji, real d_ji, rvec dvec_jk, real d_jk, 
+		      real *theta, real *cos_theta )
+{
+  (*cos_theta) = Dot( dvec_ji, dvec_jk, 3 ) / ( d_ji * d_jk );
+  if( *cos_theta > 1. ) *cos_theta  = 1.0;
+  if( *cos_theta < -1. ) *cos_theta  = -1.0;
+ 
+  (*theta) = acos( *cos_theta );
+}
+
+
+/* calculates the derivative of the cosine of the angle between i-j-k */
+void Calculate_dCos_Theta( rvec dvec_ji, real d_ji, rvec dvec_jk, real d_jk, 
+			   rvec* dcos_theta_di, 
+			   rvec* dcos_theta_dj, 
+			   rvec* dcos_theta_dk )
+{
+  int t;
+  real sqr_d_ji = SQR(d_ji);
+  real sqr_d_jk = SQR(d_jk);
+  real inv_dists = 1.0 / (d_ji * d_jk);
+  real inv_dists3 = pow( inv_dists, 3 );
+  real dot_dvecs = Dot( dvec_ji, dvec_jk, 3 );
+  real Cdot_inv3 = dot_dvecs * inv_dists3;
+
+  for( t = 0; t < 3; ++t ) {
+    (*dcos_theta_di)[t] = dvec_jk[t] * inv_dists - 
+      Cdot_inv3 * sqr_d_jk * dvec_ji[t];
+    (*dcos_theta_dj)[t] = -(dvec_jk[t] + dvec_ji[t]) * inv_dists +
+      Cdot_inv3 * ( sqr_d_jk * dvec_ji[t] + sqr_d_ji * dvec_jk[t] );
+    (*dcos_theta_dk)[t] = dvec_ji[t] * inv_dists - 
+      Cdot_inv3 * sqr_d_ji * dvec_jk[t];
+  }
+}
+
+
+/* this is a 3-body interaction in which the main role is 
+   played by j which sits in the middle of the other two. */
+void Valence_Angles( reax_system *system, control_params *control, 
+		     simulation_data *data, storage *workspace, 
+		     reax_list **lists, output_controls *out_control )
+{
+  int i, j, pi, k, pk, t;
+  int type_i, type_j, type_k;
+  int start_j, end_j, start_pk, end_pk;
+  int cnt, num_thb_intrs;
+
+  real temp, temp_bo_jt, pBOjt7;
+  real p_val1, p_val2, p_val3, p_val4, p_val5;
+  real p_val6, p_val7, p_val8, p_val9, p_val10;
+  real p_pen1, p_pen2, p_pen3, p_pen4;
+  real p_coa1, p_coa2, p_coa3, p_coa4;
+  real trm8, expval6, expval7, expval2theta, expval12theta, exp3ij, exp3jk;
+  real exp_pen2ij, exp_pen2jk, exp_pen3, exp_pen4, trm_pen34, exp_coa2;
+  real dSBO1, dSBO2, SBO, SBO2, CSBO2, SBOp, prod_SBO, vlpadj;
+  real CEval1, CEval2, CEval3, CEval4, CEval5, CEval6, CEval7, CEval8;
+  real CEpen1, CEpen2, CEpen3;
+  real e_ang, e_coa, e_pen;
+  real CEcoa1, CEcoa2, CEcoa3, CEcoa4, CEcoa5;
+  real Cf7ij, Cf7jk, Cf8j, Cf9j;
+  real f7_ij, f7_jk, f8_Dj, f9_Dj;
+  real Ctheta_0, theta_0, theta_00, theta, cos_theta, sin_theta;
+  real r_ij, r_jk;
+  real BOA_ij, BOA_jk;
+  rvec force, ext_press;
+  // rtensor temp_rtensor, total_rtensor;
+
+  three_body_header *thbh;
+  three_body_parameters *thbp;
+  three_body_interaction_data *p_ijk, *p_kji;
+  bond_data *pbond_ij, *pbond_jk, *pbond_jt;
+  bond_order_data *bo_ij, *bo_jk, *bo_jt;
+  reax_list *bonds = (*lists) + BONDS;
+  reax_list *thb_intrs =  (*lists) + THREE_BODIES;
+
+
+  /* global parameters used in these calculations */
+  p_val6 = system->reax_param.gp.l[14];
+  p_val8 = system->reax_param.gp.l[33];
+  p_val9 = system->reax_param.gp.l[16];
+  p_val10 = system->reax_param.gp.l[17];
+  num_thb_intrs = 0;
+
+  
+  for( j = 0; j < system->N; ++j ) {
+    // fprintf( out_control->eval, "j: %d\n", j );
+    type_j = system->my_atoms[j].type;
+    start_j = Start_Index(j, bonds);
+    end_j = End_Index(j, bonds);
+    
+    p_val3 = system->reax_param.sbp[ type_j ].p_val3;
+    p_val5 = system->reax_param.sbp[ type_j ].p_val5;
+    
+    SBOp = 0, prod_SBO = 1;
+    for( t = start_j; t < end_j; ++t ) {
+      bo_jt = &(bonds->select.bond_list[t].bo_data);
+      SBOp += (bo_jt->BO_pi + bo_jt->BO_pi2);
+      temp = SQR( bo_jt->BO );
+      temp *= temp; 
+      temp *= temp;
+      prod_SBO *= exp( -temp );
+    }
+    
+    /* modifications to match Adri's code - 09/01/09 */
+    if( workspace->vlpex[j] >= 0 ){
+      vlpadj = 0;
+      dSBO2 = prod_SBO - 1;
+    }
+    else{
+      vlpadj = workspace->nlp[j];
+      dSBO2 = (prod_SBO - 1) * (1 - p_val8 * workspace->dDelta_lp[j]);
+    }
+
+    SBO = SBOp + (1 - prod_SBO) * (-workspace->Delta_boc[j] - p_val8 * vlpadj);
+    dSBO1 = -8 * prod_SBO * ( workspace->Delta_boc[j] + p_val8 * vlpadj );
+      
+    if( SBO <= 0 )
+      SBO2 = 0, CSBO2 = 0;
+    else if( SBO > 0 && SBO <= 1 ) {
+	SBO2 = pow( SBO, p_val9 );
+	CSBO2 = p_val9 * pow( SBO, p_val9 - 1 );
+    }
+    else if( SBO > 1 && SBO < 2 ) {
+      SBO2 = 2 - pow( 2-SBO, p_val9 );
+      CSBO2 = p_val9 * pow( 2 - SBO, p_val9 - 1 );
+    }
+    else 
+      SBO2 = 2, CSBO2 = 0;  
+    
+    expval6 = exp( p_val6 * workspace->Delta_boc[j] );    
+    
+    for( pi = start_j; pi < end_j; ++pi ) {
+      Set_Start_Index( pi, num_thb_intrs, thb_intrs );
+      pbond_ij = &(bonds->select.bond_list[pi]);
+      bo_ij = &(pbond_ij->bo_data);
+      BOA_ij = bo_ij->BO - control->thb_cut;
+      
+      
+      if( BOA_ij/*bo_ij->BO*/ > 0.0 && 
+	  ( j < system->n || pbond_ij->nbr < system->n ) ) {
+	i = pbond_ij->nbr;
+	r_ij = pbond_ij->d;	 
+	type_i = system->my_atoms[i].type;
+	// fprintf( out_control->eval, "i: %d\n", i );
+	
+	
+	/* first copy 3-body intrs from previously computed ones where i>k.
+	   in the second for-loop below, 
+	   we compute only new 3-body intrs where i < k */
+	for( pk = start_j; pk < pi; ++pk ) {
+	  // fprintf( out_control->eval, "pk: %d\n", pk );
+	  start_pk = Start_Index( pk, thb_intrs );
+	  end_pk = End_Index( pk, thb_intrs );
+		  
+	  for( t = start_pk; t < end_pk; ++t )
+	    if( thb_intrs->select.three_body_list[t].thb == i ) {
+	      p_ijk = &(thb_intrs->select.three_body_list[num_thb_intrs] );
+	      p_kji = &(thb_intrs->select.three_body_list[t]);
+	      
+	      p_ijk->thb = bonds->select.bond_list[pk].nbr;
+	      p_ijk->pthb  = pk;
+	      p_ijk->theta = p_kji->theta;			  
+	      rvec_Copy( p_ijk->dcos_di, p_kji->dcos_dk );
+	      rvec_Copy( p_ijk->dcos_dj, p_kji->dcos_dj );
+	      rvec_Copy( p_ijk->dcos_dk, p_kji->dcos_di );
+	      
+	      ++num_thb_intrs;
+	      break;
+	    }
+	}
+	      
+
+	/* and this is the second for loop mentioned above */
+	for( pk = pi+1; pk < end_j; ++pk ) {
+	  pbond_jk = &(bonds->select.bond_list[pk]);
+	  bo_jk    = &(pbond_jk->bo_data);
+	  BOA_jk   = bo_jk->BO - control->thb_cut;
+	  k        = pbond_jk->nbr;
+	  type_k   = system->my_atoms[k].type;
+	  p_ijk    = &( thb_intrs->select.three_body_list[num_thb_intrs] );
+	  
+	  Calculate_Theta( pbond_ij->dvec, pbond_ij->d, 
+			   pbond_jk->dvec, pbond_jk->d,
+			   &theta, &cos_theta );
+	  
+	  Calculate_dCos_Theta( pbond_ij->dvec, pbond_ij->d, 
+				pbond_jk->dvec, pbond_jk->d, 
+				&(p_ijk->dcos_di), &(p_ijk->dcos_dj), 
+				&(p_ijk->dcos_dk) );
+	  p_ijk->thb = k;
+	  p_ijk->pthb = pk;
+	  p_ijk->theta = theta;
+	  
+	  sin_theta = sin( theta );
+	  if( sin_theta < 1.0e-5 )
+	    sin_theta = 1.0e-5;
+
+	  ++num_thb_intrs;
+	  
+	  
+	  if( (j < system->n) && (BOA_jk > 0.0) && 
+	      (bo_ij->BO * bo_jk->BO > SQR(control->thb_cut)/*0*/) ) {
+	    r_jk = pbond_jk->d;		      
+	    thbh = &( system->reax_param.thbp[ type_i ][ type_j ][ type_k ] );
+	    
+	    /* if( system->my_atoms[i].orig_id < system->my_atoms[k].orig_id )
+	       fprintf( fval, "%6d %6d %6d %7.3f %7.3f %7.3f\n", 
+	       system->my_atoms[i].orig_id, 
+	       system->my_atoms[j].orig_id, 
+	       system->my_atoms[k].orig_id,
+	       bo_ij->BO, bo_jk->BO, p_ijk->theta );
+	       else 
+	       fprintf( fval, "%6d %6d %6d %7.3f %7.3f %7.3f\n", 
+	       system->my_atoms[k].orig_id,
+	       system->my_atoms[j].orig_id, 
+	       system->my_atoms[i].orig_id, 
+	       bo_jk->BO, bo_ij->BO, p_ijk->theta ); */
+	    
+	    for( cnt = 0; cnt < thbh->cnt; ++cnt ) {
+	      // fprintf( out_control->eval, "%6d%6d%6d -- exists in thbp\n", 
+	      //          i+1, j+1, k+1 );
+
+	      if( fabs(thbh->prm[cnt].p_val1) > 0.001 ) {
+		thbp = &( thbh->prm[cnt] );			     
+
+		/* ANGLE ENERGY */
+		p_val1 = thbp->p_val1;
+		p_val2 = thbp->p_val2;
+		p_val4 = thbp->p_val4;
+		p_val7 = thbp->p_val7;
+		theta_00 = thbp->theta_00;
+		
+		exp3ij = exp( -p_val3 * pow( BOA_ij, p_val4 ) );
+		f7_ij = 1.0 - exp3ij;
+		Cf7ij = p_val3 * p_val4 * pow( BOA_ij, p_val4 - 1.0 ) * exp3ij;
+		
+		exp3jk = exp( -p_val3 * pow( BOA_jk, p_val4 ) );
+		f7_jk = 1.0 - exp3jk;
+		Cf7jk = p_val3 * p_val4 * pow( BOA_jk, p_val4 - 1.0 ) * exp3jk;
+		
+		expval7 = exp( -p_val7 * workspace->Delta_boc[j] );
+		trm8 = 1.0 + expval6 + expval7;
+		f8_Dj = p_val5 - ( (p_val5 - 1.0) * (2.0 + expval6) / trm8 );
+		Cf8j = ( (1.0 - p_val5) / SQR(trm8) ) *
+		  ( p_val6 * expval6 * trm8 - 
+		    (2.0 + expval6) * ( p_val6*expval6 - p_val7*expval7 ) );
+		
+		theta_0 = 180.0 - theta_00 * (1.0 - 
+					      exp(-p_val10 * (2.0 - SBO2)));
+		theta_0 = DEG2RAD( theta_0 );		      
+		
+		expval2theta  = exp( -p_val2 * SQR(theta_0 - theta) );
+		if( p_val1 >= 0 ) 
+		  expval12theta = p_val1 * (1.0 - expval2theta);
+		else // To avoid linear Me-H-Me angles (6/6/06)
+		  expval12theta = p_val1 * -expval2theta;
+		
+		CEval1 = Cf7ij * f7_jk * f8_Dj * expval12theta;
+		CEval2 = Cf7jk * f7_ij * f8_Dj * expval12theta;
+		CEval3 = Cf8j  * f7_ij * f7_jk * expval12theta;
+		CEval4 = -2.0 * p_val1 * p_val2 * f7_ij * f7_jk * f8_Dj * 
+		  expval2theta * (theta_0 - theta);
+		
+		Ctheta_0 = p_val10 * DEG2RAD(theta_00) * 
+		  exp( -p_val10 * (2.0 - SBO2) );
+		
+		CEval5 = -CEval4 * Ctheta_0 * CSBO2;
+		CEval6 = CEval5 * dSBO1;
+		CEval7 = CEval5 * dSBO2;
+		CEval8 = -CEval4 / sin_theta;
+		
+		data->my_en.e_ang += e_ang = 
+		  f7_ij * f7_jk * f8_Dj * expval12theta;
+		/* END ANGLE ENERGY*/
+		
+		
+		/* PENALTY ENERGY */
+		p_pen1 = thbp->p_pen1;
+		p_pen2 = system->reax_param.gp.l[19];
+		p_pen3 = system->reax_param.gp.l[20];
+		p_pen4 = system->reax_param.gp.l[21];
+		
+		exp_pen2ij = exp( -p_pen2 * SQR( BOA_ij - 2.0 ) );
+		exp_pen2jk = exp( -p_pen2 * SQR( BOA_jk - 2.0 ) );
+		exp_pen3 = exp( -p_pen3 * workspace->Delta[j] );
+		exp_pen4 = exp(  p_pen4 * workspace->Delta[j] );
+		trm_pen34 = 1.0 + exp_pen3 + exp_pen4;
+		f9_Dj = ( 2.0 + exp_pen3 ) / trm_pen34;
+		Cf9j = ( -p_pen3 * exp_pen3 * trm_pen34 - 
+			 (2.0 + exp_pen3) * ( -p_pen3 * exp_pen3 + 
+					      p_pen4 * exp_pen4 ) ) / 
+		  SQR( trm_pen34 );
+		
+		data->my_en.e_pen += e_pen = 
+		  p_pen1 * f9_Dj * exp_pen2ij * exp_pen2jk;
+		
+		CEpen1 = e_pen * Cf9j / f9_Dj;
+		temp   = -2.0 * p_pen2 * e_pen;
+		CEpen2 = temp * (BOA_ij - 2.0);
+		CEpen3 = temp * (BOA_jk - 2.0);
+		/* END PENALTY ENERGY */
+		
+		
+		/* COALITION ENERGY */
+		p_coa1 = thbp->p_coa1;
+		p_coa2 = system->reax_param.gp.l[2];
+		p_coa3 = system->reax_param.gp.l[38];
+		p_coa4 = system->reax_param.gp.l[30];
+		
+		exp_coa2 = exp( p_coa2 * workspace->Delta_boc[j] );
+		data->my_en.e_coa += e_coa = 
+		  p_coa1 / (1. + exp_coa2) *
+		  exp( -p_coa3 * SQR(workspace->total_bond_order[i]-BOA_ij) ) *
+		  exp( -p_coa3 * SQR(workspace->total_bond_order[k]-BOA_jk) ) *
+		  exp( -p_coa4 * SQR(BOA_ij - 1.5) ) * 
+		  exp( -p_coa4 * SQR(BOA_jk - 1.5) );
+		
+		CEcoa1 = -2 * p_coa4 * (BOA_ij - 1.5) * e_coa;
+		CEcoa2 = -2 * p_coa4 * (BOA_jk - 1.5) * e_coa;
+		CEcoa3 = -p_coa2 * exp_coa2 * e_coa / (1 + exp_coa2);
+		CEcoa4 = -2 * p_coa3 * 
+		  (workspace->total_bond_order[i]-BOA_ij) * e_coa;
+		CEcoa5 = -2 * p_coa3 * 
+		  (workspace->total_bond_order[k]-BOA_jk) * e_coa;
+		/* END COALITION ENERGY */
+		
+		/* FORCES */
+		bo_ij->Cdbo += (CEval1 + CEpen2 + (CEcoa1 - CEcoa4));
+		bo_jk->Cdbo += (CEval2 + CEpen3 + (CEcoa2 - CEcoa5));
+		workspace->CdDelta[j] += ((CEval3 + CEval7) + CEpen1 + CEcoa3);
+		workspace->CdDelta[i] += CEcoa4;
+		workspace->CdDelta[k] += CEcoa5;		      
+		
+		for( t = start_j; t < end_j; ++t ) {
+		    pbond_jt = &( bonds->select.bond_list[t] );
+		    bo_jt = &(pbond_jt->bo_data);
+		    temp_bo_jt = bo_jt->BO;
+		    temp = CUBE( temp_bo_jt );
+		    pBOjt7 = temp * temp * temp_bo_jt; 
+		    
+		    // fprintf( out_control->eval, "%6d%12.8f\n", 
+		    // workspace->reverse_map[bonds->select.bond_list[t].nbr],
+		    // (CEval6 * pBOjt7) );
+		    
+		    bo_jt->Cdbo += (CEval6 * pBOjt7);
+		    bo_jt->Cdbopi += CEval5;
+		    bo_jt->Cdbopi2 += CEval5;
+		}		      
+		
+		
+		if( control->virial == 0 ) {
+		  rvec_ScaledAdd( workspace->f[i], CEval8, p_ijk->dcos_di );
+		  rvec_ScaledAdd( workspace->f[j], CEval8, p_ijk->dcos_dj );
+		  rvec_ScaledAdd( workspace->f[k], CEval8, p_ijk->dcos_dk );
+		}
+		else {
+		  /* terms not related to bond order derivatives are
+		     added directly into forces and pressure vector/tensor */
+		  rvec_Scale( force, CEval8, p_ijk->dcos_di );
+		  rvec_Add( workspace->f[i], force );
+		  rvec_iMultiply( ext_press, pbond_ij->rel_box, force );
+		  rvec_Add( data->my_ext_press, ext_press );
+		  
+		  rvec_ScaledAdd( workspace->f[j], CEval8, p_ijk->dcos_dj );
+		  
+		  rvec_Scale( force, CEval8, p_ijk->dcos_dk );
+		  rvec_Add( workspace->f[k], force );
+		  rvec_iMultiply( ext_press, pbond_jk->rel_box, force );
+		  rvec_Add( data->my_ext_press, ext_press );
+		}
+		
+#ifdef TEST_ENERGY
+		/*fprintf( out_control->eval, "%12.8f%12.8f%12.8f%12.8f\n",
+		  p_val3, p_val4, BOA_ij, BOA_jk );
+		fprintf(out_control->eval, "%13.8f%13.8f%13.8f%13.8f%13.8f\n",
+			workspace->Delta_e[j], workspace->vlpex[j],
+			dSBO1, dSBO2, vlpadj );
+		fprintf( out_control->eval, "%12.8f%12.8f%12.8f%12.8f\n",
+			 f7_ij, f7_jk, f8_Dj, expval12theta );
+		fprintf( out_control->eval, 
+			 "%12.8f%12.8f%12.8f%12.8f%12.8f%12.8f%12.8f%12.8f\n",
+			 CEval1, CEval2, CEval3, CEval4, 
+			 CEval5, CEval6, CEval7, CEval8 );
+		
+		fprintf( out_control->eval, 
+		"%12.8f%12.8f%12.8f\n%12.8f%12.8f%12.8f\n%12.8f%12.8f%12.8f\n",
+		   p_ijk->dcos_di[0]/sin_theta, p_ijk->dcos_di[1]/sin_theta,
+		   p_ijk->dcos_di[2]/sin_theta, 
+		   p_ijk->dcos_dj[0]/sin_theta, p_ijk->dcos_dj[1]/sin_theta,
+		   p_ijk->dcos_dj[2]/sin_theta, 
+		   p_ijk->dcos_dk[0]/sin_theta, p_ijk->dcos_dk[1]/sin_theta,
+		   p_ijk->dcos_dk[2]/sin_theta);
+		
+		fprintf( out_control->eval, 
+			 "%6d%6d%6d%15.8f%15.8f\n",
+			 system->my_atoms[i].orig_id, 
+			 system->my_atoms[j].orig_id, 
+			 system->my_atoms[k].orig_id,
+			 RAD2DEG(theta), e_ang );*/
+
+		fprintf( out_control->eval, 
+		//"%6d%6d%6d%24.15e%24.15e%24.15e%24.15e%24.15e%24.15e\n",
+			 "%6d%6d%6d%12.4f%12.4f%12.4f%12.4f%12.4f%12.4f\n",
+			 system->my_atoms[i].orig_id, 
+			 system->my_atoms[j].orig_id, 
+			 system->my_atoms[k].orig_id,
+			 RAD2DEG(theta), theta_0, BOA_ij, BOA_jk,
+			 e_ang, data->my_en.e_ang );
+		
+		fprintf( out_control->epen, 
+			 //"%6d%6d%6d%24.15e%24.15e%24.15e%24.15e%24.15e\n",
+			 "%6d%6d%6d%12.4f%12.4f%12.4f%12.4f%12.4f\n",
+			 system->my_atoms[i].orig_id,
+			 system->my_atoms[j].orig_id,
+			 system->my_atoms[k].orig_id,
+			 RAD2DEG(theta), BOA_ij, BOA_jk, e_pen, 
+			 data->my_en.e_pen );
+		
+		fprintf( out_control->ecoa, 
+			 //"%6d%6d%6d%24.15e%24.15e%24.15e%24.15e%24.15e\n",
+			 "%6d%6d%6d%12.4f%12.4f%12.4f%12.4f%12.4f\n",
+			 system->my_atoms[i].orig_id, 
+			 system->my_atoms[j].orig_id, 
+			 system->my_atoms[k].orig_id,
+			 RAD2DEG(theta), BOA_ij, BOA_jk, 
+			 e_coa, data->my_en.e_coa );
+#endif
+
+#ifdef TEST_FORCES            /* angle forces */
+		Add_dBO( system, lists, j, pi, CEval1, workspace->f_ang );
+		Add_dBO( system, lists, j, pk, CEval2, workspace->f_ang );
+		Add_dDelta( system, lists, j, 
+			    CEval3 + CEval7, workspace->f_ang );
+		
+		for( t = start_j; t < end_j; ++t ) {
+		  pbond_jt = &( bonds->select.bond_list[t] );
+		  bo_jt = &(pbond_jt->bo_data);
+		  temp_bo_jt = bo_jt->BO;
+		  temp = CUBE( temp_bo_jt );
+		  pBOjt7 = temp * temp * temp_bo_jt; 
+		  
+		  Add_dBO( system, lists, j, t, pBOjt7 * CEval6, 
+			   workspace->f_ang );
+		  Add_dBOpinpi2( system, lists, j, t, CEval5, CEval5, 
+				 workspace->f_ang, workspace->f_ang );
+		}
+		
+		rvec_ScaledAdd( workspace->f_ang[i], CEval8, p_ijk->dcos_di );
+		rvec_ScaledAdd( workspace->f_ang[j], CEval8, p_ijk->dcos_dj );
+		rvec_ScaledAdd( workspace->f_ang[k], CEval8, p_ijk->dcos_dk );
+		/* end angle forces */
+		
+		/* penalty forces */
+		Add_dDelta( system, lists, j, CEpen1, workspace->f_pen );
+		Add_dBO( system, lists, j, pi, CEpen2, workspace->f_pen );
+		Add_dBO( system, lists, j, pk, CEpen3, workspace->f_pen );
+		/* end penalty forces */
+		
+		/* coalition forces */
+		Add_dBO( system, lists, j, pi, CEcoa1 - CEcoa4, 
+			 workspace->f_coa );
+		Add_dBO( system, lists, j, pk, CEcoa2 - CEcoa5, 
+			 workspace->f_coa );
+		Add_dDelta( system, lists, j, CEcoa3, workspace->f_coa );
+		Add_dDelta( system, lists, i, CEcoa4, workspace->f_coa );
+		Add_dDelta( system, lists, k, CEcoa5, workspace->f_coa );
+		/* end coalition forces */
+#endif
+	      }
+	    }
+	  }
+	}
+      }
+      
+      Set_End_Index(pi, num_thb_intrs, thb_intrs );
+    }
+  }
+
+  if( num_thb_intrs >= thb_intrs->num_intrs * DANGER_ZONE ) {
+    workspace->realloc.num_3body = num_thb_intrs;
+    if( num_thb_intrs > thb_intrs->num_intrs ) {
+      fprintf( stderr, "step%d-ran out of space on angle_list: top=%d, max=%d",
+	       data->step, num_thb_intrs, thb_intrs->num_intrs );
+      MPI_Abort( MPI_COMM_WORLD, INSUFFICIENT_MEMORY );
+    }
+  }
+  //fprintf( stderr,"%d: Number of angle interactions: %d\n", 
+  // data->step, num_thb_intrs );  
+  
+#if defined(DEBUG)
+  fprintf( stderr, "Number of angle interactions: %d\n", num_thb_intrs );
+  fprintf( stderr, 
+	   "Angle Energy: %g\t Penalty Energy: %g\t Coalition Energy: %g\t\n",
+	   data->my_en.e_ang, data->my_en.e_pen, data->my_en.e_coa );
+  
+  fprintf( stderr, "3body: ext_press (%12.6f %12.6f %12.6f)\n", 
+	   data->ext_press[0], data->ext_press[1], data->ext_press[2] );
+#endif
+}
diff --git a/src/USER-REAXC/reaxc_valence_angles.h b/src/USER-REAXC/reaxc_valence_angles.h
new file mode 100644
index 0000000000..ac27db483d
--- /dev/null
+++ b/src/USER-REAXC/reaxc_valence_angles.h
@@ -0,0 +1,34 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#ifndef __VALENCE_ANGLES_H_
+#define __VALENCE_ANGLES_H_
+
+#include "reaxc_types.h"
+
+void Valence_Angles( reax_system*, control_params*, simulation_data*,
+		     storage*, reax_list**, output_controls* );
+
+void Calculate_Theta( rvec, real, rvec, real, real*, real* );
+		      
+void Calculate_dCos_Theta( rvec, real, rvec, real, rvec*, rvec*, rvec* );
+			   
+#endif
diff --git a/src/USER-REAXC/reaxc_vector.cpp b/src/USER-REAXC/reaxc_vector.cpp
new file mode 100644
index 0000000000..77feddf9dd
--- /dev/null
+++ b/src/USER-REAXC/reaxc_vector.cpp
@@ -0,0 +1,518 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#include "reaxc_types.h"
+#if defined(PURE_REAX)
+#include "vector.h"
+#include "random.h"
+#elif defined(LAMMPS_REAX)
+#include "reaxc_vector.h"
+#endif
+
+int Vector_isZero( real* v, int k )
+{
+  for( --k; k>=0; --k )
+    if( fabs( v[k] ) > ALMOST_ZERO )
+      return 0;
+  
+  return 1;
+}
+
+
+void Vector_MakeZero( real *v, int k )
+{
+  for( --k; k>=0; --k )
+    v[k] = 0;
+}
+
+
+void Vector_Copy( real* dest, real* v, int k )
+{
+  for( --k; k>=0; --k )
+    dest[k] = v[k];
+}
+
+
+void Vector_Scale( real* dest, real c, real* v, int k )
+{
+  for( --k; k>=0; --k )
+    dest[k] = c * v[k];
+}
+
+
+void Vector_Sum( real* dest, real c, real* v, real d, real* y, int k )
+{
+  for( --k; k>=0; --k )
+    dest[k] = c * v[k] + d * y[k];
+}
+
+
+void Vector_Add( real* dest, real c, real* v, int k )
+{
+  for( --k; k>=0; --k )
+    dest[k] += c * v[k];
+}
+
+
+real Dot( real* v1, real* v2, int k )
+{
+  real ret = 0;
+  
+  for( --k; k>=0; --k )
+    ret +=  v1[k] * v2[k];
+
+  return ret;
+}
+
+
+real Norm( real* v1, int k )
+{
+  real ret = 0;
+  
+  for( --k; k>=0; --k )
+    ret +=  SQR( v1[k] );
+
+  return sqrt( ret );
+}
+
+
+void Vector_Print( FILE *fout, char *vname, real *v, int k )
+{
+  int i;
+
+  fprintf( fout, "%s:", vname );
+  for( i = 0; i < k; ++i )
+    fprintf( fout, "%24.15e\n", v[i] );
+  fprintf( fout, "\n" );
+}
+
+
+void rvec_Copy( rvec dest, rvec src )
+{
+  dest[0] = src[0], dest[1] = src[1], dest[2] = src[2];
+}
+
+void rvec_Scale( rvec ret, real c, rvec v )
+{
+  ret[0] = c * v[0], ret[1] = c * v[1], ret[2] = c * v[2];
+}
+
+
+void rvec_Add( rvec ret, rvec v )
+{
+  ret[0] += v[0], ret[1] += v[1], ret[2] += v[2];
+}
+
+
+void rvec_ScaledAdd( rvec ret, real c, rvec v )
+{
+  ret[0] += c * v[0], ret[1] += c * v[1], ret[2] += c * v[2];
+}
+
+
+void rvec_Sum( rvec ret, rvec v1 ,rvec v2 )
+{
+  ret[0] = v1[0] + v2[0];
+  ret[1] = v1[1] + v2[1];
+  ret[2] = v1[2] + v2[2];
+}
+
+
+void rvec_ScaledSum( rvec ret, real c1, rvec v1 ,real c2, rvec v2 )
+{
+  ret[0] = c1 * v1[0] + c2 * v2[0]; 
+  ret[1] = c1 * v1[1] + c2 * v2[1];
+  ret[2] = c1 * v1[2] + c2 * v2[2];
+}
+
+
+real rvec_Dot( rvec v1, rvec v2 )
+{
+  return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
+}
+
+
+real rvec_ScaledDot( real c1, rvec v1, real c2, rvec v2 )
+{
+  return (c1*c2) * (v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]);
+}
+
+
+void rvec_Multiply( rvec r, rvec v1, rvec v2 )
+{
+  r[0] = v1[0] * v2[0];
+  r[1] = v1[1] * v2[1];
+  r[2] = v1[2] * v2[2];
+}
+
+
+void rvec_iMultiply( rvec r, ivec v1, rvec v2 )
+{
+  r[0] = v1[0] * v2[0];
+  r[1] = v1[1] * v2[1];
+  r[2] = v1[2] * v2[2];
+}
+
+
+void rvec_Divide( rvec r, rvec v1, rvec v2 )
+{
+  r[0] = v1[0] / v2[0];
+  r[1] = v1[1] / v2[1];
+  r[2] = v1[2] / v2[2];
+}
+
+
+void rvec_iDivide( rvec r, rvec v1, ivec v2 )
+{
+  r[0] = v1[0] / v2[0];
+  r[1] = v1[1] / v2[1];
+  r[2] = v1[2] / v2[2];
+}
+
+
+void rvec_Invert( rvec r, rvec v )
+{
+  r[0] = 1. / v[0];
+  r[1] = 1. / v[1];
+  r[2] = 1. / v[2];
+}
+
+
+void rvec_Cross( rvec ret, rvec v1, rvec v2 )
+{
+  ret[0] = v1[1] * v2[2] - v1[2] * v2[1];
+  ret[1] = v1[2] * v2[0] - v1[0] * v2[2];
+  ret[2] = v1[0] * v2[1] - v1[1] * v2[0];
+}
+
+
+void rvec_OuterProduct( rtensor r, rvec v1, rvec v2 )
+{
+  int i, j;
+
+  for( i = 0; i < 3; ++i )
+    for( j = 0; j < 3; ++j )
+      r[i][j] = v1[i] * v2[j];
+}
+
+
+real rvec_Norm_Sqr( rvec v )
+{
+  return SQR(v[0]) + SQR(v[1]) + SQR(v[2]);
+}
+
+
+real rvec_Norm( rvec v )
+{
+  return sqrt( SQR(v[0]) + SQR(v[1]) + SQR(v[2]) );
+}
+
+
+int rvec_isZero( rvec v )
+{
+  if( fabs(v[0]) > ALMOST_ZERO || 
+      fabs(v[1]) > ALMOST_ZERO || 
+      fabs(v[2]) > ALMOST_ZERO )
+    return 0;
+  return 1;
+}
+
+
+void rvec_MakeZero( rvec v )
+{
+//  v[0] = v[1] = v[2] = 0.0000000000000;
+  v[0] = v[1] = v[2] = 0.000000000000000e+00;
+}
+
+
+#if defined(PURE_REAX)
+void rvec_Random( rvec v )
+{
+  v[0] = Random(2.0)-1.0;
+  v[1] = Random(2.0)-1.0;
+  v[2] = Random(2.0)-1.0;
+}
+#endif
+
+
+void rtensor_Multiply( rtensor ret, rtensor m1, rtensor m2 )
+{
+  int i, j, k;
+  rtensor temp;
+
+  // check if the result matrix is the same as one of m1, m2.
+  // if so, we cannot modify the contents of m1 or m2, so 
+  // we have to use a temp matrix.
+  if( ret == m1 || ret == m2 )
+    {
+      for( i = 0; i < 3; ++i )
+	for( j = 0; j < 3; ++j )
+	  {
+	    temp[i][j] = 0;	    
+	    for( k = 0; k < 3; ++k )
+	      temp[i][j] += m1[i][k] * m2[k][j];
+	  }
+      
+      for( i = 0; i < 3; ++i )
+	for( j = 0; j < 3; ++j )
+	  ret[i][j] = temp[i][j];	
+    }
+  else
+    {
+      for( i = 0; i < 3; ++i )
+	for( j = 0; j < 3; ++j )
+	  {
+	    ret[i][j] = 0;	    
+	    for( k = 0; k < 3; ++k )
+	      ret[i][j] += m1[i][k] * m2[k][j];
+	  }
+    }
+}
+
+
+void rtensor_MatVec( rvec ret, rtensor m, rvec v )
+{
+  int i;
+  rvec temp;
+
+  // if ret is the same vector as v, we cannot modify the 
+  // contents of v until all computation is finished.
+  if( ret == v )
+    {
+      for( i = 0; i < 3; ++i )
+	temp[i] = m[i][0] * v[0] + m[i][1] * v[1] + m[i][2] * v[2];
+
+      for( i = 0; i < 3; ++i )
+	ret[i] = temp[i];
+    }
+  else
+    {
+      for( i = 0; i < 3; ++i )
+	ret[i] = m[i][0] * v[0] + m[i][1] * v[1] + m[i][2] * v[2];
+    }
+}
+
+
+void rtensor_Scale( rtensor ret, real c, rtensor m )
+{
+  int i, j;
+
+  for( i = 0; i < 3; ++i )
+    for( j = 0; j < 3; ++j )
+      ret[i][j] = c * m[i][j];
+}
+
+
+void rtensor_Add( rtensor ret, rtensor t )
+{
+  int i, j;
+
+  for( i = 0; i < 3; ++i )
+    for( j = 0; j < 3; ++j )
+      ret[i][j] += t[i][j];
+}
+
+
+void rtensor_ScaledAdd( rtensor ret, real c, rtensor t )
+{
+  int i, j;
+
+  for( i = 0; i < 3; ++i )
+    for( j = 0; j < 3; ++j )
+      ret[i][j] += c * t[i][j];
+}
+
+
+void rtensor_Sum( rtensor ret, rtensor t1, rtensor t2 )
+{
+  int i, j;
+
+  for( i = 0; i < 3; ++i )
+    for( j = 0; j < 3; ++j )
+      ret[i][j] = t1[i][j] + t2[i][j];
+}
+
+
+void rtensor_ScaledSum( rtensor ret, real c1, rtensor t1, 
+			       real c2, rtensor t2 )
+{
+  int i, j;
+
+  for( i = 0; i < 3; ++i )
+    for( j = 0; j < 3; ++j )
+      ret[i][j] = c1 * t1[i][j] + c2 * t2[i][j];
+}
+
+
+void rtensor_Copy( rtensor ret, rtensor t )
+{
+  int i, j;
+
+  for( i = 0; i < 3; ++i )
+    for( j = 0; j < 3; ++j )
+      ret[i][j] = t[i][j];
+}
+
+
+void rtensor_Identity( rtensor t )
+{
+  t[0][0] = t[1][1] = t[2][2] = 1;
+  t[0][1] = t[0][2] = t[1][0] = t[1][2] = t[2][0] = t[2][1] = 0;
+}
+
+
+void rtensor_MakeZero( rtensor t )
+{
+  t[0][0] = t[0][1] = t[0][2] = 0;
+  t[1][0] = t[1][1] = t[1][2] = 0;
+  t[2][0] = t[2][1] = t[2][2] = 0;
+}
+
+
+void rtensor_Transpose( rtensor ret, rtensor t )
+{
+  ret[0][0] = t[0][0], ret[1][1] = t[1][1], ret[2][2] = t[2][2];
+  ret[0][1] = t[1][0], ret[0][2] = t[2][0];
+  ret[1][0] = t[0][1], ret[1][2] = t[2][1];
+  ret[2][0] = t[0][2], ret[2][1] = t[1][2];
+}
+
+
+real rtensor_Det( rtensor t )
+{
+  return ( t[0][0] * (t[1][1] * t[2][2] - t[1][2] * t[2][1] ) +
+           t[0][1] * (t[1][2] * t[2][0] - t[1][0] * t[2][2] ) +
+           t[0][2] * (t[1][0] * t[2][1] - t[1][1] * t[2][0] ) );
+}
+
+
+real rtensor_Trace( rtensor t )
+{
+  return (t[0][0] + t[1][1] + t[2][2]);
+}
+
+
+void Print_rTensor(FILE* fp, rtensor t)
+{
+  int i, j;
+
+  for (i=0; i < 3; i++)
+    {
+      fprintf(fp,"[");
+      for (j=0; j < 3; j++)
+	fprintf(fp,"%8.3f,\t",t[i][j]);
+      fprintf(fp,"]\n");
+    }
+}
+
+
+void ivec_MakeZero( ivec v )
+{
+  v[0] = v[1] = v[2] = 0;
+}
+
+
+void ivec_Copy( ivec dest, ivec src )
+{
+  dest[0] = src[0], dest[1] = src[1], dest[2] = src[2];
+}
+
+
+void ivec_Scale( ivec dest, real C, ivec src )
+{
+  dest[0] = (int)(C * src[0]);
+  dest[1] = (int)(C * src[1]);
+  dest[2] = (int)(C * src[2]);
+}
+
+
+void ivec_rScale( ivec dest, real C, rvec src )
+{
+  dest[0] = (int)(C * src[0]);
+  dest[1] = (int)(C * src[1]);
+  dest[2] = (int)(C * src[2]);
+}
+
+
+int ivec_isZero( ivec v )
+{
+  if( v[0]==0 && v[1]==0 && v[2]==0 )
+    return 1;
+  return 0;
+}
+
+
+int ivec_isEqual( ivec v1, ivec v2 )
+{
+  if( v1[0]==v2[0] && v1[1]==v2[1] && v1[2]==v2[2] )
+    return 1;
+  return 0;
+}
+
+
+void ivec_Sum( ivec dest, ivec v1, ivec v2 )
+{
+  dest[0] = v1[0] + v2[0];
+  dest[1] = v1[1] + v2[1];
+  dest[2] = v1[2] + v2[2];
+}
+
+
+void ivec_ScaledSum( ivec dest, int k1, ivec v1, int k2, ivec v2 )
+{
+  dest[0] = k1*v1[0] + k2*v2[0];
+  dest[1] = k1*v1[1] + k2*v2[1];
+  dest[2] = k1*v1[2] + k2*v2[2];
+}
+
+
+void ivec_Add( ivec dest, ivec v )
+{
+  dest[0] += v[0];
+  dest[1] += v[1];
+  dest[2] += v[2];
+}
+
+
+void ivec_ScaledAdd( ivec dest, int k, ivec v )
+{
+  dest[0] += k * v[0];
+  dest[1] += k * v[1];
+  dest[2] += k * v[2];
+}
+
+
+
+void ivec_Max( ivec res, ivec v1, ivec v2 )
+{
+  res[0] = MAX( v1[0], v2[0] );
+  res[1] = MAX( v1[1], v2[1] );
+  res[2] = MAX( v1[2], v2[2] );
+}
+
+
+void ivec_Max3( ivec res, ivec v1, ivec v2, ivec v3 )
+{
+  res[0] = MAX3( v1[0], v2[0], v3[0] );
+  res[1] = MAX3( v1[1], v2[1], v3[1] );
+  res[2] = MAX3( v1[2], v2[2], v3[2] );
+}
+
diff --git a/src/USER-REAXC/reaxc_vector.h b/src/USER-REAXC/reaxc_vector.h
new file mode 100644
index 0000000000..3771406478
--- /dev/null
+++ b/src/USER-REAXC/reaxc_vector.h
@@ -0,0 +1,89 @@
+/*----------------------------------------------------------------------
+  PuReMD - Purdue ReaxFF Molecular Dynamics Program
+  
+  Copyright (2010) Purdue University
+  Hasan Metin Aktulga, haktulga@cs.purdue.edu
+  Joseph Fogarty, jcfogart@mail.usf.edu
+  Sagar Pandit, pandit@usf.edu
+  Ananth Y Grama, ayg@cs.purdue.edu
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of 
+  the License, or (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+  See the GNU General Public License for more details:
+  <http://www.gnu.org/licenses/>.
+  ----------------------------------------------------------------------*/
+
+#ifndef __VECTOR_H_
+#define __VECTOR_H_
+
+#include "reaxc_types.h"
+#include "reaxc_defs.h"
+
+int  Vector_isZero( real*, int );
+void Vector_MakeZero( real*, int );
+void Vector_Copy( real*, real*, int );
+void Vector_Scale( real*, real, real*, int );
+void Vector_Sum( real*, real, real*, real, real*, int );
+void Vector_Add( real*, real, real*, int );
+real Dot( real*, real*, int );
+real Norm( real*, int );
+void Vector_Print( FILE*, char*, real*, int );
+
+void rvec_Copy( rvec, rvec );
+void rvec_Scale( rvec, real, rvec );
+void rvec_Add( rvec, rvec );
+void rvec_ScaledAdd( rvec, real, rvec );
+void rvec_Sum( rvec, rvec, rvec );
+void rvec_ScaledSum( rvec, real, rvec, real, rvec );
+real rvec_Dot( rvec, rvec );
+real rvec_ScaledDot( real, rvec, real, rvec );
+void rvec_Multiply( rvec, rvec, rvec );
+void rvec_iMultiply( rvec, ivec, rvec );
+void rvec_Divide( rvec, rvec, rvec );
+void rvec_iDivide( rvec, rvec, ivec );
+void rvec_Invert( rvec, rvec );
+void rvec_Cross( rvec, rvec, rvec );
+void rvec_OuterProduct( rtensor, rvec, rvec );
+real rvec_Norm_Sqr( rvec );
+real rvec_Norm( rvec );
+int  rvec_isZero( rvec );
+void rvec_MakeZero( rvec );
+void rvec_Random( rvec );
+
+void rtensor_MakeZero( rtensor );
+void rtensor_Multiply( rtensor, rtensor, rtensor );
+void rtensor_MatVec( rvec, rtensor, rvec );
+void rtensor_Scale( rtensor, real, rtensor );
+void rtensor_Add( rtensor, rtensor );
+void rtensor_ScaledAdd( rtensor, real, rtensor );
+void rtensor_Sum( rtensor, rtensor, rtensor );
+void rtensor_ScaledSum( rtensor, real, rtensor, real, rtensor );
+void rtensor_Scale( rtensor, real, rtensor );
+void rtensor_Copy( rtensor, rtensor );
+void rtensor_Identity( rtensor );
+void rtensor_Transpose( rtensor, rtensor );
+real rtensor_Det( rtensor );
+real rtensor_Trace( rtensor );
+
+void Print_rTensor(FILE*,rtensor);
+
+int  ivec_isZero( ivec );
+int  ivec_isEqual( ivec, ivec );
+void ivec_MakeZero( ivec );
+void ivec_Copy( ivec, ivec );
+void ivec_Scale( ivec, real, ivec );
+void ivec_rScale( ivec, real, rvec );
+void ivec_Sum( ivec, ivec, ivec );
+void ivec_ScaledSum( ivec, int, ivec, int, ivec );
+void ivec_Add( ivec, ivec );
+void ivec_ScaledAdd( ivec, int, ivec );
+void ivec_Max( ivec, ivec, ivec );
+void ivec_Max3( ivec, ivec, ivec, ivec );
+
+#endif
-- 
GitLab