diff --git a/src/GRANULAR/fix_pour.h b/src/GRANULAR/fix_pour.h
index 240937d4a..0478f897c 100644
--- a/src/GRANULAR/fix_pour.h
+++ b/src/GRANULAR/fix_pour.h
@@ -1,159 +1,159 @@
 /* -*- c++ -*- ----------------------------------------------------------
    LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
    http://lammps.sandia.gov, Sandia National Laboratories
    Steve Plimpton, sjplimp@sandia.gov
 
    Copyright (2003) Sandia Corporation.  Under the terms of Contract
    DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
    certain rights in this software.  This software is distributed under
    the GNU General Public License.
 
    See the README file in the top-level LAMMPS directory.
 ------------------------------------------------------------------------- */
 
 #ifdef FIX_CLASS
 
 FixStyle(pour,FixPour)
 
 #else
 
 #ifndef LMP_FIX_POUR_H
 #define LMP_FIX_POUR_H
 
 #include "fix.h"
 
 namespace LAMMPS_NS {
 
 class FixPour : public Fix {
   friend class PairGranHertzHistory;
   friend class PairGranHertzHistoryOMP;
   friend class PairGranHooke;
   friend class PairGranHookeOMP;
   friend class PairGranHookeHistory;
+  friend class PairGranHookeHistory2;
   friend class PairGranHookeHistoryOMP;
   friend class PairGranHookeCuda;
 
  public:
   FixPour(class LAMMPS *, int, char **);
   ~FixPour();
   int setmask();
   void init();
   void pre_exchange();
   void reset_dt();
 
  private:
   int ninsert,ntype,seed;
   int dstyle,npoly;
   double radius_one,radius_max;
   double radius_lo,radius_hi;
   double *radius_poly,*frac_poly;
   double density_lo,density_hi;
   double volfrac;
   int maxattempt;
   int region_style;
   double rate;
   double vxlo,vxhi,vylo,vyhi,vy,vz;
   double xlo,xhi,ylo,yhi,zlo,zhi;
   double xc,yc,rc;
   double grav;
 
   int me,nprocs;
   int *recvcounts,*displs;
   int nfreq,nfirst,ninserted,nper;
   double lo_current,hi_current;
-  class FixShearHistory *fix_history;
   class RanPark *random;
 
   int overlap(int);
   void xyz_random(double, double *);
   double radius_sample();
 };
 
 }
 
 #endif
 #endif
 
 /* ERROR/WARNING messages:
 
 E: Illegal ... command
 
 Self-explanatory.  Check the input script syntax and compare to the
 documentation for the command.  You can use -echo screen as a
 command-line option when running LAMMPS to see the offending line.
 
 E: Fix pour requires atom attributes radius, rmass
 
 The atom style defined does not have these attributes.
 
 E: Fix pour region ID does not exist
 
 Self-explanatory.
 
 E: Fix pour polydisperse fractions do not sum to 1.0
 
 UNDOCUMENTED
 
 E: Must specify a region in fix pour
 
 The region keyword must be specified with this fix.
 
 E: Fix pour region does not support a bounding box
 
 Not all regions represent bounded volumes.  You cannot use
 such a region with the fix pour command.
 
 E: Fix pour region cannot be dynamic
 
 Only static regions can be used with fix pour.
 
 E: Insertion region extends outside simulation box
 
 Region specified with fix pour command extends outside the global
 simulation box.
 
 E: Must use a z-axis cylinder with fix pour
 
 The axis of the cylinder region used with the fix pour command must
 be oriented along the z dimension.
 
 E: Must use a block or cylinder region with fix pour
 
 Self-explanatory.
 
 E: Must use a block region with fix pour for 2d simulations
 
 Self-explanatory.
 
 E: No fix gravity defined for fix pour
 
 Cannot add poured particles without gravity to move them.
 
 E: Cannot use fix pour with triclinic box
 
 This feature is not yet supported.
 
 E: Gravity must point in -z to use with fix pour in 3d
 
 Gravity must be pointing "down" in a 3d box, i.e. theta = 180.0.
 
 E: Gravity must point in -y to use with fix pour in 2d
 
 Gravity must be pointing "down" in a 2d box.
 
 E: Gravity changed since fix pour was created
 
 Gravity must be static and not dynamic for use with fix pour.
 
 W: Less insertions than requested
 
 Less atom insertions occurred on this timestep due to the fix pour
 command than were scheduled.  This is probably because there were too
 many overlaps detected.
 
 E: Cannot change timestep with fix pour
 
 This fix pre-computes some values based on the timestep, so it cannot
 be changed during a simulation run.
 
 */
diff --git a/src/MANYBODY/pair_airebo.cpp b/src/MANYBODY/pair_airebo.cpp
index fa01ac15a..34e4051b1 100644
--- a/src/MANYBODY/pair_airebo.cpp
+++ b/src/MANYBODY/pair_airebo.cpp
@@ -1,4205 +1,4199 @@
 /* ----------------------------------------------------------------------
    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: Ase Henry (MIT)
    Bugfixes and optimizations:
      Marcel Fallet & Steve Stuart (Clemson), Axel Kohlmeyer (Temple U)
 ------------------------------------------------------------------------- */
 
 #include "math.h"
 #include "stdio.h"
 #include "stdlib.h"
 #include "string.h"
 #include "mpi.h"
 #include "pair_airebo.h"
 #include "atom.h"
 #include "neighbor.h"
 #include "neigh_request.h"
 #include "force.h"
 #include "comm.h"
 #include "neighbor.h"
 #include "neigh_list.h"
 #include "neigh_request.h"
+#include "my_page.h"
 #include "math_const.h"
 #include "math_special.h"
 #include "memory.h"
 #include "error.h"
 
 using namespace LAMMPS_NS;
 using namespace MathConst;
 using namespace MathSpecial;
 
 #define MAXLINE 1024
 #define TOL 1.0e-9
 #define PGDELTA 1
 
 /* ---------------------------------------------------------------------- */
 
 PairAIREBO::PairAIREBO(LAMMPS *lmp) : Pair(lmp)
 {
   single_enable = 0;
   one_coeff = 1;
   ghostneigh = 1;
 
   maxlocal = 0;
   REBO_numneigh = NULL;
   REBO_firstneigh = NULL;
-  maxpage = 0;
-  pages = NULL;
+  ipage = NULL;
+  pgsize = oneatom = 0;
+
   nC = nH = NULL;
   manybody_flag = 1;
 }
 
 /* ----------------------------------------------------------------------
    check if allocated, since class can be destructed when incomplete
 ------------------------------------------------------------------------- */
 
 PairAIREBO::~PairAIREBO()
 {
   memory->destroy(REBO_numneigh);
   memory->sfree(REBO_firstneigh);
-  for (int i = 0; i < maxpage; i++) memory->destroy(pages[i]);
-  memory->sfree(pages);
+  delete[] ipage;
   memory->destroy(nC);
   memory->destroy(nH);
 
   if (allocated) {
     memory->destroy(setflag);
     memory->destroy(cutsq);
     memory->destroy(cutghost);
 
     memory->destroy(cutljsq);
     memory->destroy(lj1);
     memory->destroy(lj2);
     memory->destroy(lj3);
     memory->destroy(lj4);
     delete [] map;
   }
 }
 
 /* ---------------------------------------------------------------------- */
 
 void PairAIREBO::compute(int eflag, int vflag)
 {
   if (eflag || vflag) ev_setup(eflag,vflag);
   else evflag = vflag_fdotr = vflag_atom = 0;
 
   REBO_neigh();
   FREBO(eflag,vflag);
   if (ljflag) FLJ(eflag,vflag);
   if (torflag) TORSION(eflag,vflag);
 
   if (vflag_fdotr) virial_fdotr_compute();
 }
 
 /* ----------------------------------------------------------------------
    allocate all arrays
 ------------------------------------------------------------------------- */
 
 void PairAIREBO::allocate()
 {
   allocated = 1;
   int n = atom->ntypes;
 
   memory->create(setflag,n+1,n+1,"pair:setflag");
   for (int i = 1; i <= n; i++)
     for (int j = i; j <= n; j++)
       setflag[i][j] = 0;
 
   memory->create(cutsq,n+1,n+1,"pair:cutsq");
   memory->create(cutghost,n+1,n+1,"pair:cutghost");
 
   // only sized by C,H = 2 types
 
   memory->create(cutljsq,2,2,"pair:cutljsq");
   memory->create(lj1,2,2,"pair:lj1");
   memory->create(lj2,2,2,"pair:lj2");
   memory->create(lj3,2,2,"pair:lj3");
   memory->create(lj4,2,2,"pair:lj4");
 
   map = new int[n+1];
 }
 
 /* ----------------------------------------------------------------------
    global settings
 ------------------------------------------------------------------------- */
 
 void PairAIREBO::settings(int narg, char **arg)
 {
   if (narg != 1 && narg != 3) error->all(FLERR,"Illegal pair_style command");
 
   cutlj = force->numeric(FLERR,arg[0]);
 
   ljflag = torflag = 1;
   if (narg == 3) {
     ljflag = force->inumeric(FLERR,arg[1]);
     torflag = force->inumeric(FLERR,arg[2]);
   }
 }
 
 /* ----------------------------------------------------------------------
    set coeffs for one or more type pairs
 ------------------------------------------------------------------------- */
 
 void PairAIREBO::coeff(int narg, char **arg)
 {
   if (!allocated) allocate();
 
   if (narg != 3 + atom->ntypes)
     error->all(FLERR,"Incorrect args for pair coefficients");
 
   // insure I,J args are * *
 
   if (strcmp(arg[0],"*") != 0 || strcmp(arg[1],"*") != 0)
     error->all(FLERR,"Incorrect args for pair coefficients");
 
   // read args that map atom types to C and H
   // map[i] = which element (0,1) the Ith atom type is, -1 if NULL
 
   for (int i = 3; i < narg; i++) {
     if (strcmp(arg[i],"NULL") == 0) {
       map[i-2] = -1;
       continue;
     } else if (strcmp(arg[i],"C") == 0) {
       map[i-2] = 0;
     } else if (strcmp(arg[i],"H") == 0) {
       map[i-2] = 1;
     } else error->all(FLERR,"Incorrect args for pair coefficients");
   }
 
   // read potential file and initialize fitting splines
 
   read_file(arg[2]);
   spline_init();
 
   // clear setflag since coeff() called once with I,J = * *
 
   int n = atom->ntypes;
   for (int i = 1; i <= n; i++)
     for (int j = i; j <= n; j++)
       setflag[i][j] = 0;
 
   // set setflag i,j for type pairs where both are mapped to elements
 
   int count = 0;
   for (int i = 1; i <= n; i++)
     for (int j = i; j <= n; j++)
       if (map[i] >= 0 && map[j] >= 0) {
         setflag[i][j] = 1;
         count++;
       }
 
   if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
 }
 
 /* ----------------------------------------------------------------------
    init specific to this pair style
 ------------------------------------------------------------------------- */
 
 void PairAIREBO::init_style()
 {
   if (atom->tag_enable == 0)
     error->all(FLERR,"Pair style AIREBO requires atom IDs");
   if (force->newton_pair == 0)
     error->all(FLERR,"Pair style AIREBO requires newton pair on");
 
   // need a full neighbor list, including neighbors of ghosts
 
   int irequest = neighbor->request(this);
   neighbor->requests[irequest]->half = 0;
   neighbor->requests[irequest]->full = 1;
   neighbor->requests[irequest]->ghost = 1;
 
-  // local REBO neighbor list memory
+  // local REBO neighbor list
+  // create pages if first time or if neighbor pgsize/oneatom has changed
+
+  int create = 0;
+  if (ipage == NULL) create = 1;
+  if (pgsize != neighbor->pgsize) create = 1;
+  if (oneatom != neighbor->oneatom) create = 1;
 
-  pgsize = neighbor->pgsize;
-  oneatom = neighbor->oneatom;
-  if (maxpage == 0) add_pages();
+  if (create) {
+    pgsize = neighbor->pgsize;
+    oneatom = neighbor->oneatom;
+
+    int nmypage= comm->nthreads;
+    ipage = new MyPage<int>[nmypage];
+    for (int i=0; i < nmypage; ++i)
+      ipage[i].init(oneatom,pgsize,PGDELTA);
+  }
 }
 
 /* ----------------------------------------------------------------------
    init for one type pair i,j and corresponding j,i
 ------------------------------------------------------------------------- */
 
 double PairAIREBO::init_one(int i, int j)
 {
   if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
 
   // convert to C,H types
 
   int ii = map[i];
   int jj = map[j];
 
   // use C-C values for these cutoffs since C atoms are biggest
 
   // cut3rebo = 3 REBO distances
 
   cut3rebo = 3.0 * rcmax[0][0];
 
   // cutljrebosq = furthest distance from an owned atom a ghost atom can be
   //               to need its REBO neighs computed
   // interaction = M-K-I-J-L-N with I = owned and J = ghost
   //   this insures N is in the REBO neigh list of L
   //   since I-J < rcLJmax and J-L < rmax
 
   double cutljrebo = rcLJmax[0][0] + rcmax[0][0];
   cutljrebosq = cutljrebo * cutljrebo;
 
   // cutmax = furthest distance from an owned atom
   //          at which another atom will feel force, i.e. the ghost cutoff
   // for REBO term in potential:
   //   interaction = M-K-I-J-L-N with I = owned and J = ghost
   //   I to N is max distance = 3 REBO distances
   // for LJ term in potential:
   //   short interaction = M-K-I-J-L-N with I = owned, J = ghost, I-J < rcLJmax
   //   rcLJmax + 2*rcmax, since I-J < rcLJmax and J-L,L-N = REBO distances
   //   long interaction = I-J with I = owned and J = ghost
   //   cutlj*sigma, since I-J < LJ cutoff
   // cutghost = REBO cutoff used in REBO_neigh() for neighbors of ghosts
 
   double cutmax = cut3rebo;
   if (ljflag) {
     cutmax = MAX(cutmax,rcLJmax[0][0] + 2.0*rcmax[0][0]);
     cutmax = MAX(cutmax,cutlj*sigma[0][0]);
   }
 
   cutghost[i][j] = rcmax[ii][jj];
   cutljsq[ii][jj] = cutlj*sigma[ii][jj] * cutlj*sigma[ii][jj];
   lj1[ii][jj] = 48.0 * epsilon[ii][jj] * pow(sigma[ii][jj],12.0);
   lj2[ii][jj] = 24.0 * epsilon[ii][jj] * pow(sigma[ii][jj],6.0);
   lj3[ii][jj] = 4.0 * epsilon[ii][jj] * pow(sigma[ii][jj],12.0);
   lj4[ii][jj] = 4.0 * epsilon[ii][jj] * pow(sigma[ii][jj],6.0);
 
   cutghost[j][i] = cutghost[i][j];
   cutljsq[jj][ii] = cutljsq[ii][jj];
   lj1[jj][ii] = lj1[ii][jj];
   lj2[jj][ii] = lj2[ii][jj];
   lj3[jj][ii] = lj3[ii][jj];
   lj4[jj][ii] = lj4[ii][jj];
 
   return cutmax;
 }
 
 /* ----------------------------------------------------------------------
    create REBO neighbor list from main neighbor list
    REBO neighbor list stores neighbors of ghost atoms
 ------------------------------------------------------------------------- */
 
 void PairAIREBO::REBO_neigh()
 {
   int i,j,ii,jj,n,allnum,jnum,itype,jtype;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq,dS;
   int *ilist,*jlist,*numneigh,**firstneigh;
   int *neighptr;
 
   double **x = atom->x;
   int *type = atom->type;
   int nlocal = atom->nlocal;
   int nall = nlocal + atom->nghost;
 
   if (atom->nmax > maxlocal) {
     maxlocal = atom->nmax;
     memory->destroy(REBO_numneigh);
     memory->sfree(REBO_firstneigh);
     memory->destroy(nC);
     memory->destroy(nH);
     memory->create(REBO_numneigh,maxlocal,"AIREBO:numneigh");
     REBO_firstneigh = (int **) memory->smalloc(maxlocal*sizeof(int *),
                                                "AIREBO:firstneigh");
     memory->create(nC,maxlocal,"AIREBO:nC");
     memory->create(nH,maxlocal,"AIREBO:nH");
   }
 
   allnum = list->inum + list->gnum;
   ilist = list->ilist;
   numneigh = list->numneigh;
   firstneigh = list->firstneigh;
 
   // store all REBO neighs of owned and ghost atoms
   // scan full neighbor list of I
 
-  int npage = 0;
-  int npnt = 0;
+  ipage->reset();
 
   for (ii = 0; ii < allnum; ii++) {
     i = ilist[ii];
 
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage++;
-      if (npage == maxpage) add_pages();
-    }
-    neighptr = &pages[npage][npnt];
     n = 0;
+    neighptr = ipage->vget();
 
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
     itype = map[type[i]];
     nC[i] = nH[i] = 0.0;
     jlist = firstneigh[i];
     jnum = numneigh[i];
 
     for (jj = 0; jj < jnum; jj++) {
       j = jlist[jj];
       j &= NEIGHMASK;
       jtype = map[type[j]];
       delx = xtmp - x[j][0];
       dely = ytmp - x[j][1];
       delz = ztmp - x[j][2];
       rsq = delx*delx + dely*dely + delz*delz;
 
       if (rsq < rcmaxsq[itype][jtype]) {
         neighptr[n++] = j;
         if (jtype == 0)
           nC[i] += Sp(sqrt(rsq),rcmin[itype][jtype],rcmax[itype][jtype],dS);
         else
           nH[i] += Sp(sqrt(rsq),rcmin[itype][jtype],rcmax[itype][jtype],dS);
       }
     }
 
     REBO_firstneigh[i] = neighptr;
     REBO_numneigh[i] = n;
-    npnt += n;
-    if (npnt >= pgsize)
-      error->one(FLERR,
-                 "Neighbor list overflow, boost neigh_modify one or page");
+    ipage->vgot(n);
+    if (ipage->status())
+      error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
 }
 
 /* ----------------------------------------------------------------------
    REBO forces and energy
 ------------------------------------------------------------------------- */
 
 void PairAIREBO::FREBO(int eflag, int vflag)
 {
   int i,j,k,m,ii,inum,itype,jtype,itag,jtag;
   double delx,dely,delz,evdwl,fpair,xtmp,ytmp,ztmp;
   double rsq,rij,wij;
   double Qij,Aij,alphaij,VR,pre,dVRdi,VA,term,bij,dVAdi,dVA;
   double dwij,del[3];
   int *ilist,*REBO_neighs;
 
   evdwl = 0.0;
 
   double **x = atom->x;
   double **f = atom->f;
   int *type = atom->type;
   int *tag = atom->tag;
   int nlocal = atom->nlocal;
   int newton_pair = force->newton_pair;
 
   inum = list->inum;
   ilist = list->ilist;
 
   // two-body interactions from REBO neighbor list, skip half of them
 
   for (ii = 0; ii < inum; ii++) {
     i = ilist[ii];
     itag = tag[i];
     itype = map[type[i]];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
     REBO_neighs = REBO_firstneigh[i];
 
     for (k = 0; k < REBO_numneigh[i]; k++) {
       j = REBO_neighs[k];
       jtag = tag[j];
 
       if (itag > jtag) {
         if ((itag+jtag) % 2 == 0) continue;
       } else if (itag < jtag) {
         if ((itag+jtag) % 2 == 1) continue;
       } else {
         if (x[j][2] < ztmp) continue;
         if (x[j][2] == ztmp && x[j][1] < ytmp) continue;
         if (x[j][2] == ztmp && x[j][1] == ytmp && x[j][0] < xtmp) continue;
       }
 
       jtype = map[type[j]];
 
       delx = x[i][0] - x[j][0];
       dely = x[i][1] - x[j][1];
       delz = x[i][2] - x[j][2];
       rsq = delx*delx + dely*dely + delz*delz;
       rij = sqrt(rsq);
       wij = Sp(rij,rcmin[itype][jtype],rcmax[itype][jtype],dwij);
       if (wij <= TOL) continue;
 
       Qij = Q[itype][jtype];
       Aij = A[itype][jtype];
       alphaij = alpha[itype][jtype];
 
       VR = wij*(1.0+(Qij/rij)) * Aij*exp(-alphaij*rij);
       pre = wij*Aij * exp(-alphaij*rij);
       dVRdi = pre * ((-alphaij)-(Qij/rsq)-(Qij*alphaij/rij));
       dVRdi += VR/wij * dwij;
 
       VA = dVA = 0.0;
       for (m = 0; m < 3; m++) {
         term = -wij * BIJc[itype][jtype][m] * exp(-Beta[itype][jtype][m]*rij);
         VA += term;
         dVA += -Beta[itype][jtype][m] * term;
       }
       dVA += VA/wij * dwij;
       del[0] = delx;
       del[1] = dely;
       del[2] = delz;
       bij = bondorder(i,j,del,rij,VA,f,vflag_atom);
       dVAdi = bij*dVA;
 
       fpair = -(dVRdi+dVAdi) / rij;
       f[i][0] += delx*fpair;
       f[i][1] += dely*fpair;
       f[i][2] += delz*fpair;
       f[j][0] -= delx*fpair;
       f[j][1] -= dely*fpair;
       f[j][2] -= delz*fpair;
 
       if (eflag) evdwl = VR + bij*VA;
       if (evflag) ev_tally(i,j,nlocal,newton_pair,
                            evdwl,0.0,fpair,delx,dely,delz);
     }
   }
 }
 
 /* ----------------------------------------------------------------------
    compute LJ forces and energy
    find 3- and 4-step paths between atoms I,J via REBO neighbor lists
 ------------------------------------------------------------------------- */
 
 void PairAIREBO::FLJ(int eflag, int vflag)
 {
   int i,j,k,m,ii,jj,kk,mm,inum,jnum,itype,jtype,ktype,mtype,itag,jtag;
   int atomi,atomj,atomk,atomm;
   int testpath,npath,done;
   double evdwl,fpair,xtmp,ytmp,ztmp;
   double rsq,best,wik,wkm,cij,rij,dwij,dwik,dwkj,dwkm,dwmj;
   double delij[3],rijsq,delik[3],rik,deljk[3];
   double rkj,wkj,dC,VLJ,dVLJ,VA,Str,dStr,Stb;
   double vdw,slw,dvdw,dslw,drij,swidth,tee,tee2;
   double rljmin,rljmax,sigcut,sigmin,sigwid;
   double delkm[3],rkm,deljm[3],rmj,wmj,r2inv,r6inv,scale,delscale[3];
   int *ilist,*jlist,*numneigh,**firstneigh;
   int *REBO_neighs_i,*REBO_neighs_k;
   double delikS[3],deljkS[3],delkmS[3],deljmS[3],delimS[3];
   double rikS,rkjS,rkmS,rmjS,wikS,dwikS;
   double wkjS,dwkjS,wkmS,dwkmS,wmjS,dwmjS;
   double fpair1,fpair2,fpair3;
   double fi[3],fj[3],fk[3],fm[3];
 
   // I-J interaction from full neighbor list
   // skip 1/2 of interactions since only consider each pair once
 
   evdwl = 0.0;
   rljmin = 0.0;
   rljmax = 0.0;
   sigcut = 0.0;
   sigmin = 0.0;
   sigwid = 0.0;
 
 
   double **x = atom->x;
   double **f = atom->f;
   int *tag = atom->tag;
   int *type = atom->type;
   int nlocal = atom->nlocal;
   int newton_pair = force->newton_pair;
 
   inum = list->inum;
   ilist = list->ilist;
   numneigh = list->numneigh;
   firstneigh = list->firstneigh;
 
   // loop over neighbors of my atoms
 
   for (ii = 0; ii < inum; ii++) {
     i = ilist[ii];
     itag = tag[i];
     itype = map[type[i]];
     atomi = i;
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
     jlist = firstneigh[i];
     jnum = numneigh[i];
 
     for (jj = 0; jj < jnum; jj++) {
       j = jlist[jj];
       j &= NEIGHMASK;
       jtag = tag[j];
 
       if (itag > jtag) {
         if ((itag+jtag) % 2 == 0) continue;
       } else if (itag < jtag) {
         if ((itag+jtag) % 2 == 1) continue;
       } else {
         if (x[j][2] < ztmp) continue;
         if (x[j][2] == ztmp && x[j][1] < ytmp) continue;
         if (x[j][2] == ztmp && x[j][1] == ytmp && x[j][0] < xtmp) continue;
       }
 
       jtype = map[type[j]];
       atomj = j;
 
       delij[0] = xtmp - x[j][0];
       delij[1] = ytmp - x[j][1];
       delij[2] = ztmp - x[j][2];
       rijsq = delij[0]*delij[0] + delij[1]*delij[1] + delij[2]*delij[2];
 
       // if outside of LJ cutoff, skip
       // if outside of 4-path cutoff, best = 0.0, no need to test paths
       // if outside of 2-path cutoff but inside 4-path cutoff,
       //   best = 0.0, test 3-,4-paths
       // if inside 2-path cutoff, best = wij, only test 3-,4-paths if best < 1
 
       if (rijsq >= cutljsq[itype][jtype]) continue;
       rij = sqrt(rijsq);
       if (rij >= cut3rebo) {
         best = 0.0;
         testpath = 0;
       } else if (rij >= rcmax[itype][jtype]) {
         best = 0.0;
         testpath = 1;
       } else {
         best = Sp(rij,rcmin[itype][jtype],rcmax[itype][jtype],dwij);
         npath = 2;
         if (best < 1.0) testpath = 1;
         else testpath = 0;
       }
 
       done = 0;
       if (testpath) {
 
         // test all 3-body paths = I-K-J
         // I-K interactions come from atom I's REBO neighbors
         // if wik > current best, compute wkj
         // if best = 1.0, done
 
         REBO_neighs_i = REBO_firstneigh[i];
         for (kk = 0; kk < REBO_numneigh[i] && done==0; kk++) {
           k = REBO_neighs_i[kk];
           if (k == j) continue;
           ktype = map[type[k]];
 
           delik[0] = x[i][0] - x[k][0];
           delik[1] = x[i][1] - x[k][1];
           delik[2] = x[i][2] - x[k][2];
           rsq = delik[0]*delik[0] + delik[1]*delik[1] + delik[2]*delik[2];
           if (rsq < rcmaxsq[itype][ktype]) {
             rik = sqrt(rsq);
             wik = Sp(rik,rcmin[itype][ktype],rcmax[itype][ktype],dwik);
           } else wik = 0.0;
 
           if (wik > best) {
             deljk[0] = x[j][0] - x[k][0];
             deljk[1] = x[j][1] - x[k][1];
             deljk[2] = x[j][2] - x[k][2];
             rsq = deljk[0]*deljk[0] + deljk[1]*deljk[1] + deljk[2]*deljk[2];
             if (rsq < rcmaxsq[ktype][jtype]) {
               rkj = sqrt(rsq);
               wkj = Sp(rkj,rcmin[ktype][jtype],rcmax[ktype][jtype],dwkj);
               if (wik*wkj > best) {
                 best = wik*wkj;
                 npath = 3;
                  atomk = k;
                     delikS[0] = delik[0];
                     delikS[1] = delik[1];
                     delikS[2] = delik[2];
                     rikS = rik;
                     wikS = wik;
                     dwikS = dwik;
                     deljkS[0] = deljk[0];
                     deljkS[1] = deljk[1];
                     deljkS[2] = deljk[2];
                     rkjS = rkj;
                     wkjS = wkj;
                     dwkjS = dwkj;
                 if (best == 1.0) {
                   done = 1;
                   break;
                 }
               }
             }
 
             // test all 4-body paths = I-K-M-J
             // K-M interactions come from atom K's REBO neighbors
             // if wik*wkm > current best, compute wmj
             // if best = 1.0, done
 
             REBO_neighs_k = REBO_firstneigh[k];
             for (mm = 0; mm < REBO_numneigh[k] && done==0; mm++) {
               m = REBO_neighs_k[mm];
               if (m == i || m == j) continue;
               mtype = map[type[m]];
               delkm[0] = x[k][0] - x[m][0];
               delkm[1] = x[k][1] - x[m][1];
               delkm[2] = x[k][2] - x[m][2];
               rsq = delkm[0]*delkm[0] + delkm[1]*delkm[1] + delkm[2]*delkm[2];
               if (rsq < rcmaxsq[ktype][mtype]) {
                 rkm = sqrt(rsq);
                 wkm = Sp(rkm,rcmin[ktype][mtype],rcmax[ktype][mtype],dwkm);
               } else wkm = 0.0;
 
               if (wik*wkm > best) {
                 deljm[0] = x[j][0] - x[m][0];
                 deljm[1] = x[j][1] - x[m][1];
                 deljm[2] = x[j][2] - x[m][2];
                 rsq = deljm[0]*deljm[0] + deljm[1]*deljm[1] +
                   deljm[2]*deljm[2];
                 if (rsq < rcmaxsq[mtype][jtype]) {
                   rmj = sqrt(rsq);
                   wmj = Sp(rmj,rcmin[mtype][jtype],rcmax[mtype][jtype],dwmj);
                   if (wik*wkm*wmj > best) {
                     best = wik*wkm*wmj;
                     npath = 4;
                     atomk = k;
                     delikS[0] = delik[0];
                     delikS[1] = delik[1];
                     delikS[2] = delik[2];
                     rikS = rik;
                     wikS = wik;
                     dwikS = dwik;
                     atomm = m;
                     delkmS[0] = delkm[0];
                     delkmS[1] = delkm[1];
                         delkmS[2] = delkm[2];
                     rkmS = rkm;
                     wkmS = wkm;
                     dwkmS = dwkm;
                     deljmS[0] = deljm[0];
                     deljmS[1] = deljm[1];
                        deljmS[2] = deljm[2];
                     rmjS = rmj;
                     wmjS = wmj;
                     dwmjS = dwmj;
                     if (best == 1.0) {
                       done = 1;
                       break;
                     }
                   }
                 }
               }
             }
           }
         }
       }
 
       cij = 1.0 - best;
       if (cij == 0.0) continue;
 
       // compute LJ forces and energy
 
       sigwid = 0.84;
       sigcut = 3.0;
       sigmin = sigcut - sigwid;
 
       rljmin = sigma[itype][jtype];
       rljmax = sigcut * rljmin;
       rljmin = sigmin * rljmin;
 
       if (rij > rljmax) {
         slw = 0.0;
         dslw = 0.0;
       } else if (rij > rljmin) {
         drij = rij - rljmin;
         swidth = rljmax - rljmin;
         tee = drij / swidth;
         tee2 = tee*tee;
         slw = 1.0 - tee2 * (3.0 - 2.0 * tee);
         dslw = 6.0 * tee * (1.0 - tee) / rij / swidth;
       } else {
         slw = 1.0;
         dslw = 0.0;
       }
 
       r2inv = 1.0/rijsq;
       r6inv = r2inv*r2inv*r2inv;
 
       vdw = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]);
       dvdw = -r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]) / rij;
 
       // VLJ now becomes vdw * slw, derivaties, etc.
 
       VLJ = vdw * slw;
       dVLJ = dvdw * slw + vdw * dslw;
 
       Str = Sp2(rij,rcLJmin[itype][jtype],rcLJmax[itype][jtype],dStr);
       VA = Str*cij*VLJ;
       if (Str > 0.0) {
         scale = rcmin[itype][jtype] / rij;
         delscale[0] = scale * delij[0];
         delscale[1] = scale * delij[1];
         delscale[2] = scale * delij[2];
         Stb = bondorderLJ(i,j,delscale,rcmin[itype][jtype],VA,
                           delij,rij,f,vflag_atom);
       } else Stb = 0.0;
 
       fpair = -(dStr * (Stb*cij*VLJ - cij*VLJ) +
                 dVLJ * (Str*Stb*cij + cij - Str*cij)) / rij;
 
       f[i][0] += delij[0]*fpair;
       f[i][1] += delij[1]*fpair;
       f[i][2] += delij[2]*fpair;
       f[j][0] -= delij[0]*fpair;
       f[j][1] -= delij[1]*fpair;
       f[j][2] -= delij[2]*fpair;
 
       if (eflag) evdwl = VA*Stb + (1.0-Str)*cij*VLJ;
       if (evflag) ev_tally(i,j,nlocal,newton_pair,
                            evdwl,0.0,fpair,delij[0],delij[1],delij[2]);
 
       if (cij < 1.0) {
         dC = Str*Stb*VLJ + (1.0-Str)*VLJ;
         if (npath == 2) {
           fpair = dC*dwij / rij;
           f[atomi][0] += delij[0]*fpair;
           f[atomi][1] += delij[1]*fpair;
           f[atomi][2] += delij[2]*fpair;
           f[atomj][0] -= delij[0]*fpair;
           f[atomj][1] -= delij[1]*fpair;
           f[atomj][2] -= delij[2]*fpair;
 
           if (vflag_atom) v_tally2(atomi,atomj,fpair,delij);
 
         } else if (npath == 3) {
           fpair1 = dC*dwikS*wkjS / rikS;
           fi[0] = delikS[0]*fpair1;
           fi[1] = delikS[1]*fpair1;
           fi[2] = delikS[2]*fpair1;
           fpair2 = dC*wikS*dwkjS / rkjS;
           fj[0] = deljkS[0]*fpair2;
           fj[1] = deljkS[1]*fpair2;
           fj[2] = deljkS[2]*fpair2;
 
           f[atomi][0] += fi[0];
           f[atomi][1] += fi[1];
           f[atomi][2] += fi[2];
           f[atomj][0] += fj[0];
           f[atomj][1] += fj[1];
           f[atomj][2] += fj[2];
           f[atomk][0] -= fi[0] + fj[0];
           f[atomk][1] -= fi[1] + fj[1];
           f[atomk][2] -= fi[2] + fj[2];
 
           if (vflag_atom)
             v_tally3(atomi,atomj,atomk,fi,fj,delikS,deljkS);
 
         } else {
           fpair1 = dC*dwikS*wkmS*wmjS / rikS;
           fi[0] = delikS[0]*fpair1;
           fi[1] = delikS[1]*fpair1;
           fi[2] = delikS[2]*fpair1;
 
           fpair2 = dC*wikS*dwkmS*wmjS / rkmS;
           fk[0] = delkmS[0]*fpair2 - fi[0];
           fk[1] = delkmS[1]*fpair2 - fi[1];
           fk[2] = delkmS[2]*fpair2 - fi[2];
 
           fpair3 = dC*wikS*wkmS*dwmjS / rmjS;
           fj[0] = deljmS[0]*fpair3;
           fj[1] = deljmS[1]*fpair3;
           fj[2] = deljmS[2]*fpair3;
 
           fm[0] = -delkmS[0]*fpair2 - fj[0];
           fm[1] = -delkmS[1]*fpair2 - fj[1];
           fm[2] = -delkmS[2]*fpair2 - fj[2];
 
           f[atomi][0] += fi[0];
           f[atomi][1] += fi[1];
           f[atomi][2] += fi[2];
           f[atomj][0] += fj[0];
           f[atomj][1] += fj[1];
           f[atomj][2] += fj[2];
           f[atomk][0] += fk[0];
           f[atomk][1] += fk[1];
           f[atomk][2] += fk[2];
           f[atomm][0] += fm[0];
           f[atomm][1] += fm[1];
           f[atomm][2] += fm[2];
 
           if (vflag_atom) {
             delimS[0] = delikS[0] + delkmS[0];
             delimS[1] = delikS[1] + delkmS[1];
             delimS[2] = delikS[2] + delkmS[2];
             v_tally4(atomi,atomj,atomk,atomm,fi,fj,fk,delimS,deljmS,delkmS);
           }
         }
       }
     }
   }
 }
 
 /* ----------------------------------------------------------------------
    torsional forces and energy
 ------------------------------------------------------------------------- */
 
 void PairAIREBO::TORSION(int eflag, int vflag)
 {
   int i,j,k,l,ii,inum,itag,jtag;
   double evdwl,fpair,xtmp,ytmp,ztmp;
   double cos321;
   double w21,dw21,cos234,w34,dw34;
   double cross321[3],cross321mag,cross234[3],cross234mag;
   double w23,dw23,cw2,ekijl,Ec;
   double cw,cwnum,cwnom;
   double rij,rij2,rik,rjl,tspjik,dtsjik,tspijl,dtsijl,costmp,fcpc;
   double sin321,sin234,rjk2,rik2,ril2,rjl2;
   double rjk,ril;
   double Vtors;
   double dndij[3],tmpvec[3],dndik[3],dndjl[3];
   double dcidij,dcidik,dcidjk,dcjdji,dcjdjl,dcjdil;
   double dsidij,dsidik,dsidjk,dsjdji,dsjdjl,dsjdil;
   double dxidij,dxidik,dxidjk,dxjdji,dxjdjl,dxjdil;
   double ddndij,ddndik,ddndjk,ddndjl,ddndil,dcwddn,dcwdn,dvpdcw,Ftmp[3];
   double del32[3],rsq,r32,del23[3],del21[3],r21;
   double deljk[3],del34[3],delil[3],delkl[3],r23,r34;
   double fi[3],fj[3],fk[3],fl[3];
   int itype,jtype,ktype,ltype,kk,ll,jj;
   int *ilist,*REBO_neighs_i,*REBO_neighs_j;
 
   double **x = atom->x;
   double **f = atom->f;
   int *type = atom->type;
   int *tag = atom->tag;
 
   inum = list->inum;
   ilist = list->ilist;
 
   for (ii = 0; ii < inum; ii++) {
     i = ilist[ii];
     itag = tag[i];
     itype = map[type[i]];
     if (itype != 0) continue;
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
     REBO_neighs_i = REBO_firstneigh[i];
 
     for (jj = 0; jj < REBO_numneigh[i]; jj++) {
       j = REBO_neighs_i[jj];
       jtag = tag[j];
 
       if (itag > jtag) {
         if ((itag+jtag) % 2 == 0) continue;
       } else if (itag < jtag) {
         if ((itag+jtag) % 2 == 1) continue;
       } else {
         if (x[j][2] < ztmp) continue;
         if (x[j][2] == ztmp && x[j][1] < ytmp) continue;
         if (x[j][2] == ztmp && x[j][1] == ytmp && x[j][0] < xtmp) continue;
       }
 
       jtype = map[type[j]];
       if (jtype != 0) continue;
 
       del32[0] = x[j][0]-x[i][0];
       del32[1] = x[j][1]-x[i][1];
       del32[2] = x[j][2]-x[i][2];
       rsq = del32[0]*del32[0] + del32[1]*del32[1] + del32[2]*del32[2];
       r32 = sqrt(rsq);
       del23[0] = -del32[0];
       del23[1] = -del32[1];
       del23[2] = -del32[2];
       r23 = r32;
       w23 = Sp(r23,rcmin[itype][jtype],rcmax[itype][jtype],dw23);
 
       for (kk = 0; kk < REBO_numneigh[i]; kk++) {
         k = REBO_neighs_i[kk];
         ktype = map[type[k]];
         if (k == j) continue;
         del21[0] = x[i][0]-x[k][0];
         del21[1] = x[i][1]-x[k][1];
         del21[2] = x[i][2]-x[k][2];
         rsq = del21[0]*del21[0] + del21[1]*del21[1] + del21[2]*del21[2];
         r21 = sqrt(rsq);
         cos321 = - ((del21[0]*del32[0]) + (del21[1]*del32[1]) +
                     (del21[2]*del32[2])) / (r21*r32);
         cos321 = MIN(cos321,1.0);
         cos321 = MAX(cos321,-1.0);
         sin321 = sqrt(1.0 - cos321*cos321);
         if (sin321 < TOL) continue;
 
         deljk[0] = del21[0]-del23[0];
         deljk[1] = del21[1]-del23[1];
         deljk[2] = del21[2]-del23[2];
         rjk2 = deljk[0]*deljk[0] + deljk[1]*deljk[1] + deljk[2]*deljk[2];
         rjk=sqrt(rjk2);
         rik2 = r21*r21;
         w21 = Sp(r21,rcmin[itype][ktype],rcmax[itype][ktype],dw21);
 
         rij = r32;
         rik = r21;
         rij2 = r32*r32;
         rik2 = r21*r21;
         costmp = 0.5*(rij2+rik2-rjk2)/rij/rik;
         tspjik = Sp2(costmp,thmin,thmax,dtsjik);
         dtsjik = -dtsjik;
 
         REBO_neighs_j = REBO_firstneigh[j];
         for (ll = 0; ll < REBO_numneigh[j]; ll++) {
           l = REBO_neighs_j[ll];
           ltype = map[type[l]];
           if (l == i || l == k) continue;
           del34[0] = x[j][0]-x[l][0];
           del34[1] = x[j][1]-x[l][1];
           del34[2] = x[j][2]-x[l][2];
           rsq = del34[0]*del34[0] + del34[1]*del34[1] + del34[2]*del34[2];
           r34 = sqrt(rsq);
           cos234 = (del32[0]*del34[0] + del32[1]*del34[1] +
                     del32[2]*del34[2]) / (r32*r34);
           cos234 = MIN(cos234,1.0);
           cos234 = MAX(cos234,-1.0);
           sin234 = sqrt(1.0 - cos234*cos234);
           if (sin234 < TOL) continue;
           w34 = Sp(r34,rcmin[jtype][ltype],rcmax[jtype][ltype],dw34);
           delil[0] = del23[0] + del34[0];
           delil[1] = del23[1] + del34[1];
           delil[2] = del23[2] + del34[2];
           ril2 = delil[0]*delil[0] + delil[1]*delil[1] + delil[2]*delil[2];
           ril=sqrt(ril2);
           rjl2 = r34*r34;
 
           rjl = r34;
           rjl2 = r34*r34;
           costmp = 0.5*(rij2+rjl2-ril2)/rij/rjl;
           tspijl = Sp2(costmp,thmin,thmax,dtsijl);
           dtsijl = -dtsijl; //need minus sign
           cross321[0] = (del32[1]*del21[2])-(del32[2]*del21[1]);
           cross321[1] = (del32[2]*del21[0])-(del32[0]*del21[2]);
           cross321[2] = (del32[0]*del21[1])-(del32[1]*del21[0]);
           cross321mag = sqrt(cross321[0]*cross321[0]+
                              cross321[1]*cross321[1]+
                              cross321[2]*cross321[2]);
           cross234[0] = (del23[1]*del34[2])-(del23[2]*del34[1]);
           cross234[1] = (del23[2]*del34[0])-(del23[0]*del34[2]);
           cross234[2] = (del23[0]*del34[1])-(del23[1]*del34[0]);
           cross234mag = sqrt(cross234[0]*cross234[0]+
                              cross234[1]*cross234[1]+
                              cross234[2]*cross234[2]);
           cwnum = (cross321[0]*cross234[0]) +
             (cross321[1]*cross234[1])+(cross321[2]*cross234[2]);
           cwnom = r21*r34*r32*r32*sin321*sin234;
           cw = cwnum/cwnom;
 
           cw2 = (.5*(1.0-cw));
           ekijl = epsilonT[ktype][ltype];
           Ec = 256.0*ekijl/405.0;
           Vtors = (Ec*(powint(cw2,5)))-(ekijl/10.0);
 
           if (eflag) evdwl = Vtors*w21*w23*w34*(1.0-tspjik)*(1.0-tspijl);
 
           dndij[0] = (cross234[1]*del21[2])-(cross234[2]*del21[1]);
           dndij[1] = (cross234[2]*del21[0])-(cross234[0]*del21[2]);
           dndij[2] = (cross234[0]*del21[1])-(cross234[1]*del21[0]);
 
           tmpvec[0] = (del34[1]*cross321[2])-(del34[2]*cross321[1]);
           tmpvec[1] = (del34[2]*cross321[0])-(del34[0]*cross321[2]);
           tmpvec[2] = (del34[0]*cross321[1])-(del34[1]*cross321[0]);
 
           dndij[0] = dndij[0]+tmpvec[0];
           dndij[1] = dndij[1]+tmpvec[1];
           dndij[2] = dndij[2]+tmpvec[2];
 
           dndik[0] = (del23[1]*cross234[2])-(del23[2]*cross234[1]);
           dndik[1] = (del23[2]*cross234[0])-(del23[0]*cross234[2]);
           dndik[2] = (del23[0]*cross234[1])-(del23[1]*cross234[0]);
 
           dndjl[0] = (cross321[1]*del23[2])-(cross321[2]*del23[1]);
           dndjl[1] = (cross321[2]*del23[0])-(cross321[0]*del23[2]);
           dndjl[2] = (cross321[0]*del23[1])-(cross321[1]*del23[0]);
 
           dcidij = ((r23*r23)-(r21*r21)+(rjk*rjk))/(2.0*r23*r23*r21);
           dcidik = ((r21*r21)-(r23*r23)+(rjk*rjk))/(2.0*r23*r21*r21);
           dcidjk = (-rjk)/(r23*r21);
           dcjdji = ((r23*r23)-(r34*r34)+(ril*ril))/(2.0*r23*r23*r34);
           dcjdjl = ((r34*r34)-(r23*r23)+(ril*ril))/(2.0*r23*r34*r34);
           dcjdil = (-ril)/(r23*r34);
 
           dsidij = (-cos321/sin321)*dcidij;
           dsidik = (-cos321/sin321)*dcidik;
           dsidjk = (-cos321/sin321)*dcidjk;
 
           dsjdji = (-cos234/sin234)*dcjdji;
           dsjdjl = (-cos234/sin234)*dcjdjl;
           dsjdil = (-cos234/sin234)*dcjdil;
 
           dxidij = (r21*sin321)+(r23*r21*dsidij);
           dxidik = (r23*sin321)+(r23*r21*dsidik);
           dxidjk = (r23*r21*dsidjk);
 
           dxjdji = (r34*sin234)+(r23*r34*dsjdji);
           dxjdjl = (r23*sin234)+(r23*r34*dsjdjl);
           dxjdil = (r23*r34*dsjdil);
 
           ddndij = (dxidij*cross234mag)+(cross321mag*dxjdji);
           ddndik = dxidik*cross234mag;
           ddndjk = dxidjk*cross234mag;
           ddndjl = cross321mag*dxjdjl;
           ddndil = cross321mag*dxjdil;
           dcwddn = -cwnum/(cwnom*cwnom);
           dcwdn = 1.0/cwnom;
           dvpdcw = (-1.0)*Ec*(-.5)*5.0*powint(cw2,4) *
             w23*w21*w34*(1.0-tspjik)*(1.0-tspijl);
 
           Ftmp[0] = dvpdcw*((dcwdn*dndij[0])+(dcwddn*ddndij*del23[0]/r23));
           Ftmp[1] = dvpdcw*((dcwdn*dndij[1])+(dcwddn*ddndij*del23[1]/r23));
           Ftmp[2] = dvpdcw*((dcwdn*dndij[2])+(dcwddn*ddndij*del23[2]/r23));
           fi[0] = Ftmp[0];
           fi[1] = Ftmp[1];
           fi[2] = Ftmp[2];
           fj[0] = -Ftmp[0];
           fj[1] = -Ftmp[1];
           fj[2] = -Ftmp[2];
 
           Ftmp[0] = dvpdcw*((dcwdn*dndik[0])+(dcwddn*ddndik*del21[0]/r21));
           Ftmp[1] = dvpdcw*((dcwdn*dndik[1])+(dcwddn*ddndik*del21[1]/r21));
           Ftmp[2] = dvpdcw*((dcwdn*dndik[2])+(dcwddn*ddndik*del21[2]/r21));
           fi[0] += Ftmp[0];
           fi[1] += Ftmp[1];
           fi[2] += Ftmp[2];
           fk[0] = -Ftmp[0];
           fk[1] = -Ftmp[1];
           fk[2] = -Ftmp[2];
 
           Ftmp[0] = (dvpdcw*dcwddn*ddndjk*deljk[0])/rjk;
           Ftmp[1] = (dvpdcw*dcwddn*ddndjk*deljk[1])/rjk;
           Ftmp[2] = (dvpdcw*dcwddn*ddndjk*deljk[2])/rjk;
           fj[0] += Ftmp[0];
           fj[1] += Ftmp[1];
           fj[2] += Ftmp[2];
           fk[0] -= Ftmp[0];
           fk[1] -= Ftmp[1];
           fk[2] -= Ftmp[2];
 
           Ftmp[0] = dvpdcw*((dcwdn*dndjl[0])+(dcwddn*ddndjl*del34[0]/r34));
           Ftmp[1] = dvpdcw*((dcwdn*dndjl[1])+(dcwddn*ddndjl*del34[1]/r34));
           Ftmp[2] = dvpdcw*((dcwdn*dndjl[2])+(dcwddn*ddndjl*del34[2]/r34));
           fj[0] += Ftmp[0];
           fj[1] += Ftmp[1];
           fj[2] += Ftmp[2];
           fl[0] = -Ftmp[0];
           fl[1] = -Ftmp[1];
           fl[2] = -Ftmp[2];
 
           Ftmp[0] = (dvpdcw*dcwddn*ddndil*delil[0])/ril;
           Ftmp[1] = (dvpdcw*dcwddn*ddndil*delil[1])/ril;
           Ftmp[2] = (dvpdcw*dcwddn*ddndil*delil[2])/ril;
           fi[0] += Ftmp[0];
           fi[1] += Ftmp[1];
           fi[2] += Ftmp[2];
           fl[0] -= Ftmp[0];
           fl[1] -= Ftmp[1];
           fl[2] -= Ftmp[2];
 
           // coordination forces
 
           fpair = Vtors*dw21*w23*w34*(1.0-tspjik)*(1.0-tspijl) / r21;
           fi[0] -= del21[0]*fpair;
           fi[1] -= del21[1]*fpair;
           fi[2] -= del21[2]*fpair;
           fk[0] += del21[0]*fpair;
           fk[1] += del21[1]*fpair;
           fk[2] += del21[2]*fpair;
 
           fpair = Vtors*w21*dw23*w34*(1.0-tspjik)*(1.0-tspijl) / r23;
           fi[0] -= del23[0]*fpair;
           fi[1] -= del23[1]*fpair;
           fi[2] -= del23[2]*fpair;
           fj[0] += del23[0]*fpair;
           fj[1] += del23[1]*fpair;
           fj[2] += del23[2]*fpair;
 
           fpair = Vtors*w21*w23*dw34*(1.0-tspjik)*(1.0-tspijl) / r34;
           fj[0] -= del34[0]*fpair;
           fj[1] -= del34[1]*fpair;
           fj[2] -= del34[2]*fpair;
           fl[0] += del34[0]*fpair;
           fl[1] += del34[1]*fpair;
           fl[2] += del34[2]*fpair;
 
           // additional cut off function forces
 
           fcpc = -Vtors*w21*w23*w34*dtsjik*(1.0-tspijl);
           fpair = fcpc*dcidij/rij;
           fi[0] += fpair*del23[0];
           fi[1] += fpair*del23[1];
           fi[2] += fpair*del23[2];
           fj[0] -= fpair*del23[0];
           fj[1] -= fpair*del23[1];
           fj[2] -= fpair*del23[2];
 
           fpair = fcpc*dcidik/rik;
           fi[0] += fpair*del21[0];
           fi[1] += fpair*del21[1];
           fi[2] += fpair*del21[2];
           fk[0] -= fpair*del21[0];
           fk[1] -= fpair*del21[1];
           fk[2] -= fpair*del21[2];
 
           fpair = fcpc*dcidjk/rjk;
           fj[0] += fpair*deljk[0];
           fj[1] += fpair*deljk[1];
           fj[2] += fpair*deljk[2];
           fk[0] -= fpair*deljk[0];
           fk[1] -= fpair*deljk[1];
           fk[2] -= fpair*deljk[2];
 
           fcpc = -Vtors*w21*w23*w34*(1.0-tspjik)*dtsijl;
           fpair = fcpc*dcjdji/rij;
           fi[0] += fpair*del23[0];
           fi[1] += fpair*del23[1];
           fi[2] += fpair*del23[2];
           fj[0] -= fpair*del23[0];
           fj[1] -= fpair*del23[1];
           fj[2] -= fpair*del23[2];
 
           fpair = fcpc*dcjdjl/rjl;
           fj[0] += fpair*del34[0];
           fj[1] += fpair*del34[1];
           fj[2] += fpair*del34[2];
           fl[0] -= fpair*del34[0];
           fl[1] -= fpair*del34[1];
           fl[2] -= fpair*del34[2];
 
           fpair = fcpc*dcjdil/ril;
           fi[0] += fpair*delil[0];
           fi[1] += fpair*delil[1];
           fi[2] += fpair*delil[2];
           fl[0] -= fpair*delil[0];
           fl[1] -= fpair*delil[1];
           fl[2] -= fpair*delil[2];
 
           // sum per-atom forces into atom force array
 
           f[i][0] += fi[0]; f[i][1] += fi[1]; f[i][2] += fi[2];
           f[j][0] += fj[0]; f[j][1] += fj[1]; f[j][2] += fj[2];
           f[k][0] += fk[0]; f[k][1] += fk[1]; f[k][2] += fk[2];
           f[l][0] += fl[0]; f[l][1] += fl[1]; f[l][2] += fl[2];
 
           if (evflag) {
             delkl[0] = delil[0] - del21[0];
             delkl[1] = delil[1] - del21[1];
             delkl[2] = delil[2] - del21[2];
             ev_tally4(i,j,k,l,evdwl,fi,fj,fk,delil,del34,delkl);
           }
         }
       }
     }
   }
 }
 
 /* ----------------------------------------------------------------------
    Bij function
 ------------------------------------------------------------------------- */
 
 double PairAIREBO::bondorder(int i, int j, double rij[3],
                              double rijmag, double VA,
                              double **f, int vflag_atom)
 {
   int atomi,atomj,k,n,l,atomk,atoml,atomn,atom1,atom2,atom3,atom4;
   int itype,jtype,ktype,ltype,ntype;
   double rik[3],rjl[3],rkn[3],rji[3],rki[3],rlj[3],rknmag,dNki,dwjl,bij;
   double NijC,NijH,NjiC,NjiH,wik,dwik,dwkn,wjl;
   double rikmag,rjlmag,cosjik,cosijl,g,tmp2,tmp3;
   double Etmp,pij,tmp,wij,dwij,NconjtmpI,NconjtmpJ,Nki,Nlj,dS;
   double lamdajik,lamdaijl,dgdc,dgdN,pji,Nijconj,piRC;
   double dcosjikdri[3],dcosijldri[3],dcosjikdrk[3];
   double dN2[2],dN3[3];
   double dcosjikdrj[3],dcosijldrj[3],dcosijldrl[3];
   double Tij;
   double r32[3],r32mag,cos321,r43[3],r13[3];
   double dNlj;
   double om1234,rln[3];
   double rlnmag,dwln,r23[3],r23mag,r21[3],r21mag;
   double w21,dw21,r34[3],r34mag,cos234,w34,dw34;
   double cross321[3],cross234[3],prefactor,SpN;
   double fcijpc,fcikpc,fcjlpc,fcjkpc,fcilpc;
   double dt2dik[3],dt2djl[3],dt2dij[3],aa,aaa1,aaa2,at2,cw,cwnum,cwnom;
   double sin321,sin234,rr,rijrik,rijrjl,rjk2,rik2,ril2,rjl2;
   double dctik,dctjk,dctjl,dctij,dctji,dctil,rik2i,rjl2i,sink2i,sinl2i;
   double rjk[3],ril[3],dt1dik,dt1djk,dt1djl,dt1dil,dt1dij;
   double F23[3],F12[3],F34[3],F31[3],F24[3],fi[3],fj[3],fk[3],fl[3];
   double f1[3],f2[3],f3[3],f4[4];
   double dcut321,PijS,PjiS;
   double rij2,tspjik,dtsjik,tspijl,dtsijl,costmp;
   int *REBO_neighs,*REBO_neighs_i,*REBO_neighs_j,*REBO_neighs_k,*REBO_neighs_l;
 
   double **x = atom->x;
   int *type = atom->type;
 
   atomi = i;
   atomj = j;
   itype = map[type[i]];
   jtype = map[type[j]];
   wij = Sp(rijmag,rcmin[itype][jtype],rcmax[itype][jtype],dwij);
   NijC = nC[i]-(wij*kronecker(jtype,0));
   NijH = nH[i]-(wij*kronecker(jtype,1));
   NjiC = nC[j]-(wij*kronecker(itype,0));
   NjiH = nH[j]-(wij*kronecker(itype,1));
   bij = 0.0;
   tmp = 0.0;
   tmp2 = 0.0;
   tmp3 = 0.0;
   dgdc = 0.0;
   dgdN = 0.0;
   NconjtmpI = 0.0;
   NconjtmpJ = 0.0;
   Etmp = 0.0;
 
   REBO_neighs = REBO_firstneigh[i];
   for (k = 0; k < REBO_numneigh[i]; k++) {
     atomk = REBO_neighs[k];
     if (atomk != atomj) {
       ktype = map[type[atomk]];
       rik[0] = x[atomi][0]-x[atomk][0];
       rik[1] = x[atomi][1]-x[atomk][1];
       rik[2] = x[atomi][2]-x[atomk][2];
       rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2]));
       lamdajik = 4.0*kronecker(itype,1) *
         ((rho[ktype][1]-rikmag)-(rho[jtype][1]-rijmag));
       wik = Sp(rikmag,rcmin[itype][ktype],rcmax[itype][ktype],dS);
       Nki = nC[atomk]-(wik*kronecker(itype,0))+nH[atomk] -
         (wik*kronecker(itype,1));
       cosjik = ((rij[0]*rik[0])+(rij[1]*rik[1])+(rij[2]*rik[2])) /
         (rijmag*rikmag);
       cosjik = MIN(cosjik,1.0);
       cosjik = MAX(cosjik,-1.0);
 
       // evaluate splines g and derivatives dg
 
       g = gSpline(cosjik,(NijC+NijH),itype,&dgdc,&dgdN);
       Etmp = Etmp+(wik*g*exp(lamdajik));
       tmp3 = tmp3+(wik*dgdN*exp(lamdajik));
       NconjtmpI = NconjtmpI+(kronecker(ktype,0)*wik*Sp(Nki,Nmin,Nmax,dS));
     }
   }
 
   PijS = 0.0;
   dN2[0] = 0.0;
   dN2[1] = 0.0;
   PijS = PijSpline(NijC,NijH,itype,jtype,dN2);
   pij = pow(1.0+Etmp+PijS,-0.5);
   tmp = -0.5*cube(pij);
 
   // pij forces
 
   REBO_neighs = REBO_firstneigh[i];
   for (k = 0; k < REBO_numneigh[i]; k++) {
     atomk = REBO_neighs[k];
     if (atomk != atomj) {
       ktype = map[type[atomk]];
       rik[0] = x[atomi][0]-x[atomk][0];
       rik[1] = x[atomi][1]-x[atomk][1];
       rik[2] = x[atomi][2]-x[atomk][2];
       rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2]));
       lamdajik = 4.0*kronecker(itype,1) *
         ((rho[ktype][1]-rikmag)-(rho[jtype][1]-rijmag));
       wik = Sp(rikmag,rcmin[itype][ktype],rcmax[itype][ktype],dwik);
       cosjik = (rij[0]*rik[0] + rij[1]*rik[1] + rij[2]*rik[2]) /
         (rijmag*rikmag);
       cosjik = MIN(cosjik,1.0);
       cosjik = MAX(cosjik,-1.0);
 
       dcosjikdri[0] = ((rij[0]+rik[0])/(rijmag*rikmag)) -
         (cosjik*((rij[0]/(rijmag*rijmag))+(rik[0]/(rikmag*rikmag))));
       dcosjikdri[1] = ((rij[1]+rik[1])/(rijmag*rikmag)) -
         (cosjik*((rij[1]/(rijmag*rijmag))+(rik[1]/(rikmag*rikmag))));
       dcosjikdri[2] = ((rij[2]+rik[2])/(rijmag*rikmag)) -
         (cosjik*((rij[2]/(rijmag*rijmag))+(rik[2]/(rikmag*rikmag))));
       dcosjikdrk[0] = (-rij[0]/(rijmag*rikmag)) +
         (cosjik*(rik[0]/(rikmag*rikmag)));
       dcosjikdrk[1] = (-rij[1]/(rijmag*rikmag)) +
         (cosjik*(rik[1]/(rikmag*rikmag)));
       dcosjikdrk[2] = (-rij[2]/(rijmag*rikmag)) +
         (cosjik*(rik[2]/(rikmag*rikmag)));
       dcosjikdrj[0] = (-rik[0]/(rijmag*rikmag)) +
         (cosjik*(rij[0]/(rijmag*rijmag)));
       dcosjikdrj[1] = (-rik[1]/(rijmag*rikmag)) +
         (cosjik*(rij[1]/(rijmag*rijmag)));
       dcosjikdrj[2] = (-rik[2]/(rijmag*rikmag)) +
         (cosjik*(rij[2]/(rijmag*rijmag)));
 
       g = gSpline(cosjik,(NijC+NijH),itype,&dgdc,&dgdN);
       tmp2 = VA*.5*(tmp*wik*dgdc*exp(lamdajik));
       fj[0] = -tmp2*dcosjikdrj[0];
       fj[1] = -tmp2*dcosjikdrj[1];
       fj[2] = -tmp2*dcosjikdrj[2];
       fi[0] = -tmp2*dcosjikdri[0];
       fi[1] = -tmp2*dcosjikdri[1];
       fi[2] = -tmp2*dcosjikdri[2];
       fk[0] = -tmp2*dcosjikdrk[0];
       fk[1] = -tmp2*dcosjikdrk[1];
       fk[2] = -tmp2*dcosjikdrk[2];
 
       tmp2 = VA*.5*(tmp*wik*g*exp(lamdajik)*4.0*kronecker(itype,1));
       fj[0] -= tmp2*(-rij[0]/rijmag);
       fj[1] -= tmp2*(-rij[1]/rijmag);
       fj[2] -= tmp2*(-rij[2]/rijmag);
       fi[0] -= tmp2*((-rik[0]/rikmag)+(rij[0]/rijmag));
       fi[1] -= tmp2*((-rik[1]/rikmag)+(rij[1]/rijmag));
       fi[2] -= tmp2*((-rik[2]/rikmag)+(rij[2]/rijmag));
       fk[0] -= tmp2*(rik[0]/rikmag);
       fk[1] -= tmp2*(rik[1]/rikmag);
       fk[2] -= tmp2*(rik[2]/rikmag);
 
       // coordination forces
 
       // dwik forces
 
       tmp2 = VA*.5*(tmp*dwik*g*exp(lamdajik))/rikmag;
       fi[0] -= tmp2*rik[0];
       fi[1] -= tmp2*rik[1];
       fi[2] -= tmp2*rik[2];
       fk[0] += tmp2*rik[0];
       fk[1] += tmp2*rik[1];
       fk[2] += tmp2*rik[2];
 
       // PIJ forces
 
       tmp2 = VA*.5*(tmp*dN2[ktype]*dwik)/rikmag;
       fi[0] -= tmp2*rik[0];
       fi[1] -= tmp2*rik[1];
       fi[2] -= tmp2*rik[2];
       fk[0] += tmp2*rik[0];
       fk[1] += tmp2*rik[1];
       fk[2] += tmp2*rik[2];
 
       // dgdN forces
 
       tmp2 = VA*.5*(tmp*tmp3*dwik)/rikmag;
       fi[0] -= tmp2*rik[0];
       fi[1] -= tmp2*rik[1];
       fi[2] -= tmp2*rik[2];
       fk[0] += tmp2*rik[0];
       fk[1] += tmp2*rik[1];
       fk[2] += tmp2*rik[2];
 
       f[atomi][0] += fi[0]; f[atomi][1] += fi[1]; f[atomi][2] += fi[2];
       f[atomj][0] += fj[0]; f[atomj][1] += fj[1]; f[atomj][2] += fj[2];
       f[atomk][0] += fk[0]; f[atomk][1] += fk[1]; f[atomk][2] += fk[2];
 
       if (vflag_atom) {
         rji[0] = -rij[0]; rji[1] = -rij[1]; rji[2] = -rij[2];
         rki[0] = -rik[0]; rki[1] = -rik[1]; rki[2] = -rik[2];
         v_tally3(atomi,atomj,atomk,fj,fk,rji,rki);
       }
     }
   }
 
   tmp = 0.0;
   tmp2 = 0.0;
   tmp3 = 0.0;
   Etmp = 0.0;
 
   REBO_neighs = REBO_firstneigh[j];
   for (l = 0; l < REBO_numneigh[j]; l++) {
     atoml = REBO_neighs[l];
     if (atoml != atomi) {
       ltype = map[type[atoml]];
       rjl[0] = x[atomj][0]-x[atoml][0];
       rjl[1] = x[atomj][1]-x[atoml][1];
       rjl[2] = x[atomj][2]-x[atoml][2];
       rjlmag = sqrt((rjl[0]*rjl[0])+(rjl[1]*rjl[1])+(rjl[2]*rjl[2]));
       lamdaijl = 4.0*kronecker(jtype,1) *
         ((rho[ltype][1]-rjlmag)-(rho[itype][1]-rijmag));
       wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmax[jtype][ltype],dS);
       Nlj = nC[atoml]-(wjl*kronecker(jtype,0)) +
         nH[atoml]-(wjl*kronecker(jtype,1));
       cosijl = -1.0*((rij[0]*rjl[0])+(rij[1]*rjl[1])+(rij[2]*rjl[2])) /
         (rijmag*rjlmag);
       cosijl = MIN(cosijl,1.0);
       cosijl = MAX(cosijl,-1.0);
 
       // evaluate splines g and derivatives dg
 
       g = gSpline(cosijl,NjiC+NjiH,jtype,&dgdc,&dgdN);
       Etmp = Etmp+(wjl*g*exp(lamdaijl));
       tmp3 = tmp3+(wjl*dgdN*exp(lamdaijl));
       NconjtmpJ = NconjtmpJ+(kronecker(ltype,0)*wjl*Sp(Nlj,Nmin,Nmax,dS));
     }
   }
 
   PjiS = 0.0;
   dN2[0] = 0.0;
   dN2[1] = 0.0;
   PjiS = PijSpline(NjiC,NjiH,jtype,itype,dN2);
   pji = pow(1.0+Etmp+PjiS,-0.5);
   tmp = -0.5*cube(pji);
 
   REBO_neighs = REBO_firstneigh[j];
   for (l = 0; l < REBO_numneigh[j]; l++) {
     atoml = REBO_neighs[l];
     if (atoml != atomi) {
       ltype = map[type[atoml]];
       rjl[0] = x[atomj][0]-x[atoml][0];
       rjl[1] = x[atomj][1]-x[atoml][1];
       rjl[2] = x[atomj][2]-x[atoml][2];
       rjlmag = sqrt((rjl[0]*rjl[0])+(rjl[1]*rjl[1])+(rjl[2]*rjl[2]));
       lamdaijl = 4.0*kronecker(jtype,1) *
         ((rho[ltype][1]-rjlmag)-(rho[itype][1]-rijmag));
       wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmax[jtype][ltype],dwjl);
       cosijl = (-1.0*((rij[0]*rjl[0])+(rij[1]*rjl[1])+(rij[2]*rjl[2]))) /
         (rijmag*rjlmag);
       cosijl = MIN(cosijl,1.0);
       cosijl = MAX(cosijl,-1.0);
 
       dcosijldri[0] = (-rjl[0]/(rijmag*rjlmag)) -
         (cosijl*rij[0]/(rijmag*rijmag));
       dcosijldri[1] = (-rjl[1]/(rijmag*rjlmag)) -
         (cosijl*rij[1]/(rijmag*rijmag));
       dcosijldri[2] = (-rjl[2]/(rijmag*rjlmag)) -
         (cosijl*rij[2]/(rijmag*rijmag));
       dcosijldrj[0] = ((-rij[0]+rjl[0])/(rijmag*rjlmag)) +
         (cosijl*((rij[0]/square(rijmag))-(rjl[0]/(rjlmag*rjlmag))));
       dcosijldrj[1] = ((-rij[1]+rjl[1])/(rijmag*rjlmag)) +
         (cosijl*((rij[1]/square(rijmag))-(rjl[1]/(rjlmag*rjlmag))));
       dcosijldrj[2] = ((-rij[2]+rjl[2])/(rijmag*rjlmag)) +
         (cosijl*((rij[2]/square(rijmag))-(rjl[2]/(rjlmag*rjlmag))));
       dcosijldrl[0] = (rij[0]/(rijmag*rjlmag))+(cosijl*rjl[0]/(rjlmag*rjlmag));
       dcosijldrl[1] = (rij[1]/(rijmag*rjlmag))+(cosijl*rjl[1]/(rjlmag*rjlmag));
       dcosijldrl[2] = (rij[2]/(rijmag*rjlmag))+(cosijl*rjl[2]/(rjlmag*rjlmag));
 
       // evaluate splines g and derivatives dg
 
       g = gSpline(cosijl,NjiC+NjiH,jtype,&dgdc,&dgdN);
       tmp2 = VA*.5*(tmp*wjl*dgdc*exp(lamdaijl));
       fi[0] = -tmp2*dcosijldri[0];
       fi[1] = -tmp2*dcosijldri[1];
       fi[2] = -tmp2*dcosijldri[2];
       fj[0] = -tmp2*dcosijldrj[0];
       fj[1] = -tmp2*dcosijldrj[1];
       fj[2] = -tmp2*dcosijldrj[2];
       fl[0] = -tmp2*dcosijldrl[0];
       fl[1] = -tmp2*dcosijldrl[1];
       fl[2] = -tmp2*dcosijldrl[2];
 
       tmp2 = VA*.5*(tmp*wjl*g*exp(lamdaijl)*4.0*kronecker(jtype,1));
       fi[0] -= tmp2*(rij[0]/rijmag);
       fi[1] -= tmp2*(rij[1]/rijmag);
       fi[2] -= tmp2*(rij[2]/rijmag);
       fj[0] -= tmp2*((-rjl[0]/rjlmag)-(rij[0]/rijmag));
       fj[1] -= tmp2*((-rjl[1]/rjlmag)-(rij[1]/rijmag));
       fj[2] -= tmp2*((-rjl[2]/rjlmag)-(rij[2]/rijmag));
       fl[0] -= tmp2*(rjl[0]/rjlmag);
       fl[1] -= tmp2*(rjl[1]/rjlmag);
       fl[2] -= tmp2*(rjl[2]/rjlmag);
 
       // coordination forces
 
       // dwik forces
 
       tmp2 = VA*.5*(tmp*dwjl*g*exp(lamdaijl))/rjlmag;
       fj[0] -= tmp2*rjl[0];
       fj[1] -= tmp2*rjl[1];
       fj[2] -= tmp2*rjl[2];
       fl[0] += tmp2*rjl[0];
       fl[1] += tmp2*rjl[1];
       fl[2] += tmp2*rjl[2];
 
       // PIJ forces
 
       tmp2 = VA*.5*(tmp*dN2[ltype]*dwjl)/rjlmag;
       fj[0] -= tmp2*rjl[0];
       fj[1] -= tmp2*rjl[1];
       fj[2] -= tmp2*rjl[2];
       fl[0] += tmp2*rjl[0];
       fl[1] += tmp2*rjl[1];
       fl[2] += tmp2*rjl[2];
 
       // dgdN forces
 
       tmp2 = VA*.5*(tmp*tmp3*dwjl)/rjlmag;
       fj[0] -= tmp2*rjl[0];
       fj[1] -= tmp2*rjl[1];
       fj[2] -= tmp2*rjl[2];
       fl[0] += tmp2*rjl[0];
       fl[1] += tmp2*rjl[1];
       fl[2] += tmp2*rjl[2];
 
       f[atomi][0] += fi[0]; f[atomi][1] += fi[1]; f[atomi][2] += fi[2];
       f[atomj][0] += fj[0]; f[atomj][1] += fj[1]; f[atomj][2] += fj[2];
       f[atoml][0] += fl[0]; f[atoml][1] += fl[1]; f[atoml][2] += fl[2];
 
       if (vflag_atom) {
         rlj[0] = -rjl[0]; rlj[1] = -rjl[1]; rlj[2] = -rjl[2];
         v_tally3(atomi,atomj,atoml,fi,fl,rij,rlj);
       }
     }
   }
 
   // evaluate Nij conj
 
   Nijconj = 1.0+(NconjtmpI*NconjtmpI)+(NconjtmpJ*NconjtmpJ);
   piRC = piRCSpline(NijC+NijH,NjiC+NjiH,Nijconj,itype,jtype,dN3);
 
   // piRC forces
 
   REBO_neighs_i = REBO_firstneigh[i];
   for (k = 0; k < REBO_numneigh[i]; k++) {
     atomk = REBO_neighs_i[k];
     if (atomk !=atomj) {
       ktype = map[type[atomk]];
       rik[0] = x[atomi][0]-x[atomk][0];
       rik[1] = x[atomi][1]-x[atomk][1];
       rik[2] = x[atomi][2]-x[atomk][2];
       rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2]));
       wik = Sp(rikmag,rcmin[itype][ktype],rcmax[itype][ktype],dwik);
       Nki = nC[atomk]-(wik*kronecker(itype,0))+nH[atomk] -
         (wik*kronecker(itype,1));
       SpN = Sp(Nki,Nmin,Nmax,dNki);
 
       tmp2 = VA*dN3[0]*dwik/rikmag;
       f[atomi][0] -= tmp2*rik[0];
       f[atomi][1] -= tmp2*rik[1];
       f[atomi][2] -= tmp2*rik[2];
       f[atomk][0] += tmp2*rik[0];
       f[atomk][1] += tmp2*rik[1];
       f[atomk][2] += tmp2*rik[2];
 
       if (vflag_atom) v_tally2(atomi,atomk,-tmp2,rik);
 
       tmp2 = VA*dN3[2]*(2.0*NconjtmpI*dwik*SpN)/rikmag;
       f[atomi][0] -= tmp2*rik[0];
       f[atomi][1] -= tmp2*rik[1];
       f[atomi][2] -= tmp2*rik[2];
       f[atomk][0] += tmp2*rik[0];
       f[atomk][1] += tmp2*rik[1];
       f[atomk][2] += tmp2*rik[2];
 
       if (vflag_atom) v_tally2(atomi,atomk,-tmp2,rik);
 
       if (fabs(dNki) > TOL) {
         REBO_neighs_k = REBO_firstneigh[atomk];
         for (n = 0; n < REBO_numneigh[atomk]; n++) {
           atomn = REBO_neighs_k[n];
           if (atomn != atomi) {
             ntype = map[type[atomn]];
             rkn[0] = x[atomk][0]-x[atomn][0];
             rkn[1] = x[atomk][1]-x[atomn][1];
             rkn[2] = x[atomk][2]-x[atomn][2];
             rknmag = sqrt((rkn[0]*rkn[0])+(rkn[1]*rkn[1])+(rkn[2]*rkn[2]));
             Sp(rknmag,rcmin[ktype][ntype],rcmax[ktype][ntype],dwkn);
 
             tmp2 = VA*dN3[2]*(2.0*NconjtmpI*wik*dNki*dwkn)/rknmag;
             f[atomk][0] -= tmp2*rkn[0];
             f[atomk][1] -= tmp2*rkn[1];
             f[atomk][2] -= tmp2*rkn[2];
             f[atomn][0] += tmp2*rkn[0];
             f[atomn][1] += tmp2*rkn[1];
             f[atomn][2] += tmp2*rkn[2];
 
             if (vflag_atom) v_tally2(atomk,atomn,-tmp2,rkn);
           }
         }
       }
     }
   }
 
   // piRC forces
 
   REBO_neighs = REBO_firstneigh[atomj];
   for (l = 0; l < REBO_numneigh[atomj]; l++) {
     atoml = REBO_neighs[l];
     if (atoml !=atomi) {
       ltype = map[type[atoml]];
       rjl[0] = x[atomj][0]-x[atoml][0];
       rjl[1] = x[atomj][1]-x[atoml][1];
       rjl[2] = x[atomj][2]-x[atoml][2];
       rjlmag = sqrt((rjl[0]*rjl[0])+(rjl[1]*rjl[1])+(rjl[2]*rjl[2]));
       wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmax[jtype][ltype],dwjl);
       Nlj = nC[atoml]-(wjl*kronecker(jtype,0))+nH[atoml] -
         (wjl*kronecker(jtype,1));
       SpN = Sp(Nlj,Nmin,Nmax,dNlj);
 
       tmp2 = VA*dN3[1]*dwjl/rjlmag;
       f[atomj][0] -= tmp2*rjl[0];
       f[atomj][1] -= tmp2*rjl[1];
       f[atomj][2] -= tmp2*rjl[2];
       f[atoml][0] += tmp2*rjl[0];
       f[atoml][1] += tmp2*rjl[1];
       f[atoml][2] += tmp2*rjl[2];
 
       if (vflag_atom) v_tally2(atomj,atoml,-tmp2,rjl);
 
       tmp2 = VA*dN3[2]*(2.0*NconjtmpJ*dwjl*SpN)/rjlmag;
       f[atomj][0] -= tmp2*rjl[0];
       f[atomj][1] -= tmp2*rjl[1];
       f[atomj][2] -= tmp2*rjl[2];
       f[atoml][0] += tmp2*rjl[0];
       f[atoml][1] += tmp2*rjl[1];
       f[atoml][2] += tmp2*rjl[2];
 
       if (vflag_atom) v_tally2(atomj,atoml,-tmp2,rjl);
 
       if (fabs(dNlj) > TOL) {
         REBO_neighs_l = REBO_firstneigh[atoml];
         for (n = 0; n < REBO_numneigh[atoml]; n++) {
           atomn = REBO_neighs_l[n];
           if (atomn != atomj) {
             ntype = map[type[atomn]];
             rln[0] = x[atoml][0]-x[atomn][0];
             rln[1] = x[atoml][1]-x[atomn][1];
             rln[2] = x[atoml][2]-x[atomn][2];
             rlnmag = sqrt((rln[0]*rln[0])+(rln[1]*rln[1])+(rln[2]*rln[2]));
             Sp(rlnmag,rcmin[ltype][ntype],rcmax[ltype][ntype],dwln);
 
             tmp2 = VA*dN3[2]*(2.0*NconjtmpJ*wjl*dNlj*dwln)/rlnmag;
             f[atoml][0] -= tmp2*rln[0];
             f[atoml][1] -= tmp2*rln[1];
             f[atoml][2] -= tmp2*rln[2];
             f[atomn][0] += tmp2*rln[0];
             f[atomn][1] += tmp2*rln[1];
             f[atomn][2] += tmp2*rln[2];
 
             if (vflag_atom) v_tally2(atoml,atomn,-tmp2,rln);
           }
         }
       }
     }
   }
 
   Tij = 0.0;
   dN3[0] = 0.0;
   dN3[1] = 0.0;
   dN3[2] = 0.0;
   if (itype == 0 && jtype == 0)
     Tij=TijSpline((NijC+NijH),(NjiC+NjiH),Nijconj,dN3);
   Etmp = 0.0;
 
   if (fabs(Tij) > TOL) {
     atom2 = atomi;
     atom3 = atomj;
     r32[0] = x[atom3][0]-x[atom2][0];
     r32[1] = x[atom3][1]-x[atom2][1];
     r32[2] = x[atom3][2]-x[atom2][2];
     r32mag = sqrt((r32[0]*r32[0])+(r32[1]*r32[1])+(r32[2]*r32[2]));
     r23[0] = -r32[0];
     r23[1] = -r32[1];
     r23[2] = -r32[2];
     r23mag = r32mag;
     REBO_neighs_i = REBO_firstneigh[i];
     for (k = 0; k < REBO_numneigh[i]; k++) {
       atomk = REBO_neighs_i[k];
       atom1 = atomk;
       ktype = map[type[atomk]];
       if (atomk != atomj) {
         r21[0] = x[atom2][0]-x[atom1][0];
         r21[1] = x[atom2][1]-x[atom1][1];
         r21[2] = x[atom2][2]-x[atom1][2];
         r21mag = sqrt(r21[0]*r21[0] + r21[1]*r21[1] + r21[2]*r21[2]);
         cos321 = -1.0*((r21[0]*r32[0])+(r21[1]*r32[1])+(r21[2]*r32[2])) /
           (r21mag*r32mag);
         cos321 = MIN(cos321,1.0);
         cos321 = MAX(cos321,-1.0);
         Sp2(cos321,thmin,thmax,dcut321);
         sin321 = sqrt(1.0 - cos321*cos321);
         sink2i = 1.0/(sin321*sin321);
         rik2i = 1.0/(r21mag*r21mag);
         if (sin321 != 0.0) {
           rr = (r23mag*r23mag)-(r21mag*r21mag);
           rjk[0] = r21[0]-r23[0];
           rjk[1] = r21[1]-r23[1];
           rjk[2] = r21[2]-r23[2];
           rjk2 = (rjk[0]*rjk[0])+(rjk[1]*rjk[1])+(rjk[2]*rjk[2]);
           rijrik = 2.0*r23mag*r21mag;
           rik2 = r21mag*r21mag;
           dctik = (-rr+rjk2)/(rijrik*rik2);
           dctij = (rr+rjk2)/(rijrik*r23mag*r23mag);
           dctjk = -2.0/rijrik;
           w21 = Sp(r21mag,rcmin[itype][ktype],rcmaxp[itype][ktype],dw21);
           rijmag = r32mag;
           rikmag = r21mag;
           rij2 = r32mag*r32mag;
           rik2 = r21mag*r21mag;
           costmp = 0.5*(rij2+rik2-rjk2)/rijmag/rikmag;
           tspjik = Sp2(costmp,thmin,thmax,dtsjik);
           dtsjik = -dtsjik;
 
           REBO_neighs_j = REBO_firstneigh[j];
           for (l = 0; l < REBO_numneigh[j]; l++) {
             atoml = REBO_neighs_j[l];
             atom4 = atoml;
             ltype = map[type[atoml]];
             if (!(atoml == atomi || atoml == atomk)) {
               r34[0] = x[atom3][0]-x[atom4][0];
               r34[1] = x[atom3][1]-x[atom4][1];
               r34[2] = x[atom3][2]-x[atom4][2];
               r34mag = sqrt((r34[0]*r34[0])+(r34[1]*r34[1])+(r34[2]*r34[2]));
               cos234 = (r32[0]*r34[0] + r32[1]*r34[1] + r32[2]*r34[2]) /
                 (r32mag*r34mag);
               cos234 = MIN(cos234,1.0);
               cos234 = MAX(cos234,-1.0);
               sin234 = sqrt(1.0 - cos234*cos234);
               sinl2i = 1.0/(sin234*sin234);
               rjl2i = 1.0/(r34mag*r34mag);
 
               if (sin234 != 0.0) {
                 w34 = Sp(r34mag,rcmin[jtype][ltype],rcmaxp[jtype][ltype],dw34);
                 rr = (r23mag*r23mag)-(r34mag*r34mag);
                 ril[0] = r23[0]+r34[0];
                 ril[1] = r23[1]+r34[1];
                 ril[2] = r23[2]+r34[2];
                 ril2 = (ril[0]*ril[0])+(ril[1]*ril[1])+(ril[2]*ril[2]);
                 rijrjl = 2.0*r23mag*r34mag;
                 rjl2 = r34mag*r34mag;
                 dctjl = (-rr+ril2)/(rijrjl*rjl2);
                 dctji = (rr+ril2)/(rijrjl*r23mag*r23mag);
                 dctil = -2.0/rijrjl;
                 rjlmag = r34mag;
                 rjl2 = r34mag*r34mag;
                 costmp = 0.5*(rij2+rjl2-ril2)/rijmag/rjlmag;
                 tspijl = Sp2(costmp,thmin,thmax,dtsijl);
                 dtsijl = -dtsijl;
                 prefactor = VA*Tij;
 
                 cross321[0] = (r32[1]*r21[2])-(r32[2]*r21[1]);
                 cross321[1] = (r32[2]*r21[0])-(r32[0]*r21[2]);
                 cross321[2] = (r32[0]*r21[1])-(r32[1]*r21[0]);
                 cross234[0] = (r23[1]*r34[2])-(r23[2]*r34[1]);
                 cross234[1] = (r23[2]*r34[0])-(r23[0]*r34[2]);
                 cross234[2] = (r23[0]*r34[1])-(r23[1]*r34[0]);
 
                 cwnum = (cross321[0]*cross234[0]) +
                   (cross321[1]*cross234[1]) + (cross321[2]*cross234[2]);
                 cwnom = r21mag*r34mag*r23mag*r23mag*sin321*sin234;
                 om1234 = cwnum/cwnom;
                 cw = om1234;
                 Etmp += ((1.0-square(om1234))*w21*w34) *
                   (1.0-tspjik)*(1.0-tspijl);
 
                 dt1dik = (rik2i)-(dctik*sink2i*cos321);
                 dt1djk = (-dctjk*sink2i*cos321);
                 dt1djl = (rjl2i)-(dctjl*sinl2i*cos234);
                 dt1dil = (-dctil*sinl2i*cos234);
                 dt1dij = (2.0/(r23mag*r23mag))-(dctij*sink2i*cos321) -
                   (dctji*sinl2i*cos234);
 
                 dt2dik[0] = (-r23[2]*cross234[1])+(r23[1]*cross234[2]);
                 dt2dik[1] = (-r23[0]*cross234[2])+(r23[2]*cross234[0]);
                 dt2dik[2] = (-r23[1]*cross234[0])+(r23[0]*cross234[1]);
 
                 dt2djl[0] = (-r23[1]*cross321[2])+(r23[2]*cross321[1]);
                 dt2djl[1] = (-r23[2]*cross321[0])+(r23[0]*cross321[2]);
                 dt2djl[2] = (-r23[0]*cross321[1])+(r23[1]*cross321[0]);
 
                 dt2dij[0] = (r21[2]*cross234[1])-(r34[2]*cross321[1]) -
                   (r21[1]*cross234[2])+(r34[1]*cross321[2]);
                 dt2dij[1] = (r21[0]*cross234[2])-(r34[0]*cross321[2]) -
                   (r21[2]*cross234[0])+(r34[2]*cross321[0]);
                 dt2dij[2] = (r21[1]*cross234[0])-(r34[1]*cross321[0]) -
                   (r21[0]*cross234[1])+(r34[0]*cross321[1]);
 
                 aa = (prefactor*2.0*cw/cwnom)*w21*w34 *
                   (1.0-tspjik)*(1.0-tspijl);
                 aaa1 = -prefactor*(1.0-square(om1234)) *
                   (1.0-tspjik)*(1.0-tspijl);
                 aaa2 = aaa1*w21*w34;
                 at2 = aa*cwnum;
 
                 fcijpc = (-dt1dij*at2)+(aaa2*dtsjik*dctij*(1.0-tspijl)) +
                   (aaa2*dtsijl*dctji*(1.0-tspjik));
                 fcikpc = (-dt1dik*at2)+(aaa2*dtsjik*dctik*(1.0-tspijl));
                 fcjlpc = (-dt1djl*at2)+(aaa2*dtsijl*dctjl*(1.0-tspjik));
                 fcjkpc = (-dt1djk*at2)+(aaa2*dtsjik*dctjk*(1.0-tspijl));
                 fcilpc = (-dt1dil*at2)+(aaa2*dtsijl*dctil*(1.0-tspjik));
 
                 F23[0] = (fcijpc*r23[0])+(aa*dt2dij[0]);
                 F23[1] = (fcijpc*r23[1])+(aa*dt2dij[1]);
                 F23[2] = (fcijpc*r23[2])+(aa*dt2dij[2]);
 
                 F12[0] = (fcikpc*r21[0])+(aa*dt2dik[0]);
                 F12[1] = (fcikpc*r21[1])+(aa*dt2dik[1]);
                 F12[2] = (fcikpc*r21[2])+(aa*dt2dik[2]);
 
                 F34[0] = (fcjlpc*r34[0])+(aa*dt2djl[0]);
                 F34[1] = (fcjlpc*r34[1])+(aa*dt2djl[1]);
                 F34[2] = (fcjlpc*r34[2])+(aa*dt2djl[2]);
 
                 F31[0] = (fcjkpc*rjk[0]);
                 F31[1] = (fcjkpc*rjk[1]);
                 F31[2] = (fcjkpc*rjk[2]);
 
                 F24[0] = (fcilpc*ril[0]);
                 F24[1] = (fcilpc*ril[1]);
                 F24[2] = (fcilpc*ril[2]);
 
                 f1[0] = -F12[0]-F31[0];
                 f1[1] = -F12[1]-F31[1];
                 f1[2] = -F12[2]-F31[2];
                 f2[0] = F23[0]+F12[0]+F24[0];
                 f2[1] = F23[1]+F12[1]+F24[1];
                 f2[2] = F23[2]+F12[2]+F24[2];
                 f3[0] = -F23[0]+F34[0]+F31[0];
                 f3[1] = -F23[1]+F34[1]+F31[1];
                 f3[2] = -F23[2]+F34[2]+F31[2];
                 f4[0] = -F34[0]-F24[0];
                 f4[1] = -F34[1]-F24[1];
                 f4[2] = -F34[2]-F24[2];
 
                 // coordination forces
 
                 tmp2 = VA*Tij*((1.0-(om1234*om1234))) *
                   (1.0-tspjik)*(1.0-tspijl)*dw21*w34/r21mag;
                 f2[0] -= tmp2*r21[0];
                 f2[1] -= tmp2*r21[1];
                 f2[2] -= tmp2*r21[2];
                 f1[0] += tmp2*r21[0];
                 f1[1] += tmp2*r21[1];
                 f1[2] += tmp2*r21[2];
 
                 tmp2 = VA*Tij*((1.0-(om1234*om1234))) *
                   (1.0-tspjik)*(1.0-tspijl)*w21*dw34/r34mag;
                 f3[0] -= tmp2*r34[0];
                 f3[1] -= tmp2*r34[1];
                 f3[2] -= tmp2*r34[2];
                 f4[0] += tmp2*r34[0];
                 f4[1] += tmp2*r34[1];
                 f4[2] += tmp2*r34[2];
 
                 f[atom1][0] += f1[0]; f[atom1][1] += f1[1];
                 f[atom1][2] += f1[2];
                 f[atom2][0] += f2[0]; f[atom2][1] += f2[1];
                 f[atom2][2] += f2[2];
                 f[atom3][0] += f3[0]; f[atom3][1] += f3[1];
                 f[atom3][2] += f3[2];
                 f[atom4][0] += f4[0]; f[atom4][1] += f4[1];
                 f[atom4][2] += f4[2];
 
                 if (vflag_atom) {
                   r13[0] = -rjk[0]; r13[1] = -rjk[1]; r13[2] = -rjk[2];
                   r43[0] = -r34[0]; r43[1] = -r34[1]; r43[2] = -r34[2];
                   v_tally4(atom1,atom2,atom3,atom4,f1,f2,f4,r13,r23,r43);
                 }
               }
             }
           }
         }
       }
     }
 
     // Tij forces now that we have Etmp
 
     REBO_neighs = REBO_firstneigh[i];
     for (k = 0; k < REBO_numneigh[i]; k++) {
       atomk = REBO_neighs[k];
       if (atomk != atomj) {
         ktype = map[type[atomk]];
         rik[0] = x[atomi][0]-x[atomk][0];
         rik[1] = x[atomi][1]-x[atomk][1];
         rik[2] = x[atomi][2]-x[atomk][2];
         rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2]));
         wik = Sp(rikmag,rcmin[itype][ktype],rcmax[itype][ktype],dwik);
         Nki = nC[atomk]-(wik*kronecker(itype,0))+nH[atomk] -
           (wik*kronecker(itype,1));
         SpN = Sp(Nki,Nmin,Nmax,dNki);
 
         tmp2 = VA*dN3[0]*dwik*Etmp/rikmag;
         f[atomi][0] -= tmp2*rik[0];
         f[atomi][1] -= tmp2*rik[1];
         f[atomi][2] -= tmp2*rik[2];
         f[atomk][0] += tmp2*rik[0];
         f[atomk][1] += tmp2*rik[1];
         f[atomk][2] += tmp2*rik[2];
 
         if (vflag_atom) v_tally2(atomi,atomk,-tmp2,rik);
 
         tmp2 = VA*dN3[2]*(2.0*NconjtmpI*dwik*SpN)*Etmp/rikmag;
         f[atomi][0] -= tmp2*rik[0];
         f[atomi][1] -= tmp2*rik[1];
         f[atomi][2] -= tmp2*rik[2];
         f[atomk][0] += tmp2*rik[0];
         f[atomk][1] += tmp2*rik[1];
         f[atomk][2] += tmp2*rik[2];
 
         if (vflag_atom) v_tally2(atomi,atomk,-tmp2,rik);
 
         if (fabs(dNki) > TOL) {
           REBO_neighs_k = REBO_firstneigh[atomk];
           for (n = 0; n < REBO_numneigh[atomk]; n++) {
             atomn = REBO_neighs_k[n];
             ntype = map[type[atomn]];
             if (atomn != atomi) {
               rkn[0] = x[atomk][0]-x[atomn][0];
               rkn[1] = x[atomk][1]-x[atomn][1];
               rkn[2] = x[atomk][2]-x[atomn][2];
               rknmag = sqrt((rkn[0]*rkn[0])+(rkn[1]*rkn[1])+(rkn[2]*rkn[2]));
               Sp(rknmag,rcmin[ktype][ntype],rcmax[ktype][ntype],dwkn);
 
               tmp2 = VA*dN3[2]*(2.0*NconjtmpI*wik*dNki*dwkn)*Etmp/rknmag;
               f[atomk][0] -= tmp2*rkn[0];
               f[atomk][1] -= tmp2*rkn[1];
               f[atomk][2] -= tmp2*rkn[2];
               f[atomn][0] += tmp2*rkn[0];
               f[atomn][1] += tmp2*rkn[1];
               f[atomn][2] += tmp2*rkn[2];
 
               if (vflag_atom) v_tally2(atomk,atomn,-tmp2,rkn);
             }
           }
         }
       }
     }
 
     // Tij forces
 
     REBO_neighs = REBO_firstneigh[j];
     for (l = 0; l < REBO_numneigh[j]; l++) {
       atoml = REBO_neighs[l];
       if (atoml != atomi) {
         ltype = map[type[atoml]];
         rjl[0] = x[atomj][0]-x[atoml][0];
         rjl[1] = x[atomj][1]-x[atoml][1];
         rjl[2] = x[atomj][2]-x[atoml][2];
         rjlmag = sqrt((rjl[0]*rjl[0])+(rjl[1]*rjl[1])+(rjl[2]*rjl[2]));
         wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmax[jtype][ltype],dwjl);
         Nlj = nC[atoml]-(wjl*kronecker(jtype,0))+nH[atoml] -
           (wjl*kronecker(jtype,1));
         SpN = Sp(Nlj,Nmin,Nmax,dNlj);
 
         tmp2 = VA*dN3[1]*dwjl*Etmp/rjlmag;
         f[atomj][0] -= tmp2*rjl[0];
         f[atomj][1] -= tmp2*rjl[1];
         f[atomj][2] -= tmp2*rjl[2];
         f[atoml][0] += tmp2*rjl[0];
         f[atoml][1] += tmp2*rjl[1];
         f[atoml][2] += tmp2*rjl[2];
 
         if (vflag_atom) v_tally2(atomj,atoml,-tmp2,rjl);
 
         tmp2 = VA*dN3[2]*(2.0*NconjtmpJ*dwjl*SpN)*Etmp/rjlmag;
         f[atomj][0] -= tmp2*rjl[0];
         f[atomj][1] -= tmp2*rjl[1];
         f[atomj][2] -= tmp2*rjl[2];
         f[atoml][0] += tmp2*rjl[0];
         f[atoml][1] += tmp2*rjl[1];
         f[atoml][2] += tmp2*rjl[2];
 
         if (vflag_atom) v_tally2(atomj,atoml,-tmp2,rjl);
 
         if (fabs(dNlj) > TOL) {
           REBO_neighs_l = REBO_firstneigh[atoml];
           for (n = 0; n < REBO_numneigh[atoml]; n++) {
             atomn = REBO_neighs_l[n];
             ntype = map[type[atomn]];
             if (atomn !=atomj) {
               rln[0] = x[atoml][0]-x[atomn][0];
               rln[1] = x[atoml][1]-x[atomn][1];
               rln[2] = x[atoml][2]-x[atomn][2];
               rlnmag = sqrt((rln[0]*rln[0])+(rln[1]*rln[1])+(rln[2]*rln[2]));
               Sp(rlnmag,rcmin[ltype][ntype],rcmax[ltype][ntype],dwln);
 
               tmp2 = VA*dN3[2]*(2.0*NconjtmpJ*wjl*dNlj*dwln)*Etmp/rlnmag;
               f[atoml][0] -= tmp2*rln[0];
               f[atoml][1] -= tmp2*rln[1];
               f[atoml][2] -= tmp2*rln[2];
               f[atomn][0] += tmp2*rln[0];
               f[atomn][1] += tmp2*rln[1];
               f[atomn][2] += tmp2*rln[2];
 
               if (vflag_atom) v_tally2(atoml,atomn,-tmp2,rln);
             }
           }
         }
       }
     }
   }
 
   bij = (0.5*(pij+pji))+piRC+(Tij*Etmp);
   return bij;
 }
 
 /* ----------------------------------------------------------------------
    Bij* function
 ------------------------------------------------------------------------- */
 
 double PairAIREBO::bondorderLJ(int i, int j, double rij[3], double rijmag,
                                double VA, double rij0[3], double rij0mag,
                                double **f, int vflag_atom)
 {
   int k,n,l,atomk,atoml,atomn,atom1,atom2,atom3,atom4;
   int atomi,atomj,itype,jtype,ktype,ltype,ntype;
   double rik[3], rjl[3], rkn[3],rknmag,dNki;
   double NijC,NijH,NjiC,NjiH,wik,dwik,dwkn,wjl;
   double rikmag,rjlmag,cosjik,cosijl,g,tmp2,tmp3;
   double Etmp,pij,tmp,wij,dwij,NconjtmpI,NconjtmpJ;
   double Nki,Nlj,dS,lamdajik,lamdaijl,dgdc,dgdN,pji,Nijconj,piRC;
   double dcosjikdri[3],dcosijldri[3],dcosjikdrk[3];
   double dN2[2],dN3[3];
   double dcosijldrj[3],dcosijldrl[3],dcosjikdrj[3],dwjl;
   double Tij,crosskij[3],crosskijmag;
   double crossijl[3],crossijlmag,omkijl;
   double tmppij,tmppji,dN2PIJ[2],dN2PJI[2],dN3piRC[3],dN3Tij[3];
   double bij,tmp3pij,tmp3pji,Stb,dStb;
   double r32[3],r32mag,cos321;
   double om1234,rln[3];
   double rlnmag,dwln,r23[3],r23mag,r21[3],r21mag;
   double w21,dw21,r34[3],r34mag,cos234,w34,dw34;
   double cross321[3],cross234[3],prefactor,SpN;
   double fcijpc,fcikpc,fcjlpc,fcjkpc,fcilpc;
   double dt2dik[3],dt2djl[3],dt2dij[3],aa,aaa1,aaa2,at2,cw,cwnum,cwnom;
   double sin321,sin234,rr,rijrik,rijrjl,rjk2,rik2,ril2,rjl2;
   double dctik,dctjk,dctjl,dctij,dctji,dctil,rik2i,rjl2i,sink2i,sinl2i;
   double rjk[3],ril[3],dt1dik,dt1djk,dt1djl,dt1dil,dt1dij;
   double dNlj;
   double PijS,PjiS;
   double rij2,tspjik,dtsjik,tspijl,dtsijl,costmp;
   int *REBO_neighs,*REBO_neighs_i,*REBO_neighs_j,*REBO_neighs_k,*REBO_neighs_l;
   double F12[3],F23[3],F34[3],F31[3],F24[3];
   double fi[3],fj[3],fk[3],fl[3],f1[3],f2[3],f3[3],f4[4];
   double rji[3],rki[3],rlj[3],r13[3],r43[3];
 
   double **x = atom->x;
   int *type = atom->type;
 
   atomi = i;
   atomj = j;
   itype = map[type[atomi]];
   jtype = map[type[atomj]];
   wij = Sp(rij0mag,rcmin[itype][jtype],rcmax[itype][jtype],dwij);
   NijC = nC[atomi]-(wij*kronecker(jtype,0));
   NijH = nH[atomi]-(wij*kronecker(jtype,1));
   NjiC = nC[atomj]-(wij*kronecker(itype,0));
   NjiH = nH[atomj]-(wij*kronecker(itype,1));
 
   bij = 0.0;
   tmp = 0.0;
   tmp2 = 0.0;
   tmp3 = 0.0;
   dgdc = 0.0;
   dgdN = 0.0;
   NconjtmpI = 0.0;
   NconjtmpJ = 0.0;
   Etmp = 0.0;
   Stb = 0.0;
   dStb = 0.0;
 
   REBO_neighs = REBO_firstneigh[i];
   for (k = 0; k < REBO_numneigh[i]; k++) {
     atomk = REBO_neighs[k];
     if (atomk != atomj) {
       ktype = map[type[atomk]];
       rik[0] = x[atomi][0]-x[atomk][0];
       rik[1] = x[atomi][1]-x[atomk][1];
       rik[2] = x[atomi][2]-x[atomk][2];
       rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2]));
       lamdajik = 4.0*kronecker(itype,1) *
         ((rho[ktype][1]-rikmag)-(rho[jtype][1]-rijmag));
       wik = Sp(rikmag,rcmin[itype][ktype],rcmax[itype][ktype],dS);
       Nki = nC[atomk]-(wik*kronecker(itype,0)) +
         nH[atomk]-(wik*kronecker(itype,1));
       cosjik = ((rij[0]*rik[0])+(rij[1]*rik[1])+(rij[2]*rik[2])) /
         (rijmag*rikmag);
       cosjik = MIN(cosjik,1.0);
       cosjik = MAX(cosjik,-1.0);
 
       // evaluate splines g and derivatives dg
 
       g = gSpline(cosjik,(NijC+NijH),itype,&dgdc,&dgdN);
       Etmp += (wik*g*exp(lamdajik));
       tmp3 += (wik*dgdN*exp(lamdajik));
       NconjtmpI = NconjtmpI+(kronecker(ktype,0)*wik*Sp(Nki,Nmin,Nmax,dS));
     }
   }
 
   PijS = 0.0;
   dN2PIJ[0] = 0.0;
   dN2PIJ[1] = 0.0;
   PijS = PijSpline(NijC,NijH,itype,jtype,dN2PIJ);
   pij = pow(1.0+Etmp+PijS,-0.5);
   tmppij = -.5*cube(pij);
   tmp3pij = tmp3;
   tmp = 0.0;
   tmp2 = 0.0;
   tmp3 = 0.0;
   Etmp = 0.0;
 
   REBO_neighs = REBO_firstneigh[j];
   for (l = 0; l < REBO_numneigh[j]; l++) {
     atoml = REBO_neighs[l];
     if (atoml != atomi) {
       ltype = map[type[atoml]];
       rjl[0] = x[atomj][0]-x[atoml][0];
       rjl[1] = x[atomj][1]-x[atoml][1];
       rjl[2] = x[atomj][2]-x[atoml][2];
       rjlmag = sqrt((rjl[0]*rjl[0])+(rjl[1]*rjl[1])+(rjl[2]*rjl[2]));
       lamdaijl = 4.0*kronecker(jtype,1) *
         ((rho[ltype][1]-rjlmag)-(rho[itype][1]-rijmag));
       wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmax[jtype][ltype],dS);
       Nlj = nC[atoml]-(wjl*kronecker(jtype,0))+nH[atoml] -
         (wjl*kronecker(jtype,1));
       cosijl = -1.0*((rij[0]*rjl[0])+(rij[1]*rjl[1])+(rij[2]*rjl[2])) /
         (rijmag*rjlmag);
       cosijl = MIN(cosijl,1.0);
       cosijl = MAX(cosijl,-1.0);
 
       // evaluate splines g and derivatives dg
 
       g = gSpline(cosijl,NjiC+NjiH,jtype,&dgdc,&dgdN);
       Etmp += (wjl*g*exp(lamdaijl));
       tmp3 += (wjl*dgdN*exp(lamdaijl));
       NconjtmpJ = NconjtmpJ+(kronecker(ltype,0)*wjl*Sp(Nlj,Nmin,Nmax,dS));
     }
   }
 
   PjiS = 0.0;
   dN2PJI[0] = 0.0;
   dN2PJI[1] = 0.0;
   PjiS = PijSpline(NjiC,NjiH,jtype,itype,dN2PJI);
   pji = pow(1.0+Etmp+PjiS,-0.5);
   tmppji = -.5*cube(pji);
   tmp3pji = tmp3;
 
   // evaluate Nij conj
 
   Nijconj = 1.0+(NconjtmpI*NconjtmpI)+(NconjtmpJ*NconjtmpJ);
   piRC = piRCSpline(NijC+NijH,NjiC+NjiH,Nijconj,itype,jtype,dN3piRC);
   Tij = 0.0;
   dN3Tij[0] = 0.0;
   dN3Tij[1] = 0.0;
   dN3Tij[2] = 0.0;
   if (itype == 0 && jtype == 0)
     Tij=TijSpline((NijC+NijH),(NjiC+NjiH),Nijconj,dN3Tij);
 
   Etmp = 0.0;
   if (fabs(Tij) > TOL) {
     REBO_neighs_i = REBO_firstneigh[i];
     for (k = 0; k < REBO_numneigh[i]; k++) {
       atomk = REBO_neighs_i[k];
       ktype = map[type[atomk]];
       if (atomk != atomj) {
         rik[0] = x[atomi][0]-x[atomk][0];
         rik[1] = x[atomi][1]-x[atomk][1];
         rik[2] = x[atomi][2]-x[atomk][2];
         rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2]));
         cos321 = ((rij[0]*rik[0])+(rij[1]*rik[1])+(rij[2]*rik[2])) /
           (rijmag*rikmag);
         cos321 = MIN(cos321,1.0);
         cos321 = MAX(cos321,-1.0);
 
         rjk[0] = rik[0]-rij[0];
         rjk[1] = rik[1]-rij[1];
         rjk[2] = rik[2]-rij[2];
         rjk2 = (rjk[0]*rjk[0])+(rjk[1]*rjk[1])+(rjk[2]*rjk[2]);
         rij2 = rijmag*rijmag;
         rik2 = rikmag*rikmag;
         costmp = 0.5*(rij2+rik2-rjk2)/rijmag/rikmag;
         tspjik = Sp2(costmp,thmin,thmax,dtsjik);
 
         if (sqrt(1.0 - cos321*cos321) > sqrt(TOL)) {
           wik = Sp(rikmag,rcmin[itype][ktype],rcmaxp[itype][ktype],dwik);
           REBO_neighs_j = REBO_firstneigh[j];
           for (l = 0; l < REBO_numneigh[j]; l++) {
             atoml = REBO_neighs_j[l];
             ltype = map[type[atoml]];
             if (!(atoml == atomi || atoml == atomk)) {
               rjl[0] = x[atomj][0]-x[atoml][0];
               rjl[1] = x[atomj][1]-x[atoml][1];
               rjl[2] = x[atomj][2]-x[atoml][2];
               rjlmag = sqrt(rjl[0]*rjl[0] + rjl[1]*rjl[1] + rjl[2]*rjl[2]);
               cos234 = -((rij[0]*rjl[0])+(rij[1]*rjl[1])+(rij[2]*rjl[2])) /
                 (rijmag*rjlmag);
               cos234 = MIN(cos234,1.0);
               cos234 = MAX(cos234,-1.0);
 
               ril[0] = rij[0]+rjl[0];
               ril[1] = rij[1]+rjl[1];
               ril[2] = rij[2]+rjl[2];
               ril2 = (ril[0]*ril[0])+(ril[1]*ril[1])+(ril[2]*ril[2]);
               rijrjl = 2.0*rijmag*rjlmag;
               rjl2 = rjlmag*rjlmag;
               costmp = 0.5*(rij2+rjl2-ril2)/rijmag/rjlmag;
               tspijl = Sp2(costmp,thmin,thmax,dtsijl);
 
               if (sqrt(1.0 - cos234*cos234) > sqrt(TOL)) {
                 wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmaxp[jtype][ltype],dS);
                 crosskij[0] = (rij[1]*rik[2]-rij[2]*rik[1]);
                 crosskij[1] = (rij[2]*rik[0]-rij[0]*rik[2]);
                 crosskij[2] = (rij[0]*rik[1]-rij[1]*rik[0]);
                 crosskijmag = sqrt(crosskij[0]*crosskij[0] +
                                    crosskij[1]*crosskij[1] +
                                    crosskij[2]*crosskij[2]);
                 crossijl[0] = (rij[1]*rjl[2]-rij[2]*rjl[1]);
                 crossijl[1] = (rij[2]*rjl[0]-rij[0]*rjl[2]);
                 crossijl[2] = (rij[0]*rjl[1]-rij[1]*rjl[0]);
                 crossijlmag = sqrt(crossijl[0]*crossijl[0] +
                                    crossijl[1]*crossijl[1] +
                                    crossijl[2]*crossijl[2]);
                 omkijl = -1.0*(((crosskij[0]*crossijl[0]) +
                                 (crosskij[1]*crossijl[1]) +
                                 (crosskij[2]*crossijl[2])) /
                                (crosskijmag*crossijlmag));
                 Etmp += ((1.0-square(omkijl))*wik*wjl) *
                   (1.0-tspjik)*(1.0-tspijl);
               }
             }
           }
         }
       }
     }
   }
 
   bij = (.5*(pij+pji))+piRC+(Tij*Etmp);
   Stb = Sp2(bij,bLJmin[itype][jtype],bLJmax[itype][jtype],dStb);
   VA = VA*dStb;
 
   if (dStb != 0.0) {
     tmp = tmppij;
     dN2[0] = dN2PIJ[0];
     dN2[1] = dN2PIJ[1];
     tmp3 = tmp3pij;
 
     // pij forces
 
     REBO_neighs_i = REBO_firstneigh[i];
     for (k = 0; k < REBO_numneigh[i]; k++) {
       atomk = REBO_neighs_i[k];
       if (atomk != atomj) {
         lamdajik = 0.0;
         rik[0] = x[atomi][0]-x[atomk][0];
         rik[1] = x[atomi][1]-x[atomk][1];
         rik[2] = x[atomi][2]-x[atomk][2];
         rikmag = sqrt(rik[0]*rik[0] + rik[1]*rik[1] + rik[2]*rik[2]);
         lamdajik = 4.0*kronecker(itype,1) *
           ((rho[ktype][1]-rikmag)-(rho[jtype][1]-rijmag));
         wik = Sp(rikmag,rcmin[itype][ktype],rcmax[itype][ktype],dwik);
         cosjik = ((rij[0]*rik[0])+(rij[1]*rik[1])+(rij[2]*rik[2])) /
           (rijmag*rikmag);
         cosjik = MIN(cosjik,1.0);
         cosjik = MAX(cosjik,-1.0);
 
         dcosjikdri[0] = ((rij[0]+rik[0])/(rijmag*rikmag)) -
           (cosjik*((rij[0]/(rijmag*rijmag))+(rik[0]/(rikmag*rikmag))));
         dcosjikdri[1] = ((rij[1]+rik[1])/(rijmag*rikmag)) -
           (cosjik*((rij[1]/(rijmag*rijmag))+(rik[1]/(rikmag*rikmag))));
         dcosjikdri[2] = ((rij[2]+rik[2])/(rijmag*rikmag)) -
           (cosjik*((rij[2]/(rijmag*rijmag))+(rik[2]/(rikmag*rikmag))));
         dcosjikdrk[0] = (-rij[0]/(rijmag*rikmag)) +
           (cosjik*(rik[0]/(rikmag*rikmag)));
         dcosjikdrk[1] = (-rij[1]/(rijmag*rikmag)) +
           (cosjik*(rik[1]/(rikmag*rikmag)));
         dcosjikdrk[2] = (-rij[2]/(rijmag*rikmag)) +
           (cosjik*(rik[2]/(rikmag*rikmag)));
         dcosjikdrj[0] = (-rik[0]/(rijmag*rikmag)) +
           (cosjik*(rij[0]/(rijmag*rijmag)));
         dcosjikdrj[1] = (-rik[1]/(rijmag*rikmag)) +
           (cosjik*(rij[1]/(rijmag*rijmag)));
         dcosjikdrj[2] = (-rik[2]/(rijmag*rikmag)) +
           (cosjik*(rij[2]/(rijmag*rijmag)));
 
         g = gSpline(cosjik,(NijC+NijH),itype,&dgdc,&dgdN);
 
         tmp2 = VA*.5*(tmp*wik*dgdc*exp(lamdajik));
         fj[0] = -tmp2*dcosjikdrj[0];
         fj[1] = -tmp2*dcosjikdrj[1];
         fj[2] = -tmp2*dcosjikdrj[2];
         fi[0] = -tmp2*dcosjikdri[0];
         fi[1] = -tmp2*dcosjikdri[1];
         fi[2] = -tmp2*dcosjikdri[2];
         fk[0] = -tmp2*dcosjikdrk[0];
         fk[1] = -tmp2*dcosjikdrk[1];
         fk[2] = -tmp2*dcosjikdrk[2];
 
         tmp2 = VA*.5*(tmp*wik*g*exp(lamdajik)*4.0*kronecker(itype,1));
         fj[0] -= tmp2*(-rij[0]/rijmag);
         fj[1] -= tmp2*(-rij[1]/rijmag);
         fj[2] -= tmp2*(-rij[2]/rijmag);
         fi[0] -= tmp2*((-rik[0]/rikmag)+(rij[0]/rijmag));
         fi[1] -= tmp2*((-rik[1]/rikmag)+(rij[1]/rijmag));
         fi[2] -= tmp2*((-rik[2]/rikmag)+(rij[2]/rijmag));
         fk[0] -= tmp2*(rik[0]/rikmag);
         fk[1] -= tmp2*(rik[1]/rikmag);
         fk[2] -= tmp2*(rik[2]/rikmag);
 
         // coordination forces
 
         // dwik forces
 
         tmp2 = VA*.5*(tmp*dwik*g*exp(lamdajik))/rikmag;
         fi[0] -= tmp2*rik[0];
         fi[1] -= tmp2*rik[1];
         fi[2] -= tmp2*rik[2];
         fk[0] += tmp2*rik[0];
         fk[1] += tmp2*rik[1];
         fk[2] += tmp2*rik[2];
 
         // PIJ forces
 
         tmp2 = VA*.5*(tmp*dN2[ktype]*dwik)/rikmag;
         fi[0] -= tmp2*rik[0];
         fi[1] -= tmp2*rik[1];
         fi[2] -= tmp2*rik[2];
         fk[0] += tmp2*rik[0];
         fk[1] += tmp2*rik[1];
         fk[2] += tmp2*rik[2];
 
         // dgdN forces
 
         tmp2 = VA*.5*(tmp*tmp3*dwik)/rikmag;
         fi[0] -= tmp2*rik[0];
         fi[1] -= tmp2*rik[1];
         fi[2] -= tmp2*rik[2];
         fk[0] += tmp2*rik[0];
         fk[1] += tmp2*rik[1];
         fk[2] += tmp2*rik[2];
 
         f[atomi][0] += fi[0]; f[atomi][1] += fi[1]; f[atomi][2] += fi[2];
         f[atomj][0] += fj[0]; f[atomj][1] += fj[1]; f[atomj][2] += fj[2];
         f[atomk][0] += fk[0]; f[atomk][1] += fk[1]; f[atomk][2] += fk[2];
 
         if (vflag_atom) {
           rji[0] = -rij[0]; rji[1] = -rij[1]; rji[2] = -rij[2];
           rki[0] = -rik[0]; rki[1] = -rik[1]; rki[2] = -rik[2];
           v_tally3(atomi,atomj,atomk,fj,fk,rji,rki);
         }
       }
     }
 
     tmp = tmppji;
     tmp3 = tmp3pji;
     dN2[0] = dN2PJI[0];
     dN2[1] = dN2PJI[1];
     REBO_neighs  =  REBO_firstneigh[j];
     for (l = 0; l < REBO_numneigh[j]; l++) {
       atoml = REBO_neighs[l];
       if (atoml !=atomi) {
         ltype = map[type[atoml]];
         rjl[0] = x[atomj][0]-x[atoml][0];
         rjl[1] = x[atomj][1]-x[atoml][1];
         rjl[2] = x[atomj][2]-x[atoml][2];
         rjlmag = sqrt((rjl[0]*rjl[0])+(rjl[1]*rjl[1])+(rjl[2]*rjl[2]));
         lamdaijl = 4.0*kronecker(jtype,1) *
           ((rho[ltype][1]-rjlmag)-(rho[itype][1]-rijmag));
         wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmax[jtype][ltype],dwjl);
         cosijl = (-1.0*((rij[0]*rjl[0])+(rij[1]*rjl[1])+(rij[2]*rjl[2]))) /
           (rijmag*rjlmag);
         cosijl = MIN(cosijl,1.0);
         cosijl = MAX(cosijl,-1.0);
 
         dcosijldri[0] = (-rjl[0]/(rijmag*rjlmag)) -
           (cosijl*rij[0]/(rijmag*rijmag));
         dcosijldri[1] = (-rjl[1]/(rijmag*rjlmag)) -
           (cosijl*rij[1]/(rijmag*rijmag));
         dcosijldri[2] = (-rjl[2]/(rijmag*rjlmag)) -
           (cosijl*rij[2]/(rijmag*rijmag));
         dcosijldrj[0] = ((-rij[0]+rjl[0])/(rijmag*rjlmag)) +
           (cosijl*((rij[0]/square(rijmag))-(rjl[0]/(rjlmag*rjlmag))));
         dcosijldrj[1] = ((-rij[1]+rjl[1])/(rijmag*rjlmag)) +
           (cosijl*((rij[1]/square(rijmag))-(rjl[1]/(rjlmag*rjlmag))));
         dcosijldrj[2] = ((-rij[2]+rjl[2])/(rijmag*rjlmag)) +
           (cosijl*((rij[2]/square(rijmag))-(rjl[2]/(rjlmag*rjlmag))));
         dcosijldrl[0] = (rij[0]/(rijmag*rjlmag)) +
           (cosijl*rjl[0]/(rjlmag*rjlmag));
         dcosijldrl[1] = (rij[1]/(rijmag*rjlmag)) +
           (cosijl*rjl[1]/(rjlmag*rjlmag));
         dcosijldrl[2] = (rij[2]/(rijmag*rjlmag)) +
           (cosijl*rjl[2]/(rjlmag*rjlmag));
 
         // evaluate splines g and derivatives dg
 
         g = gSpline(cosijl,NjiC+NjiH,jtype,&dgdc,&dgdN);
         tmp2 = VA*.5*(tmp*wjl*dgdc*exp(lamdaijl));
         fi[0] = -tmp2*dcosijldri[0];
         fi[1] = -tmp2*dcosijldri[1];
         fi[2] = -tmp2*dcosijldri[2];
         fj[0] = -tmp2*dcosijldrj[0];
         fj[1] = -tmp2*dcosijldrj[1];
         fj[2] = -tmp2*dcosijldrj[2];
         fl[0] = -tmp2*dcosijldrl[0];
         fl[1] = -tmp2*dcosijldrl[1];
         fl[2] = -tmp2*dcosijldrl[2];
 
         tmp2 = VA*.5*(tmp*wjl*g*exp(lamdaijl)*4.0*kronecker(jtype,1));
         fi[0] -= tmp2*(rij[0]/rijmag);
         fi[1] -= tmp2*(rij[1]/rijmag);
         fi[2] -= tmp2*(rij[2]/rijmag);
         fj[0] -= tmp2*((-rjl[0]/rjlmag)-(rij[0]/rijmag));
         fj[1] -= tmp2*((-rjl[1]/rjlmag)-(rij[1]/rijmag));
         fj[2] -= tmp2*((-rjl[2]/rjlmag)-(rij[2]/rijmag));
         fl[0] -= tmp2*(rjl[0]/rjlmag);
         fl[1] -= tmp2*(rjl[1]/rjlmag);
         fl[2] -= tmp2*(rjl[2]/rjlmag);
 
          // coordination forces
         // dwik forces
 
         tmp2 = VA*.5*(tmp*dwjl*g*exp(lamdaijl))/rjlmag;
         fj[0] -= tmp2*rjl[0];
         fj[1] -= tmp2*rjl[1];
         fj[2] -= tmp2*rjl[2];
         fl[0] += tmp2*rjl[0];
         fl[1] += tmp2*rjl[1];
         fl[2] += tmp2*rjl[2];
 
         // PIJ forces
 
         tmp2 = VA*.5*(tmp*dN2[ltype]*dwjl)/rjlmag;
         fj[0] -= tmp2*rjl[0];
         fj[1] -= tmp2*rjl[1];
         fj[2] -= tmp2*rjl[2];
         fl[0] += tmp2*rjl[0];
         fl[1] += tmp2*rjl[1];
         fl[2] += tmp2*rjl[2];
 
         // dgdN forces
 
         tmp2=VA*.5*(tmp*tmp3*dwjl)/rjlmag;
         fj[0] -= tmp2*rjl[0];
         fj[1] -= tmp2*rjl[1];
         fj[2] -= tmp2*rjl[2];
         fl[0] += tmp2*rjl[0];
         fl[1] += tmp2*rjl[1];
         fl[2] += tmp2*rjl[2];
 
         f[atomi][0] += fi[0]; f[atomi][1] += fi[1]; f[atomi][2] += fi[2];
         f[atomj][0] += fj[0]; f[atomj][1] += fj[1]; f[atomj][2] += fj[2];
         f[atoml][0] += fl[0]; f[atoml][1] += fl[1]; f[atoml][2] += fl[2];
 
         if (vflag_atom) {
           rlj[0] = -rjl[0]; rlj[1] = -rjl[1]; rlj[2] = -rjl[2];
           v_tally3(atomi,atomj,atoml,fi,fl,rij,rlj);
         }
       }
     }
 
     // piRC forces
 
     dN3[0] = dN3piRC[0];
     dN3[1] = dN3piRC[1];
     dN3[2] = dN3piRC[2];
 
     REBO_neighs_i = REBO_firstneigh[i];
     for (k = 0; k < REBO_numneigh[i]; k++) {
       atomk = REBO_neighs_i[k];
       if (atomk != atomj) {
         ktype = map[type[atomk]];
         rik[0] = x[atomi][0]-x[atomk][0];
         rik[1] = x[atomi][1]-x[atomk][1];
         rik[2] = x[atomi][2]-x[atomk][2];
         rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2]));
         wik = Sp(rikmag,rcmin[itype][ktype],rcmax[itype][ktype],dwik);
         Nki = nC[atomk]-(wik*kronecker(itype,0))+nH[atomk] -
           (wik*kronecker(itype,1));
         SpN = Sp(Nki,Nmin,Nmax,dNki);
 
         tmp2 = VA*dN3[0]*dwik/rikmag;
         f[atomi][0] -= tmp2*rik[0];
         f[atomi][1] -= tmp2*rik[1];
         f[atomi][2] -= tmp2*rik[2];
         f[atomk][0] += tmp2*rik[0];
         f[atomk][1] += tmp2*rik[1];
         f[atomk][2] += tmp2*rik[2];
 
         if (vflag_atom) v_tally2(atomi,atomk,-tmp2,rik);
 
         tmp2 = VA*dN3[2]*(2.0*NconjtmpI*dwik*SpN)/rikmag;
         f[atomi][0] -= tmp2*rik[0];
         f[atomi][1] -= tmp2*rik[1];
         f[atomi][2] -= tmp2*rik[2];
         f[atomk][0] += tmp2*rik[0];
         f[atomk][1] += tmp2*rik[1];
         f[atomk][2] += tmp2*rik[2];
 
         if (vflag_atom) v_tally2(atomi,atomk,-tmp2,rik);
 
         if (fabs(dNki) > TOL) {
           REBO_neighs_k = REBO_firstneigh[atomk];
           for (n = 0; n < REBO_numneigh[atomk]; n++) {
             atomn = REBO_neighs_k[n];
             if (atomn != atomi) {
               ntype = map[type[atomn]];
               rkn[0] = x[atomk][0]-x[atomn][0];
               rkn[1] = x[atomk][1]-x[atomn][1];
               rkn[2] = x[atomk][2]-x[atomn][2];
               rknmag = sqrt((rkn[0]*rkn[0])+(rkn[1]*rkn[1])+(rkn[2]*rkn[2]));
               Sp(rknmag,rcmin[ktype][ntype],rcmax[ktype][ntype],dwkn);
 
               tmp2 = VA*dN3[2]*(2.0*NconjtmpI*wik*dNki*dwkn)/rknmag;
               f[atomk][0] -= tmp2*rkn[0];
               f[atomk][1] -= tmp2*rkn[1];
               f[atomk][2] -= tmp2*rkn[2];
               f[atomn][0] += tmp2*rkn[0];
               f[atomn][1] += tmp2*rkn[1];
               f[atomn][2] += tmp2*rkn[2];
 
               if (vflag_atom) v_tally2(atomk,atomn,-tmp2,rkn);
             }
           }
         }
       }
     }
 
     // piRC forces to J side
 
     REBO_neighs = REBO_firstneigh[j];
     for (l = 0; l < REBO_numneigh[j]; l++) {
       atoml = REBO_neighs[l];
       if (atoml != atomi) {
         ltype = map[type[atoml]];
         rjl[0] = x[atomj][0]-x[atoml][0];
         rjl[1] = x[atomj][1]-x[atoml][1];
         rjl[2] = x[atomj][2]-x[atoml][2];
         rjlmag = sqrt((rjl[0]*rjl[0])+(rjl[1]*rjl[1])+(rjl[2]*rjl[2]));
         wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmax[jtype][ltype],dwjl);
         Nlj = nC[atoml]-(wjl*kronecker(jtype,0))+nH[atoml] -
           (wjl*kronecker(jtype,1));
         SpN = Sp(Nlj,Nmin,Nmax,dNlj);
 
         tmp2 = VA*dN3[1]*dwjl/rjlmag;
         f[atomj][0] -= tmp2*rjl[0];
         f[atomj][1] -= tmp2*rjl[1];
         f[atomj][2] -= tmp2*rjl[2];
         f[atoml][0] += tmp2*rjl[0];
         f[atoml][1] += tmp2*rjl[1];
         f[atoml][2] += tmp2*rjl[2];
 
         if (vflag_atom) v_tally2(atomj,atoml,-tmp2,rjl);
 
         tmp2 = VA*dN3[2]*(2.0*NconjtmpJ*dwjl*SpN)/rjlmag;
         f[atomj][0] -= tmp2*rjl[0];
         f[atomj][1] -= tmp2*rjl[1];
         f[atomj][2] -= tmp2*rjl[2];
         f[atoml][0] += tmp2*rjl[0];
         f[atoml][1] += tmp2*rjl[1];
         f[atoml][2] += tmp2*rjl[2];
 
         if (vflag_atom) v_tally2(atomj,atoml,-tmp2,rjl);
 
         if (fabs(dNlj) > TOL) {
           REBO_neighs_l = REBO_firstneigh[atoml];
           for (n = 0; n < REBO_numneigh[atoml]; n++) {
             atomn = REBO_neighs_l[n];
             if (atomn != atomj) {
               ntype = map[type[atomn]];
               rln[0] = x[atoml][0]-x[atomn][0];
               rln[1] = x[atoml][1]-x[atomn][1];
               rln[2] = x[atoml][2]-x[atomn][2];
               rlnmag = sqrt((rln[0]*rln[0])+(rln[1]*rln[1])+(rln[2]*rln[2]));
               Sp(rlnmag,rcmin[ltype][ntype],rcmax[ltype][ntype],dwln);
 
               tmp2 = VA*dN3[2]*(2.0*NconjtmpJ*wjl*dNlj*dwln)/rlnmag;
               f[atoml][0] -= tmp2*rln[0];
               f[atoml][1] -= tmp2*rln[1];
               f[atoml][2] -= tmp2*rln[2];
               f[atomn][0] += tmp2*rln[0];
               f[atomn][1] += tmp2*rln[1];
               f[atomn][2] += tmp2*rln[2];
 
               if (vflag_atom) v_tally2(atoml,atomn,-tmp2,rln);
             }
           }
         }
       }
     }
 
     if (fabs(Tij) > TOL) {
       dN3[0] = dN3Tij[0];
       dN3[1] = dN3Tij[1];
       dN3[2] = dN3Tij[2];
       atom2 = atomi;
       atom3 = atomj;
       r32[0] = x[atom3][0]-x[atom2][0];
       r32[1] = x[atom3][1]-x[atom2][1];
       r32[2] = x[atom3][2]-x[atom2][2];
       r32mag = sqrt((r32[0]*r32[0])+(r32[1]*r32[1])+(r32[2]*r32[2]));
       r23[0] = -r32[0];
       r23[1] = -r32[1];
       r23[2] = -r32[2];
       r23mag = r32mag;
 
       REBO_neighs_i = REBO_firstneigh[i];
       for (k = 0; k < REBO_numneigh[i]; k++) {
         atomk = REBO_neighs_i[k];
         atom1 = atomk;
         ktype = map[type[atomk]];
         if (atomk != atomj) {
           r21[0] = x[atom2][0]-x[atom1][0];
           r21[1] = x[atom2][1]-x[atom1][1];
           r21[2] = x[atom2][2]-x[atom1][2];
           r21mag = sqrt(r21[0]*r21[0] + r21[1]*r21[1] + r21[2]*r21[2]);
           cos321 = ((r21[0]*rij[0])+(r21[1]*rij[1])+(r21[2]*rij[2])) /
             (r21mag*rijmag);
           cos321 = MIN(cos321,1.0);
           cos321 = MAX(cos321,-1.0);
           sin321 = sqrt(1.0 - cos321*cos321);
           sink2i = 1.0/(sin321*sin321);
           rik2i = 1.0/(r21mag*r21mag);
 
           if (sin321 != 0.0) {
             rr = (rijmag*rijmag)-(r21mag*r21mag);
             rjk[0] = r21[0]-rij[0];
             rjk[1] = r21[1]-rij[1];
             rjk[2] = r21[2]-rij[2];
             rjk2 = (rjk[0]*rjk[0])+(rjk[1]*rjk[1])+(rjk[2]*rjk[2]);
             rijrik = 2.0*rijmag*r21mag;
             rik2 = r21mag*r21mag;
             dctik = (-rr+rjk2)/(rijrik*rik2);
             dctij = (rr+rjk2)/(rijrik*rijmag*rijmag);
             dctjk = -2.0/rijrik;
             w21 = Sp(r21mag,rcmin[itype][ktype],rcmaxp[itype][ktype],dw21);
             rikmag = r21mag;
             rij2 = r32mag*r32mag;
             rik2 = r21mag*r21mag;
             costmp = 0.5*(rij2+rik2-rjk2)/rijmag/rikmag;
             tspjik = Sp2(costmp,thmin,thmax,dtsjik);
             dtsjik = -dtsjik;
 
             REBO_neighs_j = REBO_firstneigh[j];
             for (l = 0; l < REBO_numneigh[j]; l++) {
               atoml = REBO_neighs_j[l];
               atom4 = atoml;
               ltype = map[type[atoml]];
               if (!(atoml == atomi || atoml == atomk)) {
                 r34[0] = x[atom3][0]-x[atom4][0];
                 r34[1] = x[atom3][1]-x[atom4][1];
                 r34[2] = x[atom3][2]-x[atom4][2];
                 r34mag = sqrt(r34[0]*r34[0] + r34[1]*r34[1] + r34[2]*r34[2]);
                 cos234 = -1.0*((rij[0]*r34[0])+(rij[1]*r34[1]) +
                                (rij[2]*r34[2]))/(rijmag*r34mag);
                 cos234 = MIN(cos234,1.0);
                 cos234 = MAX(cos234,-1.0);
                 sin234 = sqrt(1.0 - cos234*cos234);
                 sinl2i = 1.0/(sin234*sin234);
                 rjl2i = 1.0/(r34mag*r34mag);
 
                 if (sin234 != 0.0) {
                   w34 = Sp(r34mag,rcmin[jtype][ltype],
                            rcmaxp[jtype][ltype],dw34);
                   rr = (r23mag*r23mag)-(r34mag*r34mag);
                   ril[0] = r23[0]+r34[0];
                   ril[1] = r23[1]+r34[1];
                   ril[2] = r23[2]+r34[2];
                   ril2 = (ril[0]*ril[0])+(ril[1]*ril[1])+(ril[2]*ril[2]);
                   rijrjl = 2.0*r23mag*r34mag;
                   rjl2 = r34mag*r34mag;
                   dctjl = (-rr+ril2)/(rijrjl*rjl2);
                   dctji = (rr+ril2)/(rijrjl*r23mag*r23mag);
                   dctil = -2.0/rijrjl;
                   rjlmag = r34mag;
                   rjl2 = r34mag*r34mag;
                   costmp = 0.5*(rij2+rjl2-ril2)/rijmag/rjlmag;
                   tspijl = Sp2(costmp,thmin,thmax,dtsijl);
                   dtsijl = -dtsijl; //need minus sign
                   prefactor = VA*Tij;
 
                   cross321[0] = (r32[1]*r21[2])-(r32[2]*r21[1]);
                   cross321[1] = (r32[2]*r21[0])-(r32[0]*r21[2]);
                   cross321[2] = (r32[0]*r21[1])-(r32[1]*r21[0]);
                   cross234[0] = (r23[1]*r34[2])-(r23[2]*r34[1]);
                   cross234[1] = (r23[2]*r34[0])-(r23[0]*r34[2]);
                   cross234[2] = (r23[0]*r34[1])-(r23[1]*r34[0]);
 
                   cwnum = (cross321[0]*cross234[0]) +
                     (cross321[1]*cross234[1])+(cross321[2]*cross234[2]);
                   cwnom = r21mag*r34mag*r23mag*r23mag*sin321*sin234;
                   om1234 = cwnum/cwnom;
                   cw = om1234;
                   Etmp += ((1.0-square(om1234))*w21*w34) *
                     (1.0-tspjik)*(1.0-tspijl);
 
                   dt1dik = (rik2i)-(dctik*sink2i*cos321);
                   dt1djk = (-dctjk*sink2i*cos321);
                   dt1djl = (rjl2i)-(dctjl*sinl2i*cos234);
                   dt1dil = (-dctil*sinl2i*cos234);
                   dt1dij = (2.0/(r23mag*r23mag)) -
                     (dctij*sink2i*cos321)-(dctji*sinl2i*cos234);
 
                   dt2dik[0] = (-r23[2]*cross234[1])+(r23[1]*cross234[2]);
                   dt2dik[1] = (-r23[0]*cross234[2])+(r23[2]*cross234[0]);
                   dt2dik[2] = (-r23[1]*cross234[0])+(r23[0]*cross234[1]);
 
                   dt2djl[0] = (-r23[1]*cross321[2])+(r23[2]*cross321[1]);
                   dt2djl[1] = (-r23[2]*cross321[0])+(r23[0]*cross321[2]);
                   dt2djl[2] = (-r23[0]*cross321[1])+(r23[1]*cross321[0]);
 
                   dt2dij[0] = (r21[2]*cross234[1]) -
                     (r34[2]*cross321[1])-(r21[1]*cross234[2]) +
                     (r34[1]*cross321[2]);
                   dt2dij[1] = (r21[0]*cross234[2]) -
                     (r34[0]*cross321[2])-(r21[2]*cross234[0]) +
                     (r34[2]*cross321[0]);
                   dt2dij[2] = (r21[1]*cross234[0]) -
                     (r34[1]*cross321[0])-(r21[0]*cross234[1]) +
                     (r34[0]*cross321[1]);
 
                   aa = (prefactor*2.0*cw/cwnom)*w21*w34 *
                     (1.0-tspjik)*(1.0-tspijl);
                   aaa1 = -prefactor*(1.0-square(om1234)) *
                     (1.0-tspjik)*(1.0-tspijl);
                   aaa2 = aaa1*w21*w34;
                   at2 = aa*cwnum;
 
                   fcijpc = (-dt1dij*at2)+(aaa2*dtsjik*dctij*(1.0-tspijl)) +
                     (aaa2*dtsijl*dctji*(1.0-tspjik));
                   fcikpc = (-dt1dik*at2)+(aaa2*dtsjik*dctik*(1.0-tspijl));
                   fcjlpc = (-dt1djl*at2)+(aaa2*dtsijl*dctjl*(1.0-tspjik));
                   fcjkpc = (-dt1djk*at2)+(aaa2*dtsjik*dctjk*(1.0-tspijl));
                   fcilpc = (-dt1dil*at2)+(aaa2*dtsijl*dctil*(1.0-tspjik));
 
                   F23[0] = (fcijpc*r23[0])+(aa*dt2dij[0]);
                   F23[1] = (fcijpc*r23[1])+(aa*dt2dij[1]);
                   F23[2] = (fcijpc*r23[2])+(aa*dt2dij[2]);
 
                   F12[0] = (fcikpc*r21[0])+(aa*dt2dik[0]);
                   F12[1] = (fcikpc*r21[1])+(aa*dt2dik[1]);
                   F12[2] = (fcikpc*r21[2])+(aa*dt2dik[2]);
 
                   F34[0] = (fcjlpc*r34[0])+(aa*dt2djl[0]);
                   F34[1] = (fcjlpc*r34[1])+(aa*dt2djl[1]);
                   F34[2] = (fcjlpc*r34[2])+(aa*dt2djl[2]);
 
                   F31[0] = (fcjkpc*rjk[0]);
                   F31[1] = (fcjkpc*rjk[1]);
                   F31[2] = (fcjkpc*rjk[2]);
 
                   F24[0] = (fcilpc*ril[0]);
                   F24[1] = (fcilpc*ril[1]);
                   F24[2] = (fcilpc*ril[2]);
 
                   f1[0] = -F12[0]-F31[0];
                   f1[1] = -F12[1]-F31[1];
                   f1[2] = -F12[2]-F31[2];
                   f2[0] = F23[0]+F12[0]+F24[0];
                   f2[1] = F23[1]+F12[1]+F24[1];
                   f2[2] = F23[2]+F12[2]+F24[2];
                   f3[0] = -F23[0]+F34[0]+F31[0];
                   f3[1] = -F23[1]+F34[1]+F31[1];
                   f3[2] = -F23[2]+F34[2]+F31[2];
                   f4[0] = -F34[0]-F24[0];
                   f4[1] = -F34[1]-F24[1];
                   f4[2] = -F34[2]-F24[2];
 
                   // coordination forces
 
                   tmp2 = VA*Tij*((1.0-(om1234*om1234))) *
                     (1.0-tspjik)*(1.0-tspijl)*dw21*w34/r21mag;
                   f2[0] -= tmp2*r21[0];
                   f2[1] -= tmp2*r21[1];
                   f2[2] -= tmp2*r21[2];
                   f1[0] += tmp2*r21[0];
                   f1[1] += tmp2*r21[1];
                   f1[2] += tmp2*r21[2];
 
                   tmp2 = VA*Tij*((1.0-(om1234*om1234))) *
                     (1.0-tspjik)*(1.0-tspijl)*w21*dw34/r34mag;
                   f3[0] -= tmp2*r34[0];
                   f3[1] -= tmp2*r34[1];
                   f3[2] -= tmp2*r34[2];
                   f4[0] += tmp2*r34[0];
                   f4[1] += tmp2*r34[1];
                   f4[2] += tmp2*r34[2];
 
                   f[atom1][0] += f1[0]; f[atom1][1] += f1[1];
                   f[atom1][2] += f1[2];
                   f[atom2][0] += f2[0]; f[atom2][1] += f2[1];
                   f[atom2][2] += f2[2];
                   f[atom3][0] += f3[0]; f[atom3][1] += f3[1];
                   f[atom3][2] += f3[2];
                   f[atom4][0] += f4[0]; f[atom4][1] += f4[1];
                   f[atom4][2] += f4[2];
 
                   if (vflag_atom) {
                     r13[0] = -rjk[0]; r13[1] = -rjk[1]; r13[2] = -rjk[2];
                     r43[0] = -r34[0]; r43[1] = -r34[1]; r43[2] = -r34[2];
                     v_tally4(atom1,atom2,atom3,atom4,f1,f2,f4,r13,r23,r43);
                   }
                 }
               }
             }
           }
         }
       }
 
       REBO_neighs = REBO_firstneigh[i];
       for (k = 0; k < REBO_numneigh[i]; k++) {
         atomk = REBO_neighs[k];
         if (atomk != atomj) {
           ktype = map[type[atomk]];
           rik[0] = x[atomi][0]-x[atomk][0];
           rik[1] = x[atomi][1]-x[atomk][1];
           rik[2] = x[atomi][2]-x[atomk][2];
           rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2]));
           wik = Sp(rikmag,rcmin[itype][ktype],rcmax[itype][ktype],dwik);
           Nki = nC[atomk]-(wik*kronecker(itype,0))+nH[atomk] -
             (wik*kronecker(itype,1));
           SpN = Sp(Nki,Nmin,Nmax,dNki);
 
           tmp2 = VA*dN3[0]*dwik*Etmp/rikmag;
           f[atomi][0] -= tmp2*rik[0];
           f[atomi][1] -= tmp2*rik[1];
           f[atomi][2] -= tmp2*rik[2];
           f[atomk][0] += tmp2*rik[0];
           f[atomk][1] += tmp2*rik[1];
           f[atomk][2] += tmp2*rik[2];
 
           if (vflag_atom) v_tally2(atomi,atomk,-tmp2,rik);
 
           tmp2 = VA*dN3[2]*(2.0*NconjtmpI*dwik*SpN)*Etmp/rikmag;
           f[atomi][0] -= tmp2*rik[0];
           f[atomi][1] -= tmp2*rik[1];
           f[atomi][2] -= tmp2*rik[2];
           f[atomk][0] += tmp2*rik[0];
           f[atomk][1] += tmp2*rik[1];
           f[atomk][2] += tmp2*rik[2];
 
           if (vflag_atom) v_tally2(atomi,atomk,-tmp2,rik);
 
           if (fabs(dNki) > TOL) {
             REBO_neighs_k = REBO_firstneigh[atomk];
             for (n = 0; n < REBO_numneigh[atomk]; n++) {
               atomn = REBO_neighs_k[n];
               ntype = map[type[atomn]];
               if (atomn !=atomi) {
                 rkn[0] = x[atomk][0]-x[atomn][0];
                 rkn[1] = x[atomk][1]-x[atomn][1];
                 rkn[2] = x[atomk][2]-x[atomn][2];
                 rknmag = sqrt((rkn[0]*rkn[0])+(rkn[1]*rkn[1])+(rkn[2]*rkn[2]));
                 Sp(rknmag,rcmin[ktype][ntype],rcmax[ktype][ntype],dwkn);
 
                 tmp2 = VA*dN3[2]*(2.0*NconjtmpI*wik*dNki*dwkn)*Etmp/rknmag;
                 f[atomk][0] -= tmp2*rkn[0];
                 f[atomk][1] -= tmp2*rkn[1];
                 f[atomk][2] -= tmp2*rkn[2];
                 f[atomn][0] += tmp2*rkn[0];
                 f[atomn][1] += tmp2*rkn[1];
                 f[atomn][2] += tmp2*rkn[2];
 
                 if (vflag_atom) v_tally2(atomk,atomn,-tmp2,rkn);
               }
             }
           }
         }
       }
 
       // Tij forces
 
       REBO_neighs = REBO_firstneigh[j];
       for (l = 0; l < REBO_numneigh[j]; l++) {
         atoml = REBO_neighs[l];
         if (atoml != atomi) {
           ltype = map[type[atoml]];
           rjl[0] = x[atomj][0]-x[atoml][0];
           rjl[1] = x[atomj][1]-x[atoml][1];
           rjl[2] = x[atomj][2]-x[atoml][2];
           rjlmag = sqrt((rjl[0]*rjl[0])+(rjl[1]*rjl[1])+(rjl[2]*rjl[2]));
           wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmax[jtype][ltype],dwjl);
           Nlj = nC[atoml]-(wjl*kronecker(jtype,0))+nH[atoml] -
             (wjl*kronecker(jtype,1));
           SpN = Sp(Nlj,Nmin,Nmax,dNlj);
 
           tmp2 = VA*dN3[1]*dwjl*Etmp/rjlmag;
           f[atomj][0] -= tmp2*rjl[0];
           f[atomj][1] -= tmp2*rjl[1];
           f[atomj][2] -= tmp2*rjl[2];
           f[atoml][0] += tmp2*rjl[0];
           f[atoml][1] += tmp2*rjl[1];
           f[atoml][2] += tmp2*rjl[2];
 
           if (vflag_atom) v_tally2(atomj,atoml,-tmp2,rjl);
 
           tmp2 = VA*dN3[2]*(2.0*NconjtmpJ*dwjl*SpN)*Etmp/rjlmag;
           f[atomj][0] -= tmp2*rjl[0];
           f[atomj][1] -= tmp2*rjl[1];
           f[atomj][2] -= tmp2*rjl[2];
           f[atoml][0] += tmp2*rjl[0];
           f[atoml][1] += tmp2*rjl[1];
           f[atoml][2] += tmp2*rjl[2];
 
           if (vflag_atom) v_tally2(atomj,atoml,-tmp2,rjl);
 
           if (fabs(dNlj) > TOL) {
             REBO_neighs_l = REBO_firstneigh[atoml];
             for (n = 0; n < REBO_numneigh[atoml]; n++) {
               atomn = REBO_neighs_l[n];
               ntype = map[type[atomn]];
               if (atomn != atomj) {
                 rln[0] = x[atoml][0]-x[atomn][0];
                 rln[1] = x[atoml][1]-x[atomn][1];
                 rln[2] = x[atoml][2]-x[atomn][2];
                 rlnmag = sqrt((rln[0]*rln[0])+(rln[1]*rln[1])+(rln[2]*rln[2]));
                 Sp(rlnmag,rcmin[ltype][ntype],rcmax[ltype][ntype],dwln);
 
                 tmp2 = VA*dN3[2]*(2.0*NconjtmpJ*wjl*dNlj*dwln)*Etmp/rlnmag;
                 f[atoml][0] -= tmp2*rln[0];
                 f[atoml][1] -= tmp2*rln[1];
                 f[atoml][2] -= tmp2*rln[2];
                 f[atomn][0] += tmp2*rln[0];
                 f[atomn][1] += tmp2*rln[1];
                 f[atomn][2] += tmp2*rln[2];
 
                 if (vflag_atom) v_tally2(atoml,atomn,-tmp2,rln);
               }
             }
           }
         }
       }
     }
   }
 
   return Stb;
 }
 
 /* ----------------------------------------------------------------------
    G spline
 ------------------------------------------------------------------------- */
 
 double PairAIREBO::gSpline(double costh, double Nij, int typei,
                            double *dgdc, double *dgdN)
 {
   double coeffs[6],dS,g1,g2,dg1,dg2,cut,g;
   int i,j;
 
   i = 0;
   j = 0;
   g = 0.0;
   cut = 0.0;
   dS = 0.0;
   dg1 = 0.0;
   dg2 = 0.0;
   *dgdc = 0.0;
   *dgdN = 0.0;
 
   // central atom is Carbon
 
   if (typei == 0) {
     if (costh < gCdom[0]) costh = gCdom[0];
     if (costh > gCdom[4]) costh = gCdom[4];
     if (Nij >= NCmax) {
       for (i = 0; i < 4; i++) {
         if (costh >= gCdom[i] && costh <= gCdom[i+1]) {
           for (j = 0; j < 6; j++) coeffs[j] = gC2[i][j];
         }
       }
       g2 = Sp5th(costh,coeffs,&dg2);
       g = g2;
       *dgdc = dg2;
       *dgdN = 0.0;
     }
     if (Nij <= NCmin) {
       for (i = 0; i < 4; i++) {
         if (costh >= gCdom[i] && costh <= gCdom[i+1]) {
           for (j = 0; j < 6; j++) coeffs[j] = gC1[i][j];
         }
       }
       g1 = Sp5th(costh,coeffs,&dg1);
       g = g1;
       *dgdc = dg1;
       *dgdN = 0.0;
     }
     if (Nij > NCmin && Nij < NCmax) {
       for (i = 0; i < 4; i++) {
         if (costh >= gCdom[i] && costh <= gCdom[i+1]) {
           for (j = 0; j < 6; j++) coeffs[j] = gC1[i][j];
         }
       }
       g1 = Sp5th(costh,coeffs,&dg1);
       for (i = 0; i < 4; i++) {
         if (costh >= gCdom[i] && costh <= gCdom[i+1]) {
           for (j = 0; j < 6; j++) coeffs[j] = gC2[i][j];
         }
       }
       g2 = Sp5th(costh,coeffs,&dg2);
       cut = Sp(Nij,NCmin,NCmax,dS);
       g = g2+cut*(g1-g2);
       *dgdc = dg2+(cut*(dg1-dg2));
       *dgdN = dS*(g1-g2);
     }
   }
 
   // central atom is Hydrogen
 
   if (typei == 1) {
     if (costh < gHdom[0]) costh = gHdom[0];
     if (costh > gHdom[3]) costh = gHdom[3];
     for (i = 0; i < 3; i++) {
       if (costh >= gHdom[i] && costh <= gHdom[i+1]) {
         for (j = 0; j < 6; j++) coeffs[j] = gH[i][j];
       }
     }
     g = Sp5th(costh,coeffs,&dg1);
     *dgdN = 0.0;
     *dgdc = dg1;
   }
 
   return g;
 }
 
 /* ----------------------------------------------------------------------
    Pij spline
 ------------------------------------------------------------------------- */
 
 double PairAIREBO::PijSpline(double NijC, double NijH, int typei, int typej,
                              double dN2[2])
 {
   int x,y,i,done;
   double Pij,coeffs[16];
 
   for (i = 0; i < 16; i++) coeffs[i]=0.0;
 
   x = 0;
   y = 0;
   dN2[0] = 0.0;
   dN2[1] = 0.0;
   done = 0;
 
   // if inputs are out of bounds set them back to a point in bounds
 
   if (typei == 0 && typej == 0) {
     if (NijC < pCCdom[0][0]) NijC=pCCdom[0][0];
     if (NijC > pCCdom[0][1]) NijC=pCCdom[0][1];
     if (NijH < pCCdom[1][0]) NijH=pCCdom[1][0];
     if (NijH > pCCdom[1][1]) NijH=pCCdom[1][1];
 
     if (fabs(NijC-floor(NijC)) < TOL && fabs(NijH-floor(NijH)) < TOL) {
       Pij = PCCf[(int) NijC][(int) NijH];
       dN2[0] = PCCdfdx[(int) NijC][(int) NijH];
       dN2[1] = PCCdfdy[(int) NijC][(int) NijH];
       done = 1;
     }
     if (done == 0) {
       x = (int) (floor(NijC));
       y = (int) (floor(NijH));
       for (i = 0; i<16; i++) coeffs[i] = pCC[x][y][i];
       Pij = Spbicubic(NijC,NijH,coeffs,dN2);
     }
   }
 
   // if inputs are out of bounds set them back to a point in bounds
 
    if (typei == 0 && typej == 1){
      if (NijC < pCHdom[0][0]) NijC=pCHdom[0][0];
      if (NijC > pCHdom[0][1]) NijC=pCHdom[0][1];
       if (NijH < pCHdom[1][0]) NijH=pCHdom[1][0];
       if (NijH > pCHdom[1][1]) NijH=pCHdom[1][1];
 
     if (fabs(NijC-floor(NijC)) < TOL && fabs(NijH-floor(NijH)) < TOL) {
       Pij = PCHf[(int) NijC][(int) NijH];
       dN2[0] = PCHdfdx[(int) NijC][(int) NijH];
       dN2[1] = PCHdfdy[(int) NijC][(int) NijH];
       done = 1;
     }
     if (done == 0) {
       x = (int) (floor(NijC));
       y = (int) (floor(NijH));
       for (i = 0; i<16; i++) coeffs[i] = pCH[x][y][i];
       Pij = Spbicubic(NijC,NijH,coeffs,dN2);
     }
   }
 
   if (typei == 1 && typej == 0) {
     Pij = 0.0;
     dN2[0] = 0.0;
     dN2[1] = 0.0;
   }
 
 
   if (typei == 1 && typej == 1) {
     Pij = 0.0;
     dN2[0] = 0.0;
     dN2[1] = 0.0;
   }
   return Pij;
 }
 
 /* ----------------------------------------------------------------------
    PiRC spline
 ------------------------------------------------------------------------- */
 
 double PairAIREBO::piRCSpline(double Nij, double Nji, double Nijconj,
                               int typei, int typej, double dN3[3])
 {
   int x,y,z,i,done;
   double piRC,coeffs[64];
   x=0;
   y=0;
   z=0;
   i=0;
 
   done=0;
 
   for (i=0; i<64; i++) coeffs[i]=0.0;
 
   if (typei==0 && typej==0) {
     //if the inputs are out of bounds set them back to a point in bounds
     if (Nij<piCCdom[0][0]) Nij=piCCdom[0][0];
     if (Nij>piCCdom[0][1]) Nij=piCCdom[0][1];
     if (Nji<piCCdom[1][0]) Nji=piCCdom[1][0];
     if (Nji>piCCdom[1][1]) Nji=piCCdom[1][1];
     if (Nijconj<piCCdom[2][0]) Nijconj=piCCdom[2][0];
     if (Nijconj>piCCdom[2][1]) Nijconj=piCCdom[2][1];
 
     if (fabs(Nij-floor(Nij))<TOL && fabs(Nji-floor(Nji))<TOL &&
         fabs(Nijconj-floor(Nijconj))<TOL) {
       piRC=piCCf[(int) Nij][(int) Nji][(int) Nijconj];
       dN3[0]=piCCdfdx[(int) Nij][(int) Nji][(int) Nijconj];
       dN3[1]=piCCdfdy[(int) Nij][(int) Nji][(int) Nijconj];
       dN3[2]=piCCdfdz[(int) Nij][(int) Nji][(int) Nijconj];
       done=1;
     }
 
     if (done==0) {
       for (i=0; i<piCCdom[0][1]; i++)
         if (Nij>=(double) i && Nij<=(double) i+1 || Nij==(double) i) x=i;
       for (i=0; i<piCCdom[1][1]; i++)
         if (Nji>=(double) i && Nji<=(double) i+1 || Nji==(double) i) y=i;
       for (i=0; i<piCCdom[2][1]; i++)
         if (Nijconj>=(double) i && Nijconj<=(double) i+1 ||
             Nijconj==(double) i) z=i;
 
       for (i=0; i<64; i++) coeffs[i]=piCC[x][y][z][i];
       piRC=Sptricubic(Nij,Nji,Nijconj,coeffs,dN3);
     }
   }
 
 
   // CH interaction
 
   if (typei==0 && typej==1 || typei==1 && typej==0) {
     // if the inputs are out of bounds set them back to a point in bounds
 
     if (Nij<piCHdom[0][0] || Nij>piCHdom[0][1] ||
         Nji<piCHdom[1][0] || Nji>piCHdom[1][1] ||
         Nijconj<piCHdom[2][0] || Nijconj>piCHdom[2][1]) {
       if (Nij<piCHdom[0][0]) Nij=piCHdom[0][0];
       if (Nij>piCHdom[0][1]) Nij=piCHdom[0][1];
       if (Nji<piCHdom[1][0]) Nji=piCHdom[1][0];
       if (Nji>piCHdom[1][1]) Nji=piCHdom[1][1];
       if (Nijconj<piCHdom[2][0]) Nijconj=piCHdom[2][0];
       if (Nijconj>piCHdom[2][1]) Nijconj=piCHdom[2][1];
     }
 
     if (fabs(Nij-floor(Nij))<TOL && fabs(Nji-floor(Nji))<TOL &&
         fabs(Nijconj-floor(Nijconj))<TOL) {
       piRC=piCHf[(int) Nij][(int) Nji][(int) Nijconj];
       dN3[0]=piCHdfdx[(int) Nij][(int) Nji][(int) Nijconj];
       dN3[1]=piCHdfdy[(int) Nij][(int) Nji][(int) Nijconj];
       dN3[2]=piCHdfdz[(int) Nij][(int) Nji][(int) Nijconj];
       done=1;
     }
 
     if (done==0) {
       for (i=0; i<piCHdom[0][1]; i++)
         if (Nij>=i && Nij<=i+1) x=i;
       for (i=0; i<piCHdom[1][1]; i++)
         if (Nji>=i && Nji<=i+1) y=i;
       for (i=0; i<piCHdom[2][1]; i++)
         if (Nijconj>=i && Nijconj<=i+1) z=i;
 
       for (i=0; i<64; i++) coeffs[i]=piCH[x][y][z][i];
       piRC=Sptricubic(Nij,Nji,Nijconj,coeffs,dN3);
     }
   }
 
   if (typei==1 && typej==1) {
     if (Nij<piHHdom[0][0] || Nij>piHHdom[0][1] ||
         Nji<piHHdom[1][0] || Nji>piHHdom[1][1] ||
         Nijconj<piHHdom[2][0] || Nijconj>piHHdom[2][1]) {
       Nij=0.0;
       Nji=0.0;
       Nijconj=0.0;
     }
     if (fabs(Nij-floor(Nij))<TOL && fabs(Nji-floor(Nji))<TOL &&
         fabs(Nijconj-floor(Nijconj))<TOL) {
       piRC=piHHf[(int) Nij][(int) Nji][(int) Nijconj];
       dN3[0]=piHHdfdx[(int) Nij][(int) Nji][(int) Nijconj];
       dN3[1]=piHHdfdy[(int) Nij][(int) Nji][(int) Nijconj];
       dN3[2]=piHHdfdz[(int) Nij][(int) Nji][(int) Nijconj];
       done=1;
     }
     if (done==0) {
       for (i=0; i<piHHdom[0][1]; i++)
         if (Nij>=i && Nij<=i+1) x=i;
       for (i=0; i<piHHdom[1][1]; i++)
         if (Nji>=i && Nji<=i+1) y=i;
       for (i=0; i<piHHdom[2][1]; i++)
         if (Nijconj>=i && Nijconj<=i+1) z=i;
 
       for (i=0; i<64; i++) coeffs[i]=piHH[x][y][z][i];
       piRC=Sptricubic(Nij,Nji,Nijconj,coeffs,dN3);
     }
   }
 
   return piRC;
 }
 
 /* ----------------------------------------------------------------------
    Tij spline
 ------------------------------------------------------------------------- */
 
 double PairAIREBO::TijSpline(double Nij, double Nji,
                              double Nijconj, double dN3[3])
 {
   int x,y,z,i,done;
   double Tijf,coeffs[64];
 
   x=0;
   y=0;
   z=0;
   i=0;
   Tijf=0.0;
   done=0;
   for (i=0; i<64; i++) coeffs[i]=0.0;
 
   //if the inputs are out of bounds set them back to a point in bounds
 
   if (Nij<Tijdom[0][0]) Nij=Tijdom[0][0];
   if (Nij>Tijdom[0][1]) Nij=Tijdom[0][1];
   if (Nji<Tijdom[1][0]) Nji=Tijdom[1][0];
   if (Nji>Tijdom[1][1]) Nji=Tijdom[1][1];
   if (Nijconj<Tijdom[2][0]) Nijconj=Tijdom[2][0];
   if (Nijconj>Tijdom[2][1]) Nijconj=Tijdom[2][1];
 
   if (fabs(Nij-floor(Nij))<TOL && fabs(Nji-floor(Nji))<TOL &&
       fabs(Nijconj-floor(Nijconj))<TOL) {
     Tijf=Tf[(int) Nij][(int) Nji][(int) Nijconj];
     dN3[0]=Tdfdx[(int) Nij][(int) Nji][(int) Nijconj];
     dN3[1]=Tdfdy[(int) Nij][(int) Nji][(int) Nijconj];
     dN3[2]=Tdfdz[(int) Nij][(int) Nji][(int) Nijconj];
     done=1;
   }
 
   if (done==0) {
     for (i=0; i<Tijdom[0][1]; i++)
       if (Nij>=i && Nij<=i+1) x=i;
     for (i=0; i<Tijdom[1][1]; i++)
       if (Nji>=i && Nji<=i+1) y=i;
     for (i=0; i<Tijdom[2][1]; i++)
       if (Nijconj>=i && Nijconj<=i+1) z=i;
 
     for (i=0; i<64; i++) coeffs[i]=Tijc[x][y][z][i];
     Tijf=Sptricubic(Nij,Nji,Nijconj,coeffs,dN3);
   }
 
   return Tijf;
 }
 
-/* ----------------------------------------------------------------------
-   add pages to REBO neighbor list
-------------------------------------------------------------------------- */
-
-void PairAIREBO::add_pages(int howmany)
-{
-  int toppage = maxpage;
-  maxpage += howmany*PGDELTA;
-
-  pages = (int **)
-    memory->srealloc(pages,maxpage*sizeof(int *),"AIREBO:pages");
-  for (int i = toppage; i < maxpage; i++)
-    memory->create(pages[i],pgsize,"AIREBO:pages[i]");
-}
-
 /* ----------------------------------------------------------------------
    read AIREBO potential file
 ------------------------------------------------------------------------- */
 
 void PairAIREBO::read_file(char *filename)
 {
   int i,j,k,l,limit;
   char s[MAXLINE];
 
   // REBO Parameters (AIREBO)
 
   double rcmin_CC,rcmin_CH,rcmin_HH,rcmax_CC,rcmax_CH,
     rcmax_HH,rcmaxp_CC,rcmaxp_CH,rcmaxp_HH;
   double Q_CC,Q_CH,Q_HH,alpha_CC,alpha_CH,alpha_HH,A_CC,A_CH,A_HH;
   double BIJc_CC1,BIJc_CC2,BIJc_CC3,BIJc_CH1,BIJc_CH2,BIJc_CH3,
     BIJc_HH1,BIJc_HH2,BIJc_HH3;
   double Beta_CC1,Beta_CC2,Beta_CC3,Beta_CH1,Beta_CH2,Beta_CH3,
     Beta_HH1,Beta_HH2,Beta_HH3;
   double rho_CC,rho_CH,rho_HH;
 
   // LJ Parameters (AIREBO)
 
   double rcLJmin_CC,rcLJmin_CH,rcLJmin_HH,rcLJmax_CC,rcLJmax_CH,
     rcLJmax_HH,bLJmin_CC;
   double bLJmin_CH,bLJmin_HH,bLJmax_CC,bLJmax_CH,bLJmax_HH,
     epsilon_CC,epsilon_CH,epsilon_HH;
   double sigma_CC,sigma_CH,sigma_HH,epsilonT_CCCC,epsilonT_CCCH,epsilonT_HCCH;
 
   MPI_Comm_rank(world,&me);
 
   // read file on proc 0
 
   if (me == 0) {
     FILE *fp = open_potential(filename);
     if (fp == NULL) {
       char str[128];
       sprintf(str,"Cannot open AIREBO potential file %s",filename);
       error->one(FLERR,str);
     }
 
     // skip initial comment lines
 
     while (1) {
       fgets(s,MAXLINE,fp);
       if (s[0] != '#') break;
     }
 
     // read parameters
 
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&rcmin_CC);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&rcmin_CH);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&rcmin_HH);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&rcmax_CC);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&rcmax_CH);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&rcmax_HH);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&rcmaxp_CC);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&rcmaxp_CH);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&rcmaxp_HH);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&smin);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&Nmin);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&Nmax);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&NCmin);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&NCmax);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&Q_CC);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&Q_CH);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&Q_HH);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&alpha_CC);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&alpha_CH);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&alpha_HH);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&A_CC);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&A_CH);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&A_HH);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&BIJc_CC1);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&BIJc_CC2);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&BIJc_CC3);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&BIJc_CH1);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&BIJc_CH2);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&BIJc_CH3);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&BIJc_HH1);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&BIJc_HH2);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&BIJc_HH3);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&Beta_CC1);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&Beta_CC2);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&Beta_CC3);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&Beta_CH1);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&Beta_CH2);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&Beta_CH3);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&Beta_HH1);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&Beta_HH2);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&Beta_HH3);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&rho_CC);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&rho_CH);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&rho_HH);
 
     // LJ parameters
 
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&rcLJmin_CC);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&rcLJmin_CH);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&rcLJmin_HH);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&rcLJmax_CC);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&rcLJmax_CH);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&rcLJmax_HH);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&bLJmin_CC);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&bLJmin_CH);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&bLJmin_HH);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&bLJmax_CC);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&bLJmax_CH);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&bLJmax_HH);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&epsilon_CC);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&epsilon_CH);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&epsilon_HH);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&sigma_CC);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&sigma_CH);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&sigma_HH);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&epsilonT_CCCC);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&epsilonT_CCCH);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%lg",&epsilonT_HCCH);
 
     // gC spline
 
     fgets(s,MAXLINE,fp);
     fgets(s,MAXLINE,fp);
     fgets(s,MAXLINE,fp);
 
     // number-1 = # of domains for the spline
 
     fgets(s,MAXLINE,fp);
     sscanf(s,"%d",&limit);
 
     for (i = 0; i < limit; i++) {
       fgets(s,MAXLINE,fp);
       sscanf(s,"%lg",&gCdom[i]);
     }
     fgets(s,MAXLINE,fp);
     for (i = 0; i < limit-1; i++) {
       for (j = 0; j < 6; j++) {
         fgets(s,MAXLINE,fp);
         sscanf(s,"%lg",&gC1[i][j]);
       }
     }
     fgets(s,MAXLINE,fp);
     for (i = 0; i < limit-1; i++) {
       for (j = 0; j < 6; j++) {
         fgets(s,MAXLINE,fp);
         sscanf(s,"%lg",&gC2[i][j]);
       }
     }
 
     // gH spline
 
     fgets(s,MAXLINE,fp);
     fgets(s,MAXLINE,fp);
     fgets(s,MAXLINE,fp);
 
     fgets(s,MAXLINE,fp);
     sscanf(s,"%d",&limit);
 
     for (i = 0; i < limit; i++) {
       fgets(s,MAXLINE,fp);
       sscanf(s,"%lg",&gHdom[i]);
     }
 
     fgets(s,MAXLINE,fp);
 
     for (i = 0; i < limit-1; i++) {
       for (j = 0; j < 6; j++) {
         fgets(s,MAXLINE,fp);
         sscanf(s,"%lg",&gH[i][j]);
       }
     }
 
     // pCC spline
 
     fgets(s,MAXLINE,fp);
     fgets(s,MAXLINE,fp);
     fgets(s,MAXLINE,fp);
 
     fgets(s,MAXLINE,fp);
     sscanf(s,"%d",&limit);
 
     for (i = 0; i < limit/2; i++) {
       for (j = 0; j < limit/2; j++) {
         fgets(s,MAXLINE,fp);
         sscanf(s,"%lg",&pCCdom[i][j]);
       }
     }
     fgets(s,MAXLINE,fp);
 
     for (i = 0; i < (int) pCCdom[0][1]; i++) {
       for (j = 0; j < (int) pCCdom[1][1]; j++) {
         for (k = 0; k < 16; k++) {
           fgets(s,MAXLINE,fp);
           sscanf(s,"%lg",&pCC[i][j][k]);
         }
       }
     }
 
     // pCH spline
 
     fgets(s,MAXLINE,fp);
     fgets(s,MAXLINE,fp);
     fgets(s,MAXLINE,fp);
     fgets(s,MAXLINE,fp);
     sscanf(s,"%d",&limit);
 
     for (i = 0; i < limit/2; i++) {
       for (j = 0; j < limit/2; j++) {
         fgets(s,MAXLINE,fp);
         sscanf(s,"%lg",&pCHdom[i][j]);
       }
     }
     fgets(s,MAXLINE,fp);
 
     for (i = 0; i < (int) pCHdom[0][1]; i++) {
       for (j = 0; j < (int) pCHdom[1][1]; j++) {
         for (k = 0; k < 16; k++) {
           fgets(s,MAXLINE,fp);
           sscanf(s,"%lg",&pCH[i][j][k]);
         }
       }
     }
 
     // piCC cpline
 
     fgets(s,MAXLINE,fp);
     fgets(s,MAXLINE,fp);
     fgets(s,MAXLINE,fp);
 
     fgets(s,MAXLINE,fp);
     sscanf(s,"%d",&limit);
 
     for (i = 0; i < limit/2; i++) {
       for (j = 0; j < limit/3; j++) {
         fgets(s,MAXLINE,fp);
         sscanf(s,"%lg",&piCCdom[i][j]);
       }
     }
     fgets(s,MAXLINE,fp);
 
     for (i = 0; i < (int) piCCdom[0][1]; i++) {
       for (j = 0; j < (int) piCCdom[1][1]; j++) {
         for (k = 0; k < (int) piCCdom[2][1]; k++) {
           for (l = 0; l < 64; l = l+1) {
             fgets(s,MAXLINE,fp);
             sscanf(s,"%lg",&piCC[i][j][k][l]);
           }
         }
       }
     }
 
     // piCH spline
 
     fgets(s,MAXLINE,fp);
     fgets(s,MAXLINE,fp);
     fgets(s,MAXLINE,fp);
 
     fgets(s,MAXLINE,fp);
     sscanf(s,"%d",&limit);
 
     for (i = 0; i < limit/2; i++) {
       for (j = 0; j < limit/3; j++) {
         fgets(s,MAXLINE,fp);
         sscanf(s,"%lg",&piCHdom[i][j]);
       }
     }
     fgets(s,MAXLINE,fp);
 
     for (i = 0; i < (int) piCHdom[0][1]; i++) {
       for (j = 0; j < (int) piCHdom[1][1]; j++) {
         for (k = 0; k < (int) piCHdom[2][1]; k++) {
           for (l = 0; l < 64; l = l+1) {
             fgets(s,MAXLINE,fp);
             sscanf(s,"%lg",&piCH[i][j][k][l]);
           }
         }
       }
     }
 
     // piHH spline
 
     fgets(s,MAXLINE,fp);
     fgets(s,MAXLINE,fp);
     fgets(s,MAXLINE,fp);
 
     fgets(s,MAXLINE,fp);
     sscanf(s,"%d",&limit);
 
     for (i = 0; i < limit/2; i++) {
       for (j = 0; j < limit/3; j++) {
         fgets(s,MAXLINE,fp);
         sscanf(s,"%lg",&piHHdom[i][j]);
       }
     }
     fgets(s,MAXLINE,fp);
 
     for (i = 0; i < (int) piHHdom[0][1]; i++) {
       for (j = 0; j < (int) piHHdom[1][1]; j++) {
         for (k = 0; k < (int) piHHdom[2][1]; k++) {
           for (l = 0; l < 64; l = l+1) {
             fgets(s,MAXLINE,fp);
             sscanf(s,"%lg",&piHH[i][j][k][l]);
           }
         }
       }
     }
 
     // Tij spline
 
     fgets(s,MAXLINE,fp);
     fgets(s,MAXLINE,fp);
     fgets(s,MAXLINE,fp);
 
     fgets(s,MAXLINE,fp);
     sscanf(s,"%d",&limit);
 
     for (i = 0; i < limit/2; i++) {
       for (j = 0; j < limit/3; j++) {
         fgets(s,MAXLINE,fp);
         sscanf(s,"%lg",&Tijdom[i][j]);
       }
     }
     fgets(s,MAXLINE,fp);
 
     for (i = 0; i < (int) Tijdom[0][1]; i++) {
       for (j = 0; j < (int) Tijdom[1][1]; j++) {
         for (k = 0; k < (int) Tijdom[2][1]; k++) {
           for (l = 0; l < 64; l = l+1) {
             fgets(s,MAXLINE,fp);
             sscanf(s,"%lg",&Tijc[i][j][k][l]);
           }
         }
       }
     }
 
     fclose(fp);
   }
 
   // store read-in values in arrays
 
   if (me == 0) {
 
     // REBO
 
     rcmin[0][0] = rcmin_CC;
     rcmin[0][1] = rcmin_CH;
     rcmin[1][0] = rcmin[0][1];
     rcmin[1][1] = rcmin_HH;
 
     rcmax[0][0] = rcmax_CC;
     rcmax[0][1] = rcmax_CH;
     rcmax[1][0] = rcmax[0][1];
     rcmax[1][1] = rcmax_HH;
 
     rcmaxsq[0][0] = rcmax[0][0]*rcmax[0][0];
     rcmaxsq[1][0] = rcmax[1][0]*rcmax[1][0];
     rcmaxsq[0][1] = rcmax[0][1]*rcmax[0][1];
     rcmaxsq[1][1] = rcmax[1][1]*rcmax[1][1];
 
     rcmaxp[0][0] = rcmaxp_CC;
     rcmaxp[0][1] = rcmaxp_CH;
     rcmaxp[1][0] = rcmaxp[0][1];
     rcmaxp[1][1] = rcmaxp_HH;
 
     Q[0][0] = Q_CC;
     Q[0][1] = Q_CH;
     Q[1][0] = Q[0][1];
     Q[1][1] = Q_HH;
 
     alpha[0][0] = alpha_CC;
     alpha[0][1] = alpha_CH;
     alpha[1][0] = alpha[0][1];
     alpha[1][1] = alpha_HH;
 
     A[0][0] = A_CC;
     A[0][1] = A_CH;
     A[1][0] = A[0][1];
     A[1][1] = A_HH;
 
     rho[0][0] = rho_CC;
     rho[0][1] = rho_CH;
     rho[1][0] = rho[0][1];
     rho[1][1] = rho_HH;
 
     BIJc[0][0][0] = BIJc_CC1;
     BIJc[0][0][1] = BIJc_CC2;
     BIJc[0][0][2] = BIJc_CC3;
     BIJc[0][1][0] = BIJc_CH1;
     BIJc[0][1][1] = BIJc_CH2;
     BIJc[0][1][2] = BIJc_CH3;
     BIJc[1][0][0] = BIJc_CH1;
     BIJc[1][0][1] = BIJc_CH2;
     BIJc[1][0][2] = BIJc_CH3;
     BIJc[1][1][0] = BIJc_HH1;
     BIJc[1][1][1] = BIJc_HH2;
     BIJc[1][1][2] = BIJc_HH3;
 
     Beta[0][0][0] = Beta_CC1;
     Beta[0][0][1] = Beta_CC2;
     Beta[0][0][2] = Beta_CC3;
     Beta[0][1][0] = Beta_CH1;
     Beta[0][1][1] = Beta_CH2;
     Beta[0][1][2] = Beta_CH3;
     Beta[1][0][0] = Beta_CH1;
     Beta[1][0][1] = Beta_CH2;
     Beta[1][0][2] = Beta_CH3;
     Beta[1][1][0] = Beta_HH1;
     Beta[1][1][1] = Beta_HH2;
     Beta[1][1][2] = Beta_HH3;
 
     // LJ
 
     rcLJmin[0][0] = rcLJmin_CC;
     rcLJmin[0][1] = rcLJmin_CH;
     rcLJmin[1][0] = rcLJmin[0][1];
     rcLJmin[1][1] = rcLJmin_HH;
 
     rcLJmax[0][0] = rcLJmax_CC;
     rcLJmax[0][1] = rcLJmax_CH;
     rcLJmax[1][0] = rcLJmax[0][1];
     rcLJmax[1][1] = rcLJmax_HH;
 
     rcLJmaxsq[0][0] = rcLJmax[0][0]*rcLJmax[0][0];
     rcLJmaxsq[1][0] = rcLJmax[1][0]*rcLJmax[1][0];
     rcLJmaxsq[0][1] = rcLJmax[0][1]*rcLJmax[0][1];
     rcLJmaxsq[1][1] = rcLJmax[1][1]*rcLJmax[1][1];
 
     bLJmin[0][0] = bLJmin_CC;
     bLJmin[0][1] = bLJmin_CH;
     bLJmin[1][0] = bLJmin[0][1];
     bLJmin[1][1] = bLJmin_HH;
 
     bLJmax[0][0] = bLJmax_CC;
     bLJmax[0][1] = bLJmax_CH;
     bLJmax[1][0] = bLJmax[0][1];
     bLJmax[1][1] = bLJmax_HH;
 
     epsilon[0][0] = epsilon_CC;
     epsilon[0][1] = epsilon_CH;
     epsilon[1][0] = epsilon[0][1];
     epsilon[1][1] = epsilon_HH;
 
     sigma[0][0] = sigma_CC;
     sigma[0][1] = sigma_CH;
     sigma[1][0] = sigma[0][1];
     sigma[1][1] = sigma_HH;
 
     // torsional
 
     thmin = -1.0;
     thmax = -0.995;
     epsilonT[0][0] = epsilonT_CCCC;
     epsilonT[0][1] = epsilonT_CCCH;
     epsilonT[1][0] = epsilonT[0][1];
     epsilonT[1][1] = epsilonT_HCCH;
   }
 
   // broadcast read-in and setup values
 
   MPI_Bcast(&thmin,1,MPI_DOUBLE,0,world);
   MPI_Bcast(&thmax,1,MPI_DOUBLE,0,world);
 
   MPI_Bcast(&smin,1,MPI_DOUBLE,0,world);
   MPI_Bcast(&Nmin,1,MPI_DOUBLE,0,world);
   MPI_Bcast(&Nmax,1,MPI_DOUBLE,0,world);
   MPI_Bcast(&NCmin,1,MPI_DOUBLE,0,world);
   MPI_Bcast(&NCmax,1,MPI_DOUBLE,0,world);
 
 
   MPI_Bcast(&rcmin[0][0],4,MPI_DOUBLE,0,world);
   MPI_Bcast(&rcmax[0][0],4,MPI_DOUBLE,0,world);
   MPI_Bcast(&rcmaxsq[0][0],4,MPI_DOUBLE,0,world);
   MPI_Bcast(&rcmaxp[0][0],4,MPI_DOUBLE,0,world);
 
   MPI_Bcast(&Q[0][0],4,MPI_DOUBLE,0,world);
   MPI_Bcast(&alpha[0][0],4,MPI_DOUBLE,0,world);
   MPI_Bcast(&A[0][0],4,MPI_DOUBLE,0,world);
   MPI_Bcast(&rho[0][0],4,MPI_DOUBLE,0,world);
   MPI_Bcast(&BIJc[0][0][0],12,MPI_DOUBLE,0,world);
   MPI_Bcast(&Beta[0][0][0],12,MPI_DOUBLE,0,world);
 
   MPI_Bcast(&rcLJmin[0][0],4,MPI_DOUBLE,0,world);
   MPI_Bcast(&rcLJmax[0][0],4,MPI_DOUBLE,0,world);
   MPI_Bcast(&rcLJmaxsq[0][0],4,MPI_DOUBLE,0,world);
   MPI_Bcast(&rcLJmin[0][0],4,MPI_DOUBLE,0,world);
   MPI_Bcast(&rcLJmin[0][0],4,MPI_DOUBLE,0,world);
 
   MPI_Bcast(&rcLJmin[0][0],4,MPI_DOUBLE,0,world);
   MPI_Bcast(&rcLJmax[0][0],4,MPI_DOUBLE,0,world);
   MPI_Bcast(&bLJmin[0][0],4,MPI_DOUBLE,0,world);
   MPI_Bcast(&bLJmax[0][0],4,MPI_DOUBLE,0,world);
 
   MPI_Bcast(&epsilon[0][0],4,MPI_DOUBLE,0,world);
   MPI_Bcast(&sigma[0][0],4,MPI_DOUBLE,0,world);
   MPI_Bcast(&epsilonT[0][0],4,MPI_DOUBLE,0,world);
 
   MPI_Bcast(&gCdom[0],5,MPI_DOUBLE,0,world);
   MPI_Bcast(&gC1[0][0],24,MPI_DOUBLE,0,world);
   MPI_Bcast(&gC2[0][0],24,MPI_DOUBLE,0,world);
   MPI_Bcast(&gHdom[0],4,MPI_DOUBLE,0,world);
   MPI_Bcast(&gH[0][0],18,MPI_DOUBLE,0,world);
 
   MPI_Bcast(&pCCdom[0][0],4,MPI_DOUBLE,0,world);
   MPI_Bcast(&pCHdom[0][0],4,MPI_DOUBLE,0,world);
   MPI_Bcast(&pCC[0][0][0],256,MPI_DOUBLE,0,world);
   MPI_Bcast(&pCH[0][0][0],256,MPI_DOUBLE,0,world);
 
   MPI_Bcast(&piCCdom[0][0],6,MPI_DOUBLE,0,world);
   MPI_Bcast(&piCHdom[0][0],6,MPI_DOUBLE,0,world);
   MPI_Bcast(&piHHdom[0][0],6,MPI_DOUBLE,0,world);
   MPI_Bcast(&piCC[0][0][0][0],9216,MPI_DOUBLE,0,world);
   MPI_Bcast(&piCH[0][0][0][0],9216,MPI_DOUBLE,0,world);
   MPI_Bcast(&piHH[0][0][0][0],9216,MPI_DOUBLE,0,world);
 
   MPI_Bcast(&Tijdom[0][0],6,MPI_DOUBLE,0,world);
   MPI_Bcast(&Tijc[0][0][0][0],9216,MPI_DOUBLE,0,world);
 }
 
 // ----------------------------------------------------------------------
 // generic Spline functions
 // ----------------------------------------------------------------------
 
 /* ----------------------------------------------------------------------
    fifth order spline evaluation
 ------------------------------------------------------------------------- */
 
 double PairAIREBO::Sp5th(double x, double coeffs[6], double *df)
 {
   double f, d;
   const double x2 = x*x;
   const double x3 = x2*x;
 
   f  = coeffs[0];
   f += coeffs[1]*x;
   d  = coeffs[1];
   f += coeffs[2]*x2;
   d += 2.0*coeffs[2]*x;
   f += coeffs[3]*x3;
   d += 3.0*coeffs[3]*x2;
   f += coeffs[4]*x2*x2;
   d += 4.0*coeffs[4]*x3;
   f += coeffs[5]*x2*x3;
   d += 5.0*coeffs[5]*x2*x2;
 
   *df = d;
   return f;
 }
 
 /* ----------------------------------------------------------------------
    bicubic spline evaluation
 ------------------------------------------------------------------------- */
 
 double PairAIREBO::Spbicubic(double x, double y,
                              double coeffs[16], double df[2])
 {
   double f,xn,yn,xn1,yn1,c;
   int i,j;
 
   f = 0.0;
   df[0] = 0.0;
   df[1] = 0.0;
 
   xn = 1.0;
   for (i = 0; i < 4; i++) {
     yn = 1.0;
     for (j = 0; j < 4; j++) {
       c = coeffs[i*4+j];
 
       f += c*xn*yn;
       if (i > 0) df[0] += c * ((double) i) * xn1 * yn;
       if (j > 0) df[1] += c * ((double) j) * xn * yn1;
 
       yn1 = yn;
       yn *= y;
     }
     xn1 = xn;
     xn *= x;
   }
 
   return f;
 }
 
 /* ----------------------------------------------------------------------
    tricubic spline evaluation
 ------------------------------------------------------------------------- */
 
 double PairAIREBO::Sptricubic(double x, double y, double z,
                               double coeffs[64], double df[3])
 {
   double f,ir,jr,kr,xn,yn,zn,xn1,yn1,zn1,c;
   int i,j,k;
 
   f = 0.0;
   df[0] = 0.0;
   df[1] = 0.0;
   df[2] = 0.0;
 
   xn = 1.0;
   for (i = 0; i < 4; i++) {
     ir = (double) i;
     yn = 1.0;
     for (j = 0; j < 4; j++) {
       jr = (double) j;
       zn = 1.0;
       for (k = 0; k < 4; k++) {
         kr = (double) k;
         c = coeffs[16*i+4*j+k];
         f += c*xn*yn*zn;
         if (i > 0) df[0] += c * ir * xn1 * yn * zn;
         if (j > 0) df[1] += c * jr * xn * yn1 * zn;
         if (k > 0) df[2] += c * kr * xn * yn * zn1;
         zn1 = zn;
         zn *= z;
       }
       yn1 = yn;
       yn *= y;
     }
     xn1 = xn;
     xn *= x;
   }
 
   return f;
 }
 
 /* ----------------------------------------------------------------------
    initialize spline knot values
 ------------------------------------------------------------------------- */
 
 void PairAIREBO::spline_init()
 {
   int i,j,k;
 
   for (i = 0; i < 5; i++) {
     for (j = 0; j < 5; j++) {
       PCCf[i][j] = 0.0;
       PCCdfdx[i][j] = 0.0;
       PCCdfdy[i][j] = 0.0;
       PCHf[i][j] = 0.0;
       PCHdfdx[i][j] = 0.0;
       PCHdfdy[i][j] = 0.0;
     }
   }
 
   PCCf[0][2] = -0.00050;
   PCCf[0][3] = 0.0161253646;
   PCCf[1][1] = -0.010960;
   PCCf[1][2] = 0.00632624824;
   PCCf[2][0] = -0.0276030;
   PCCf[2][1] = 0.00317953083;
 
   PCHf[0][1] = 0.209336733;
   PCHf[0][2] = -0.0644496154;
   PCHf[0][3] = -0.303927546;
   PCHf[1][0] = 0.010;
   PCHf[1][1] = -0.125123401;
   PCHf[1][2] = -0.298905246;
   PCHf[2][0] = -0.122042146;
   PCHf[2][1] = -0.300529172;
   PCHf[3][0] = -0.307584705;
 
   for (i = 0; i < 5; i++) {
     for (j = 0; j < 5; j++) {
       for (k = 0; k < 10; k++) {
         piCCf[i][j][k] = 0.0;
         piCCdfdx[i][j][k] = 0.0;
         piCCdfdy[i][j][k] = 0.0;
         piCCdfdz[i][j][k] = 0.0;
         piCHf[i][j][k] = 0.0;
         piCHdfdx[i][j][k] = 0.0;
         piCHdfdy[i][j][k] = 0.0;
         piCHdfdz[i][j][k] = 0.0;
         piHHf[i][j][k] = 0.0;
         piHHdfdx[i][j][k] = 0.0;
         piHHdfdy[i][j][k] = 0.0;
         piHHdfdz[i][j][k] = 0.0;
         Tf[i][j][k] = 0.0;
         Tdfdx[i][j][k] = 0.0;
         Tdfdy[i][j][k] = 0.0;
         Tdfdz[i][j][k] = 0.0;
       }
     }
   }
 
   for (i = 3; i < 10; i++) piCCf[0][0][i] = 0.0049586079;
   piCCf[1][0][1] = 0.021693495;
   piCCf[0][1][1] = 0.021693495;
   for (i = 2; i < 10; i++) piCCf[1][0][i] = 0.0049586079;
   for (i = 2; i < 10; i++) piCCf[0][1][i] = 0.0049586079;
   piCCf[1][1][1] = 0.05250;
   piCCf[1][1][2] = -0.002088750;
   for (i = 3; i < 10; i++) piCCf[1][1][i] = -0.00804280;
   piCCf[2][0][1] = 0.024698831850;
   piCCf[0][2][1] = 0.024698831850;
   piCCf[2][0][2] = -0.00597133450;
   piCCf[0][2][2] = -0.00597133450;
   for (i = 3; i < 10; i++) piCCf[2][0][i] = 0.0049586079;
   for (i = 3; i < 10; i++) piCCf[0][2][i] = 0.0049586079;
   piCCf[2][1][1] = 0.00482478490;
   piCCf[1][2][1] = 0.00482478490;
   piCCf[2][1][2] = 0.0150;
   piCCf[1][2][2] = 0.0150;
   piCCf[2][1][3] = -0.010;
   piCCf[1][2][3] = -0.010;
   piCCf[2][1][4] = -0.01168893870;
   piCCf[1][2][4] = -0.01168893870;
   piCCf[2][1][5] = -0.013377877400;
   piCCf[1][2][5] = -0.013377877400;
   piCCf[2][1][6] = -0.015066816000;
   piCCf[1][2][6] = -0.015066816000;
   for (i = 7; i < 10; i++) piCCf[2][1][i] = -0.015066816000;
   for (i = 7; i < 10; i++) piCCf[1][2][i] = -0.015066816000;
   piCCf[2][2][1] = 0.0472247850;
   piCCf[2][2][2] = 0.0110;
   piCCf[2][2][3] = 0.0198529350;
   piCCf[2][2][4] = 0.01654411250;
   piCCf[2][2][5] = 0.013235290;
   piCCf[2][2][6] = 0.00992646749999 ;
   piCCf[2][2][7] = 0.006617644999;
   piCCf[2][2][8] = 0.00330882250;
   piCCf[3][0][1] = -0.05989946750;
   piCCf[0][3][1] = -0.05989946750;
   piCCf[3][0][2] = -0.05989946750;
   piCCf[0][3][2] = -0.05989946750;
   for (i = 3; i < 10; i++) piCCf[3][0][i] = 0.0049586079;
   for (i = 3; i < 10; i++) piCCf[0][3][i] = 0.0049586079;
   piCCf[3][1][2] = -0.0624183760;
   piCCf[1][3][2] = -0.0624183760;
   for (i = 3; i < 10; i++) piCCf[3][1][i] = -0.0624183760;
   for (i = 3; i < 10; i++) piCCf[1][3][i] = -0.0624183760;
   piCCf[3][2][1] = -0.02235469150;
   piCCf[2][3][1] = -0.02235469150;
   for (i = 2; i < 10; i++) piCCf[3][2][i] = -0.02235469150;
   for (i = 2; i < 10; i++) piCCf[2][3][i] = -0.02235469150;
 
   piCCdfdx[2][1][1] = -0.026250;
   piCCdfdx[2][1][5] = -0.0271880;
   piCCdfdx[2][1][6] = -0.0271880;
   for (i = 7; i < 10; i++) piCCdfdx[2][1][i] = -0.0271880;
   piCCdfdx[1][3][2] = 0.0187723882;
   for (i = 2; i < 10; i++) piCCdfdx[2][3][i] = 0.031209;
 
   piCCdfdy[1][2][1] = -0.026250;
   piCCdfdy[1][2][5] = -0.0271880;
   piCCdfdy[1][2][6] = -0.0271880;
   for (i = 7; i < 10; i++) piCCdfdy[1][2][i] = -0.0271880;
   piCCdfdy[3][1][2] = 0.0187723882;
   for (i = 2; i < 10; i++) piCCdfdy[3][2][i] = 0.031209;
 
   piCCdfdz[1][1][2] = -0.0302715;
   piCCdfdz[2][1][4] = -0.0100220;
   piCCdfdz[1][2][4] = -0.0100220;
   piCCdfdz[2][1][5] = -0.0100220;
   piCCdfdz[1][2][5] = -0.0100220;
   for (i = 4; i < 9; i++) piCCdfdz[2][2][i] = -0.0033090;
 
   //  make top end of piCC flat instead of zero
   i = 4;
   for (j = 0; j < 4; j++){
       for (k = 1; k < 11; k++){
           piCCf[i][j][k] = piCCf[i-1][j][k];
       }
   }
   for (i = 0; i < 4; i++){ // also enforces some symmetry
       for (j = i+1; j < 5; j++){
           for (k = 1; k < 11; k++){
               piCCf[i][j][k] = piCCf[j][i][k];
           }
       }
   }
   for (k = 1; k < 11; k++) piCCf[4][4][k] = piCCf[3][4][k];
   k = 10;
   for (i = 0; i < 5; i++){
       for (j = 0; j < 5; j++){
       piCCf[i][j][k] = piCCf[i][j][k-1];
       }
   }
 
   piCHf[1][1][1] = -0.050;
   piCHf[1][1][2] = -0.050;
   piCHf[1][1][3] = -0.30;
   for (i = 4; i < 10; i++) piCHf[1][1][i] = -0.050;
   for (i = 5; i < 10; i++) piCHf[2][0][i] = -0.004523893758064;
   for (i = 5; i < 10; i++) piCHf[0][2][i] = -0.004523893758064;
   piCHf[2][1][2] = -0.250;
   piCHf[1][2][2] = -0.250;
   piCHf[2][1][3] = -0.250;
   piCHf[1][2][3] = -0.250;
   piCHf[3][1][1] = -0.10;
   piCHf[1][3][1] = -0.10;
   piCHf[3][1][2] = -0.125;
   piCHf[1][3][2] = -0.125;
   piCHf[3][1][3] = -0.125;
   piCHf[1][3][3] = -0.125;
   for (i = 4; i < 10; i++) piCHf[3][1][i] = -0.10;
   for (i = 4; i < 10; i++) piCHf[1][3][i] = -0.10;
 
   // make top end of piCH flat instead of zero
  // also enforces some symmetry
 
   i = 4;
   for (j = 0; j < 4; j++){
       for (k = 1; k < 11; k++){
           piCHf[i][j][k] = piCHf[i-1][j][k];
       }
   }
   for (i = 0; i < 4; i++){
       for (j = i+1; j < 5; j++){
           for (k = 1; k < 11; k++){
               piCHf[i][j][k] = piCHf[j][i][k];
           }
       }
   }
   for (k = 1; k < 11; k++) piCHf[4][4][k] = piCHf[3][4][k];
   k = 10;
   for (i = 0; i < 5; i++){
       for (j = 0; j < 5; j++){
       piCHf[i][j][k] = piCHf[i][j][k-1];
       }
   }
 
   piHHf[1][1][1] = 0.124915958;
 
   Tf[2][2][1] = -0.035140;
   for (i = 2; i < 10; i++) Tf[2][2][i] = -0.0040480;
 }
 
 /* ----------------------------------------------------------------------
    memory usage of local atom-based arrays
 ------------------------------------------------------------------------- */
 
 double PairAIREBO::memory_usage()
 {
   double bytes = 0.0;
   bytes += maxlocal * sizeof(int);
   bytes += maxlocal * sizeof(int *);
-  bytes += maxpage * neighbor->pgsize * sizeof(int);
-  bytes += 3 * maxlocal * sizeof(double);
+
+  for (int i = 0; i < comm->nthreads; ++i)
+    bytes += ipage[i].size();
+
+  bytes += 2*maxlocal * sizeof(double);
   return bytes;
 }
diff --git a/src/MANYBODY/pair_airebo.h b/src/MANYBODY/pair_airebo.h
index 7cbdca3df..b91b697d1 100644
--- a/src/MANYBODY/pair_airebo.h
+++ b/src/MANYBODY/pair_airebo.h
@@ -1,215 +1,215 @@
 /* -*- c++ -*- ----------------------------------------------------------
    LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
    http://lammps.sandia.gov, Sandia National Laboratories
    Steve Plimpton, sjplimp@sandia.gov
 
    Copyright (2003) Sandia Corporation.  Under the terms of Contract
    DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
    certain rights in this software.  This software is distributed under
    the GNU General Public License.
 
    See the README file in the top-level LAMMPS directory.
 ------------------------------------------------------------------------- */
 
 #ifdef PAIR_CLASS
 
 PairStyle(airebo,PairAIREBO)
 
 #else
 
 #ifndef LMP_PAIR_AIREBO_H
 #define LMP_PAIR_AIREBO_H
 
 #include "pair.h"
+#include "my_page.h"
 #include "math.h"
 #include "math_const.h"
 
 namespace LAMMPS_NS {
 
 class PairAIREBO : public Pair {
  public:
   PairAIREBO(class LAMMPS *);
   virtual ~PairAIREBO();
   virtual void compute(int, int);
   virtual void settings(int, char **);
   void coeff(int, char **);
   void init_style();
   double init_one(int, int);
   double memory_usage();
 
  protected:
-  int **pages;                     // neighbor list pages
   int *map;                        // 0 (C), 1 (H), or -1 (NULL) for each type
 
   int me;
   int ljflag,torflag;              // 0/1 if LJ,torsion terms included
-  int maxlocal;                    // size of numneigh, firstneigh arrays
-  int maxpage;                     // # of pages currently allocated
-  int pgsize;                      // size of neighbor page
-  int oneatom;                     // max # of neighbors for one atom
 
   double cutlj;                    // user-specified LJ cutoff
   double cutljrebosq;              // cut for when to compute
                                    // REBO neighs of ghost atoms
 
   double **cutljsq;                // LJ cutoffs for C,H types
   double **lj1,**lj2,**lj3,**lj4;  // pre-computed LJ coeffs for C,H types
   double cut3rebo;                 // maximum distance for 3rd REBO neigh
 
+  int maxlocal;                    // size of numneigh, firstneigh arrays
+  int pgsize;                      // size of neighbor page
+  int oneatom;                     // max # of neighbors for one atom
+  MyPage<int> *ipage;              // neighbor list pages
   int *REBO_numneigh;              // # of pair neighbors for each atom
   int **REBO_firstneigh;           // ptr to 1st neighbor of each atom
+
   double *closestdistsq;           // closest owned atom dist to each ghost
   double *nC,*nH;                  // sum of weighting fns with REBO neighs
 
   double smin,Nmin,Nmax,NCmin,NCmax,thmin,thmax;
   double rcmin[2][2],rcmax[2][2],rcmaxsq[2][2],rcmaxp[2][2];
   double Q[2][2],alpha[2][2],A[2][2],rho[2][2],BIJc[2][2][3],Beta[2][2][3];
   double rcLJmin[2][2],rcLJmax[2][2],rcLJmaxsq[2][2],bLJmin[2][2],bLJmax[2][2];
   double epsilon[2][2],sigma[2][2],epsilonT[2][2];
 
   // spline coefficients
 
   double gCdom[5],gC1[4][6],gC2[4][6],gHdom[4],gH[3][6];
   double pCCdom[2][2],pCHdom[2][2],pCC[4][4][16],pCH[4][4][16];
   double piCCdom[3][2],piCHdom[3][2],piHHdom[3][2];
   double piCC[4][4][9][64],piCH[4][4][9][64],piHH[4][4][9][64];
   double Tijdom[3][2],Tijc[4][4][9][64];
 
   // spline knot values
 
   double PCCf[5][5],PCCdfdx[5][5],PCCdfdy[5][5],PCHf[5][5];
   double PCHdfdx[5][5],PCHdfdy[5][5];
   double piCCf[5][5][11],piCCdfdx[5][5][11];
   double piCCdfdy[5][5][11],piCCdfdz[5][5][11];
   double piCHf[5][5][11],piCHdfdx[5][5][11];
   double piCHdfdy[5][5][11],piCHdfdz[5][5][11];
   double piHHf[5][5][11],piHHdfdx[5][5][11];
   double piHHdfdy[5][5][11],piHHdfdz[5][5][11];
   double Tf[5][5][10],Tdfdx[5][5][10],Tdfdy[5][5][10],Tdfdz[5][5][10];
 
   void REBO_neigh();
   void FREBO(int, int);
   void FLJ(int, int);
   void TORSION(int, int);
 
   double bondorder(int, int, double *, double, double, double **, int);
   double bondorderLJ(int, int, double *, double, double,
                      double *, double, double **, int);
 
   double gSpline(double, double, int, double *, double *);
   double PijSpline(double, double, int, int, double *);
   double piRCSpline(double, double, double, int, int, double *);
   double TijSpline(double, double, double, double *);
 
-  void add_pages(int howmany = 1);
   void read_file(char *);
 
   double Sp5th(double, double *, double *);
   double Spbicubic(double, double, double *, double *);
   double Sptricubic(double, double, double, double *, double *);
   void spline_init();
 
   void allocate();
 
   // ----------------------------------------------------------------------
   // S'(t) and S(t) cutoff functions
   // added to header for inlining
   // ----------------------------------------------------------------------
 
   /* ----------------------------------------------------------------------
      cutoff function Sprime
      return cutoff and dX = derivative
      no side effects
   ------------------------------------------------------------------------- */
 
   inline double Sp(double Xij, double Xmin, double Xmax, double &dX) const {
     double cutoff;
 
     double t = (Xij-Xmin) / (Xmax-Xmin);
     if (t <= 0.0) {
       cutoff = 1.0;
       dX = 0.0;
     } else if (t >= 1.0) {
       cutoff = 0.0;
       dX = 0.0;
     } else {
       cutoff = 0.5 * (1.0+cos(t*MathConst::MY_PI));
       dX = (-0.5*MathConst::MY_PI*sin(t*MathConst::MY_PI)) / (Xmax-Xmin);
     }
     return cutoff;
   };
 
   /* ----------------------------------------------------------------------
      LJ cutoff function Sp2
      return cutoff and dX = derivative
      no side effects
   ------------------------------------------------------------------------- */
 
   inline double Sp2(double Xij, double Xmin, double Xmax, double &dX) const {
     double cutoff;
 
     double t = (Xij-Xmin) / (Xmax-Xmin);
     if (t <= 0.0) {
       cutoff = 1.0;
       dX = 0.0;
     } else if (t >= 1.0) {
       cutoff = 0.0;
       dX = 0.0;
     } else {
       cutoff = (1.0-(t*t*(3.0-2.0*t)));
       dX = 6.0*(t*t-t) / (Xmax-Xmin);
     }
     return cutoff;
   };
 
   /* kronecker delta function returning a double */
 
   inline double kronecker(const int a, const int b) const {
     return (a == b) ? 1.0 : 0.0;
   };
 
 };
 
 }
 
 #endif
 #endif
 
 /* ERROR/WARNING messages:
 
 E: Illegal ... command
 
 Self-explanatory.  Check the input script syntax and compare to the
 documentation for the command.  You can use -echo screen as a
 command-line option when running LAMMPS to see the offending line.
 
 E: Incorrect args for pair coefficients
 
 Self-explanatory.  Check the input script or data file.
 
 E: Pair style AIREBO requires atom IDs
 
 This is a requirement to use the AIREBO potential.
 
 E: Pair style AIREBO requires newton pair on
 
 See the newton command.  This is a restriction to use the AIREBO
 potential.
 
 E: All pair coeffs are not set
 
 All pair coefficients must be set in the data file or by the
 pair_coeff command before running a simulation.
 
 E: Neighbor list overflow, boost neigh_modify one or page
 
 There are too many neighbors of a single atom.  Use the neigh_modify
 command to increase the neighbor page size and the max number of
 neighbors allowed for one atom.
 
 E: Cannot open AIREBO potential file %s
 
 The specified AIREBO potential file cannot be opened.  Check that the
 path and name are correct.
 
 */
diff --git a/src/MANYBODY/pair_comb.cpp b/src/MANYBODY/pair_comb.cpp
index d5982caf0..e74a44253 100644
--- a/src/MANYBODY/pair_comb.cpp
+++ b/src/MANYBODY/pair_comb.cpp
@@ -1,2121 +1,2132 @@
 /* ----------------------------------------------------------------------
    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: Tzu-Ray Shan (U Florida, present: tnshan@sandia.gov)
    LAMMPS implementation of the Charge-optimized many-body (COMB) potential
    based on the HELL MD program (Prof Simon Phillpot, UF, sphil@mse.ufl.edu)
    and Aidan Thompson's Tersoff code in LAMMPS
 ------------------------------------------------------------------------- */
 
 #include "math.h"
 #include "stdio.h"
 #include "stdlib.h"
 #include "string.h"
 #include "pair_comb.h"
 #include "atom.h"
 #include "comm.h"
 #include "force.h"
 #include "neighbor.h"
 #include "neigh_list.h"
 #include "neigh_request.h"
 #include "group.h"
 #include "update.h"
+#include "my_page.h"
 #include "math_const.h"
 #include "memory.h"
 #include "error.h"
 
 using namespace LAMMPS_NS;
 using namespace MathConst;
 
 #define MAXLINE 1024
 #define DELTA 4
 #define PGDELTA 1
 #define MAXNEIGH 24
 
 /* ---------------------------------------------------------------------- */
 
 PairComb::PairComb(LAMMPS *lmp) : Pair(lmp)
 {
   single_enable = 0;
   restartinfo = 0;
   one_coeff = 1;
   manybody_flag = 1;
 
   nmax = 0;
   NCo = NULL;
   bbij = NULL;
 
   nelements = 0;
   elements = NULL;
   nparams = 0;
   maxparam = 0;
   params = NULL;
   elem2param = NULL;
 
   intype = NULL;
   fafb = NULL;
   dfafb = NULL;
   ddfafb = NULL;
   phin = NULL;
   dphin = NULL;
   erpaw = NULL;
 
   sht_num = NULL;
   sht_first = NULL;
-  maxpage = 0;
-  pages = NULL;
+
+  ipage = NULL;
+  pgsize = oneatom = 0;
 
   // set comm size needed by this Pair
 
   comm_forward = 1;
   comm_reverse = 1;
 }
 
 /* ----------------------------------------------------------------------
    check if allocated, since class can be destructed when incomplete
 ------------------------------------------------------------------------- */
 
 PairComb::~PairComb()
 {
   memory->destroy(NCo);
 
   if (elements)
     for (int i = 0; i < nelements; i++) delete [] elements[i];
 
   delete [] elements;
   memory->sfree(params);
   memory->destroy(elem2param);
 
   memory->destroy(intype);
   memory->destroy(fafb);
   memory->destroy(dfafb);
   memory->destroy(ddfafb);
   memory->destroy(phin);
   memory->destroy(dphin);
   memory->destroy(erpaw);
   memory->destroy(bbij);
   memory->destroy(sht_num);
   memory->destroy(sht_first);
 
+  delete[] ipage;
+
   if (allocated) {
     memory->destroy(setflag);
     memory->destroy(cutsq);
     delete [] map;
     delete [] esm;
   }
 }
 
 /* ---------------------------------------------------------------------- */
 
 void PairComb::compute(int eflag, int vflag)
 {
   int i,j,k,ii,jj,kk,inum,jnum,iparam_i;
   int itag,jtag,itype,jtype,ktype,iparam_ij,iparam_ijk;
   double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair;
   double rsq,rsq1,rsq2;
   double delr1[3],delr2[3],fi[3],fj[3],fk[3];
   double zeta_ij,prefactor;
   int *ilist,*jlist,*numneigh,**firstneigh;
   int mr1,mr2,mr3;
   int rsc,inty;
   double elp_ij,filp[3],fjlp[3],fklp[3];
   double iq,jq;
   double yaself;
   double potal,fac11,fac11e;
   double vionij,fvionij,sr1,sr2,sr3,Eov,Fov;
   int sht_jnum, *sht_jlist, nj;
 
   evdwl = ecoul = 0.0;
   if (eflag || vflag) ev_setup(eflag,vflag);
   else evflag = vflag_fdotr = vflag_atom = 0;
 
   // Build short range neighbor list
 
   Short_neigh();
 
   double **x = atom->x;
   double **f = atom->f;
   double *q = atom->q;
   int *tag = atom->tag;
   int *type = atom->type;
   int nlocal = atom->nlocal;
   int newton_pair = force->newton_pair;
 
   inum = list->inum;
   ilist = list->ilist;
   numneigh = list->numneigh;
   firstneigh = list->firstneigh;
 
   yaself = vionij = fvionij = Eov = Fov = 0.0;
 
   // self energy correction term: potal
 
   potal_calc(potal,fac11,fac11e);
 
   // loop over full neighbor list of my atoms
 
   for (ii = 0; ii < inum; ii++) {
     i = ilist[ii];
     itag = tag[i];
     itype = map[type[i]];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
     iq = q[i];
     NCo[i] = 0;
     nj = 0;
     iparam_i = elem2param[itype][itype][itype];
 
     // self energy, only on i atom
 
     yaself = self(&params[iparam_i],iq,potal);
 
     if (evflag) ev_tally(i,i,nlocal,0,yaself,0.0,0.0,0.0,0.0,0.0);
 
     // two-body interactions (long and short repulsive)
 
     jlist = firstneigh[i];
     jnum = numneigh[i];
     sht_jlist = sht_first[i];
     sht_jnum = sht_num[i];
 
     for (jj = 0; jj < jnum; jj++) {
       j = jlist[jj];
       j &= NEIGHMASK;
       jtag = tag[j];
 
       if (itag > jtag) {
         if ((itag+jtag) % 2 == 0) continue;
       } else if (itag < jtag) {
         if ((itag+jtag) % 2 == 1) continue;
       } else {
         if (x[j][2] < x[i][2]) continue;
         if (x[j][2] == ztmp && x[j][1] < ytmp) continue;
         if (x[j][2] == ztmp && x[j][1] == ytmp && x[j][0] < xtmp) continue;
       }
 
       // Qj calculates 2-body Coulombic
 
       jtype = map[type[j]];
       jq = q[j];
 
       delx = xtmp - x[j][0];
       dely = ytmp - x[j][1];
       delz = ztmp - x[j][2];
       rsq = delx*delx + dely*dely + delz*delz;
       iparam_ij = elem2param[itype][jtype][jtype];
 
       // long range q-dependent
 
       if (rsq > params[iparam_ij].lcutsq) continue;
 
       inty = intype[itype][jtype];
 
       // polynomial three-point interpolation
 
       tri_point(rsq, mr1, mr2, mr3, sr1, sr2, sr3, itype);
 
       // 1/r energy and forces
 
       direct(inty,mr1,mr2,mr3,rsq,sr1,sr2,sr3,iq,jq,
              potal,fac11,fac11e,vionij,fvionij);
 
       // field correction to self energy
 
       field(&params[iparam_ij],rsq,iq,jq,vionij,fvionij);
 
       // polarization field
       // sums up long range forces
 
       f[i][0] += delx*fvionij;
       f[i][1] += dely*fvionij;
       f[i][2] += delz*fvionij;
       f[j][0] -= delx*fvionij;
       f[j][1] -= dely*fvionij;
       f[j][2] -= delz*fvionij;
 
       if (evflag)
         ev_tally(i,j,nlocal,newton_pair,0.0,vionij,fvionij,delx,dely,delz);
 
       // short range q-independent
 
       if (rsq > params[iparam_ij].cutsq) continue;
 
       repulsive(&params[iparam_ij],rsq,fpair,eflag,evdwl,iq,jq);
 
       // repulsion is pure two-body, sums up pair repulsive forces
 
       f[i][0] += delx*fpair;
       f[i][1] += dely*fpair;
       f[i][2] += delz*fpair;
       f[j][0] -= delx*fpair;
       f[j][1] -= dely*fpair;
       f[j][2] -= delz*fpair;
 
       if (evflag)
         ev_tally(i,j,nlocal,newton_pair,evdwl,0.0,fpair,delx,dely,delz);
     }
 
     // accumulate coordination number information
 
     if (cor_flag) {
       for (jj = 0; jj < sht_jnum; jj++) {
         j = sht_jlist[jj];
         jtype = map[type[j]];
         iparam_ij = elem2param[itype][jtype][jtype];
 
         if(params[iparam_ij].hfocor > 0.0 ) {
           delr1[0] = x[j][0] - xtmp;
           delr1[1] = x[j][1] - ytmp;
           delr1[2] = x[j][2] - ztmp;
           rsq1 = vec3_dot(delr1,delr1);
 
           if (rsq1 > params[iparam_ij].cutsq) continue;
           NCo[i] += 1;
         }
       }
     }
 
     // three-body interactions
     // half i-j loop
 
     for (jj = 0; jj < sht_jnum; jj++) {
       j = sht_jlist[jj];
 
       jtype = map[type[j]];
       iparam_ij = elem2param[itype][jtype][jtype];
 
       // this Qj for q-dependent BSi
 
       jq = q[j];
 
       delr1[0] = x[j][0] - xtmp;
       delr1[1] = x[j][1] - ytmp;
       delr1[2] = x[j][2] - ztmp;
       rsq1 = vec3_dot(delr1,delr1);
 
       if (rsq1 > params[iparam_ij].cutsq) continue;
       nj ++;
 
       // accumulate bondorder zeta for each i-j interaction via loop over k
 
       zeta_ij = 0.0;
       cuo_flag1 = 0; cuo_flag2 = 0;
 
       for (kk = 0; kk < sht_jnum; kk++) {
         k = sht_jlist[kk];
         if (j == k) continue;
         ktype = map[type[k]];
         iparam_ijk = elem2param[itype][jtype][ktype];
 
         delr2[0] = x[k][0] - xtmp;
         delr2[1] = x[k][1] - ytmp;
         delr2[2] = x[k][2] - ztmp;
         rsq2 = vec3_dot(delr2,delr2);
 
         if (rsq2 > params[iparam_ijk].cutsq) continue;
 
         zeta_ij += zeta(&params[iparam_ijk],rsq1,rsq2,delr1,delr2);
 
         if (params[iparam_ijk].hfocor == -2.0) cuo_flag1 = 1;
         if (params[iparam_ijk].hfocor == -1.0) cuo_flag2 = 1;
       }
 
       if (cuo_flag1 && cuo_flag2) cuo_flag = 1;
       else cuo_flag = 0;
 
       force_zeta(&params[iparam_ij],eflag,i,nj,rsq1,zeta_ij,
                  iq,jq,fpair,prefactor,evdwl);
 
       // over-coordination correction for HfO2
 
       if (cor_flag && NCo[i] != 0)
         Over_cor(&params[iparam_ij],rsq1,NCo[i],Eov, Fov);
       evdwl +=  Eov;
       fpair +=  Fov;
 
       f[i][0] += delr1[0]*fpair;
       f[i][1] += delr1[1]*fpair;
       f[i][2] += delr1[2]*fpair;
       f[j][0] -= delr1[0]*fpair;
       f[j][1] -= delr1[1]*fpair;
       f[j][2] -= delr1[2]*fpair;
 
       if (evflag) ev_tally(i,j,nlocal,newton_pair,
                            evdwl,0.0,-fpair,-delr1[0],-delr1[1],-delr1[2]);
 
       // attractive term via loop over k (3-body forces)
 
       for (kk = 0; kk < sht_jnum; kk++) {
         k = sht_jlist[kk];
         if (j == k) continue;
         ktype = map[type[k]];
         iparam_ijk = elem2param[itype][jtype][ktype];
 
         delr2[0] = x[k][0] - xtmp;
         delr2[1] = x[k][1] - ytmp;
         delr2[2] = x[k][2] - ztmp;
         rsq2 = vec3_dot(delr2,delr2);
         if (rsq2 > params[iparam_ijk].cutsq) continue;
 
         for (rsc = 0; rsc < 3; rsc++)
           fi[rsc] = fj[rsc] = fk[rsc] = 0.0;
 
         attractive(&params[iparam_ijk],prefactor,
                    rsq1,rsq2,delr1,delr2,fi,fj,fk);
 
         // 3-body LP and BB correction and forces
 
         elp_ij = elp(&params[iparam_ijk],rsq1,rsq2,delr1,delr2);
         flp(&params[iparam_ijk],rsq1,rsq2,delr1,delr2,filp,fjlp,fklp);
 
         for (rsc = 0; rsc < 3; rsc++) {
           fi[rsc] += filp[rsc];
           fj[rsc] += fjlp[rsc];
           fk[rsc] += fklp[rsc];
         }
 
         for (rsc = 0; rsc < 3; rsc++) {
           f[i][rsc] += fi[rsc];
           f[j][rsc] += fj[rsc];
           f[k][rsc] += fk[rsc];
         }
 
         if (evflag)
           ev_tally(i,j,nlocal,newton_pair,elp_ij,0.0,0.0,0.0,0.0,0.0);
         if (vflag_atom) v_tally3(i,j,k,fj,fk,delr1,delr2);
 
       }
     }
 
     if (cuo_flag) params[iparam_i].cutsq *= 0.65;
   }
 
   cuo_flag = 0;
 
   if (vflag_fdotr) virial_fdotr_compute();
 }
 
 /* ---------------------------------------------------------------------- */
 
 void PairComb::allocate()
 {
  allocated = 1;
  int n = atom->ntypes;
 
  memory->create(setflag,n+1,n+1,"pair:setflag");
  memory->create(cutsq,n+1,n+1,"pair:cutsq");
 
  map = new int[n+1];
  esm = new double[n];
 }
 
 /* ----------------------------------------------------------------------
    global settings
 ------------------------------------------------------------------------- */
 
 void PairComb::settings(int narg, char **arg)
 {
   if (narg > 0) error->all(FLERR,"Illegal pair_style command");
 }
 
 /* ----------------------------------------------------------------------
    set coeffs for one or more type pairs
 ------------------------------------------------------------------------- */
 
 void PairComb::coeff(int narg, char **arg)
 {
   int i,j,n;
 
   if (!allocated) allocate();
 
   if (narg != 3 + atom->ntypes)
     error->all(FLERR,"Incorrect args for pair coefficients");
 
   // insure I,J args are * *
 
   if (strcmp(arg[0],"*") != 0 || strcmp(arg[1],"*") != 0)
     error->all(FLERR,"Incorrect args for pair coefficients");
 
   // read args that map atom types to elements in potential file
   // map[i] = which element the Ith atom type is, -1 if NULL
   // nelements = # of unique elements
   // elements = list of element names
 
   if (elements) {
     for (i = 0; i < nelements; i++) delete [] elements[i];
     delete [] elements;
   }
   elements = new char*[atom->ntypes];
   for (i = 0; i < atom->ntypes; i++) elements[i] = NULL;
 
   nelements = 0;
   for (i = 3; i < narg; i++) {
     if (strcmp(arg[i],"NULL") == 0) {
       map[i-2] = -1;
       continue;
     }
     for (j = 0; j < nelements; j++)
       if (strcmp(arg[i],elements[j]) == 0) break;
     map[i-2] = j;
     if (j == nelements) {
       n = strlen(arg[i]) + 1;
       elements[j] = new char[n];
       strcpy(elements[j],arg[i]);
       nelements++;
     }
   }
 
   // read potential file and initialize potential parameters
 
   read_file(arg[2]);
   setup();
 
   n = atom->ntypes;
 
   // generate streitz-mintmire direct 1/r energy look-up table
 
   if (comm->me == 0 && screen) fprintf(screen,"Pair COMB:\n");
   if (comm->me == 0 && screen)
     fprintf(screen,"  generating Coulomb integral lookup table ...\n");
   sm_table();
 
   if (cor_flag && comm->me == 0 && screen)
     fprintf(screen,"  will apply over-coordination correction ...\n");
   if (!cor_flag&& comm->me == 0 && screen)
     fprintf(screen,"  will not apply over-coordination correction ...\n");
 
   // clear setflag since coeff() called once with I,J = * *
 
   for (int i = 1; i <= n; i++)
     for (int j = i; j <= n; j++)
       setflag[i][j] = 0;
 
   // set setflag i,j for type pairs where both are mapped to elements
 
   int count = 0;
   for (int i = 1; i <= n; i++)
     for (int j = i; j <= n; j++)
       if (map[i] >= 0 && map[j] >= 0) {
         setflag[i][j] = 1;
         count++;
       }
 
   if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
 }
 
 /* ----------------------------------------------------------------------
    init specific to this pair style
 ------------------------------------------------------------------------- */
 
 void PairComb::init_style()
 {
   if (atom->tag_enable == 0)
     error->all(FLERR,"Pair style COMB requires atom IDs");
   if (force->newton_pair == 0)
     error->all(FLERR,"Pair style COMB requires newton pair on");
   if (!atom->q_flag)
     error->all(FLERR,"Pair style COMB requires atom attribute q");
 
   // ptr to QEQ fix
 
   //for (i = 0; i < modify->nfix; i++)
   //  if (strcmp(modify->fix[i]->style,"qeq") == 0) break;
   //if (i < modify->nfix) fixqeq = (FixQEQ *) modify->fix[i];
   //else fixqeq = NULL;
 
   // need a full neighbor list
 
   int irequest = neighbor->request(this);
   neighbor->requests[irequest]->half = 0;
   neighbor->requests[irequest]->full = 1;
 
-  pgsize = neighbor->pgsize;
-  oneatom = neighbor->oneatom;
-  if (maxpage == 0) add_pages();
+  // local Comb neighbor list
+  // create pages if first time or if neighbor pgsize/oneatom has changed
+
+  int create = 0;
+  if (ipage == NULL) create = 1;
+  if (pgsize != neighbor->pgsize) create = 1;
+  if (oneatom != neighbor->oneatom) create = 1;
+
+  if (create) {
+    delete[] ipage;
+
+    pgsize = neighbor->pgsize;
+    oneatom = neighbor->oneatom;
+
+    int nmypage= comm->nthreads;
+    ipage = new MyPage<int>[nmypage];
+    for (int i=0; i < nmypage; ++i)
+      ipage[i].init(oneatom,pgsize);
+  }
 }
 
 /* ----------------------------------------------------------------------
    init for one type pair i,j and corresponding j,i
 ------------------------------------------------------------------------- */
 
 double PairComb::init_one(int i, int j)
 {
   if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
   return cutmax;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void PairComb::read_file(char *file)
 {
   int params_per_line = 49;
   char **words = new char*[params_per_line+1];
 
   memory->sfree(params);
   params = NULL;
   nparams = 0;
   maxparam = 0;
 
   // open file on proc 0
 
   FILE *fp;
   if (comm->me == 0) {
     fp = open_potential(file);
     if (fp == NULL) {
       char str[128];
       sprintf(str,"Cannot open COMB potential file %s",file);
       error->one(FLERR,str);
     }
   }
 
   // read each line out of file, skipping blank lines or leading '#'
   // store line of params if all 3 element tags are in element list
 
   int n,nwords,ielement,jelement,kelement;
   char line[MAXLINE],*ptr;
   int eof = 0;
 
   while (1) {
     if (comm->me == 0) {
       ptr = fgets(line,MAXLINE,fp);
       if (ptr == NULL) {
         eof = 1;
         fclose(fp);
       } else n = strlen(line) + 1;
     }
     MPI_Bcast(&eof,1,MPI_INT,0,world);
     if (eof) break;
     MPI_Bcast(&n,1,MPI_INT,0,world);
     MPI_Bcast(line,n,MPI_CHAR,0,world);
 
     // strip comment, skip line if blank
 
     if (ptr = strchr(line,'#')) *ptr = '\0';
     nwords = atom->count_words(line);
     if (nwords == 0) continue;
 
     // concatenate additional lines until have params_per_line words
 
     while (nwords < params_per_line) {
       n = strlen(line);
       if (comm->me == 0) {
         ptr = fgets(&line[n],MAXLINE-n,fp);
         if (ptr == NULL) {
           eof = 1;
           fclose(fp);
         } else n = strlen(line) + 1;
       }
       MPI_Bcast(&eof,1,MPI_INT,0,world);
       if (eof) break;
       MPI_Bcast(&n,1,MPI_INT,0,world);
       MPI_Bcast(line,n,MPI_CHAR,0,world);
       if (ptr = strchr(line,'#')) *ptr = '\0';
       nwords = atom->count_words(line);
     }
 
     if (nwords != params_per_line)
       error->all(FLERR,"Incorrect format in COMB potential file");
 
     // words = ptrs to all words in line
 
     nwords = 0;
     words[nwords++] = strtok(line," \t\n\r\f");
     while (words[nwords++] = strtok(NULL," \t\n\r\f")) continue;
 
     // ielement,jelement,kelement = 1st args
     // if all 3 args are in element list, then parse this line
     // else skip to next line
 
     for (ielement = 0; ielement < nelements; ielement++)
       if (strcmp(words[0],elements[ielement]) == 0) break;
     if (ielement == nelements) continue;
     for (jelement = 0; jelement < nelements; jelement++)
       if (strcmp(words[1],elements[jelement]) == 0) break;
     if (jelement == nelements) continue;
     for (kelement = 0; kelement < nelements; kelement++)
       if (strcmp(words[2],elements[kelement]) == 0) break;
     if (kelement == nelements) continue;
 
     // load up parameter settings and error check their values
 
     if (nparams == maxparam) {
       maxparam += DELTA;
       params = (Param *) memory->srealloc(params,maxparam*sizeof(Param),
                                           "pair:params");
     }
 
     params[nparams].ielement = ielement;
     params[nparams].jelement = jelement;
     params[nparams].kelement = kelement;
     params[nparams].powerm = atof(words[3]);
     params[nparams].c = atof(words[4]);
     params[nparams].d = atof(words[5]);
     params[nparams].h = atof(words[6]);
     params[nparams].powern = atof(words[7]);
     params[nparams].beta = atof(words[8]);
     params[nparams].lam21 = atof(words[9]);
     params[nparams].lam22 = atof(words[10]);
     params[nparams].bigb1 = atof(words[11]);
     params[nparams].bigb2 = atof(words[12]);
     params[nparams].bigr = atof(words[13]);
     params[nparams].bigd = atof(words[14]);
     params[nparams].lam11 = atof(words[15]);
     params[nparams].lam12 = atof(words[16]);
     params[nparams].biga1 = atof(words[17]);
     params[nparams].biga2 = atof(words[18]);
     params[nparams].plp1 = atof(words[19]);
     params[nparams].plp3 = atof(words[20]);
     params[nparams].plp6 = atof(words[21]);
     params[nparams].a123 = atof(words[22]);
     params[nparams].aconf= atof(words[23]);
     params[nparams].addrep = atof(words[24]);
     params[nparams].romigb = atof(words[25]);
     params[nparams].romigc = atof(words[26]);
     params[nparams].romigd = atof(words[27]);
     params[nparams].romiga = atof(words[28]);
     params[nparams].QL1 = atof(words[29]);
     params[nparams].QU1 = atof(words[30]);
     params[nparams].DL1 = atof(words[31]);
     params[nparams].DU1 = atof(words[32]);
     params[nparams].QL2 = atof(words[33]);
     params[nparams].QU2 = atof(words[34]);
     params[nparams].DL2 = atof(words[35]);
     params[nparams].DU2 = atof(words[36]);
     params[nparams].chi = atof(words[37]);
     params[nparams].dj  = atof(words[38]);
     params[nparams].dk  = atof(words[39]);
     params[nparams].dl  = atof(words[40]);
     params[nparams].dm  = atof(words[41]);
     params[nparams].esm1 = atof(words[42]);
     params[nparams].cmn1 = atof(words[43]);
     params[nparams].cml1 = atof(words[44]);
     params[nparams].cmn2 = atof(words[45]);
     params[nparams].cml2 = atof(words[46]);
     params[nparams].coulcut = atof(words[47]);
     params[nparams].hfocor = atof(words[48]);
 
     params[nparams].powermint = int(params[nparams].powerm);
 
     // parameter sanity checks
 
     if (params[nparams].lam11 < 0.0 || params[nparams].lam12 < 0.0 ||
         params[nparams].c < 0.0 || params[nparams].d < 0.0 ||
         params[nparams].powern < 0.0 || params[nparams].beta < 0.0 ||
         params[nparams].lam21 < 0.0 || params[nparams].lam22 < 0.0 ||
         params[nparams].bigb1< 0.0 || params[nparams].bigb2< 0.0 ||
         params[nparams].biga1< 0.0 || params[nparams].biga2< 0.0 ||
         params[nparams].bigr < 0.0 || params[nparams].bigd < 0.0 ||
         params[nparams].bigd > params[nparams].bigr ||
         params[nparams].powerm - params[nparams].powermint != 0.0 ||
         (params[nparams].powermint != 3 && params[nparams].powermint != 1) ||
         params[nparams].plp1 < 0.0 || params[nparams].plp3 < 0.0 ||
         params[nparams].plp6 < 0.0  ||
         params[nparams].a123 > 360.0 || params[nparams].aconf < 0.0 ||
         params[nparams].addrep < 0.0 || params[nparams].romigb < 0.0 ||
         params[nparams].romigc < 0.0 || params[nparams].romigd < 0.0 ||
         params[nparams].romiga < 0.0 ||
         params[nparams].QL1 > 0.0 || params[nparams].QU1 < 0.0 ||
         params[nparams].DL1 < 0.0 || params[nparams].DU1 > 0.0 ||
         params[nparams].QL2 > 0.0 || params[nparams].QU2 < 0.0 ||
         params[nparams].DL2 < 0.0 || params[nparams].DU2 > 0.0 ||
         params[nparams].chi < 0.0 ||
 //        params[nparams].dj < 0.0 || params[nparams].dk < 0.0 ||
 //        params[nparams].dl < 0.0 || params[nparams].dm < 0.0 ||
         params[nparams].esm1 < 0.0)
       error->all(FLERR,"Illegal COMB parameter");
 
     if (params[nparams].lam11 < params[nparams].lam21 ||
         params[nparams].lam12 < params[nparams].lam22 ||
         params[nparams].biga1< params[nparams].bigb1 ||
         params[nparams].biga2< params[nparams].bigb2)
       error->all(FLERR,"Illegal COMB parameter");
 
     nparams++;
   }
 
   delete [] words;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void PairComb::setup()
 {
   int i,j,k,m,n;
 
   // set elem2param for all element triplet combinations
   // must be a single exact match to lines read from file
   // do not allow for ACB in place of ABC
 
   memory->destroy(elem2param);
   memory->create(elem2param,nelements,nelements,nelements,"pair:elem2param");
 
   for (i = 0; i < nelements; i++)
     for (j = 0; j < nelements; j++)
       for (k = 0; k < nelements; k++) {
         n = -1;
         for (m = 0; m < nparams; m++) {
           if (i == params[m].ielement && j == params[m].jelement &&
               k == params[m].kelement) {
             if (n >= 0) error->all(FLERR,"Potential file has duplicate entry");
             n = m;
           }
         }
         if (n < 0) error->all(FLERR,"Potential file is missing an entry");
         elem2param[i][j][k] = n;
       }
 
   // compute parameter values derived from inputs
 
   for (m = 0; m < nparams; m++) {
     params[m].cut = params[m].bigr + params[m].bigd;
     params[m].cutsq = params[m].cut*params[m].cut;
     params[m].c1 = pow(2.0*params[m].powern*1.0e-16,-1.0/params[m].powern);
     params[m].c2 = pow(2.0*params[m].powern*1.0e-8,-1.0/params[m].powern);
     params[m].c3 = 1.0/params[m].c2;
     params[m].c4 = 1.0/params[m].c1;
     params[m].rlm1 = 0.5*(params[m].lam11+params[m].lam12)*params[m].romigc;
     params[m].rlm2 = 0.5*(params[m].lam21+params[m].lam22)*params[m].romigd;
 
     params[m].Qo1 = (params[m].QU1+params[m].QL1)/2.0; // (A22)
     params[m].dQ1 = (params[m].QU1-params[m].QL1)/2.0; // (A21)
     params[m].aB1 = 1.0 /
       (1.0-pow(fabs(params[m].Qo1/params[m].dQ1),10.0)); // (A20)
     params[m].bB1 = pow(fabs(params[m].aB1),0.1)/params[m].dQ1; // (A19)
     params[m].nD1 = log(params[m].DU1/(params[m].DU1-params[m].DL1))/
                     log(params[m].QU1/(params[m].QU1-params[m].QL1));
     params[m].bD1 = (pow((params[m].DL1-params[m].DU1),(1.0/params[m].nD1)))/
                     (params[m].QU1-params[m].QL1);
 
     params[m].Qo2 = (params[m].QU2+params[m].QL2)/2.0; // (A22)
     params[m].dQ2 = (params[m].QU2-params[m].QL2)/2.0; // (A21)
     params[m].aB2 = 1.0 /
       (1.0-pow(fabs(params[m].Qo2/params[m].dQ2),10.0)); // (A20)
     params[m].bB2 = pow(fabs(params[m].aB2),0.1)/params[m].dQ2; // (A19)
     params[m].nD2 = log(params[m].DU2/(params[m].DU2-params[m].DL2))/
                     log(params[m].QU2/(params[m].QU2-params[m].QL2));
     params[m].bD2 = (pow((params[m].DL2-params[m].DU2),(1.0/params[m].nD2)))/
                     (params[m].QU2-params[m].QL2);
 
     params[m].lcut = params[m].coulcut;
     params[m].lcutsq = params[m].lcut*params[m].lcut;
 
     params[m].gamma = 1.0;        // for the change in pair_comb.h
   }
 
   // set cutmax to max of all params
 
   cutmax = cutmin = 0.0;
   cor_flag = 0;
   for (m = 0; m < nparams; m++) {
     if (params[m].cut > cutmax) cutmax = params[m].cut;
     if (params[m].lcut > cutmax) cutmax = params[m].lcut;
     if (params[m].cutsq > cutmin) cutmin = params[m].cutsq+0.2;
     if (params[m].hfocor > 0.0001) cor_flag = 1;
   }
 }
 
 /* ---------------------------------------------------------------------- */
 
 void PairComb::repulsive(Param *param, double rsq, double &fforce,
                     int eflag, double &eng, double iq, double jq)
 {
   double r,tmp_fc,tmp_fc_d,tmp_exp,Di,Dj;
   double bigA,Asi,Asj,vrcs,fvrcs,fforce_tmp;
   double rslp,rslp2,rslp4,arr1,arr2,fc2j,fc3j,fcp2j,fcp3j;
 
   double romi = param->addrep;
   double rrcs = param->bigr + param->bigd;
 
   r = sqrt(rsq);
   if (r > rrcs) return ;
 
   tmp_fc = comb_fc(r,param);
   tmp_fc_d = comb_fc_d(r,param);
   tmp_exp = exp(-param->rlm1 * r);
 
   arr1 = 2.22850; arr2 = 1.89350;
   fc2j = comb_fc2(r);
   fc3j = comb_fc3(r);
   fcp2j = comb_fc2_d(r);
   fcp3j = comb_fc3_d(r);
 
   Di = param->DU1 + pow(fabs(param->bD1*(param->QU1-iq)),param->nD1);
   Dj = param->DU2 + pow(fabs(param->bD2*(param->QU2-jq)),param->nD2);
   Asi = param->biga1 * exp(param->lam11*Di);
   Asj = param->biga2 * exp(param->lam12*Dj);
 
   if ( Asi > 0.0 && Asj > 0.0 )
     bigA = sqrt(Asi*Asj)*param->romiga;
   else
     bigA = 0.0;
 
   fforce = -bigA * tmp_exp * (tmp_fc_d - tmp_fc*param->rlm1) / r;
 
   // additional repulsion for TiO2 and HfO2 (switch by cor_flag)
 
   vrcs = 0.0; fvrcs = 0.0;
   if (romi > 0.0) {
     if (!cor_flag) {
       vrcs = romi * pow((1.0-r/rrcs),2.0);
       fvrcs= romi * 2.0 * (r/rrcs-1.0)/rrcs; }
     else if (cor_flag) {
       rslp = ((arr1-r)/(arr1-arr2));
       rslp2 = rslp * rslp; rslp4 = rslp2 * rslp2;
       vrcs = fc2j * fc3j * romi * ((50.0*rslp4-30.0*rslp2+4.50))/8.0;
       fvrcs = fcp2j*fcp3j*romi*rslp*(-25.0*rslp2+7.50)/(arr1-arr2);
     }
     fforce_tmp = fforce*vrcs - (tmp_fc * bigA * tmp_exp * fvrcs);
     fforce += fforce_tmp;
   }
 
   // eng = repulsive energy
 
   if (eflag) eng = (tmp_fc * bigA * tmp_exp)*(1.0+vrcs);
 }
 
 /* ---------------------------------------------------------------------- */
 
 double PairComb::zeta(Param *param, double rsqij, double rsqik,
                          double *delrij, double *delrik)
 {
   double rij,rik,costheta,arg,ex_delr;
 
   rij = sqrt(rsqij);
   if (rij > param->bigr+param->bigd) return 0.0;
   rik = sqrt(rsqik);
   costheta = vec3_dot(delrij,delrik) / (rij*rik);
 
   if (param->powermint == 3) arg = pow(param->rlm2 * (rij-rik),3.0);
   else arg = param->rlm2 * (rij-rik);
 
   if (arg > 69.0776) ex_delr = 1.e30;
   else if (arg < -69.0776) ex_delr = 0.0;
   else ex_delr = exp(arg);
 
   return comb_fc(rik,param) * comb_gijk(costheta,param) * ex_delr;
 }
 
 /* ----------------------------------------------------------------------
    Legendre polynomial bond angle correction to energy
 ------------------------------------------------------------------------- */
 
 double PairComb::elp(Param *param, double rsqij, double rsqik,
                      double *delrij, double *delrik)
 {
   if (param->aconf > 1.0e-6 || param->plp1 > 1.0e-6 ||
       param->plp3 > 1.0e-6 || param->plp6 > 1.0e-6) {
     double rij,rik,costheta,lp1,lp3,lp6;
     double rmu,rmu2,comtt,fck;
     double pplp1 = param->plp1, pplp3 = param->plp3, pplp6 = param->plp6;
     double c123 = cos(param->a123*MY_PI/180.0);
 
     // cos(theta) of the i-j-k
     // cutoff function of rik
 
     rij = sqrt(rsqij);
     rik = sqrt(rsqik);
     costheta = vec3_dot(delrij,delrik) / (rij*rik);
     fck = comb_fc(rik,param);
     rmu = costheta;
 
     // Legendre Polynomial functions
 
     if (param->plp1 > 1.0e-6 || param->plp3 > 1.0e-6 || param->plp6 > 1.0e-6) {
       rmu2 = rmu*rmu;
       lp1 = rmu; lp3 = 0.5*(5.0*rmu2*rmu-3.0*rmu);
       lp6 = (231.0*rmu2*rmu2*rmu2-315.0*rmu2*rmu2+105.0*rmu2-5.0)/16.0;
       comtt = pplp1*lp1 + pplp3*lp3 + pplp6*lp6;
     } else comtt = 0.0;
 
     // bond-bending terms
 
     if (param->aconf>1e-4) {
       if (param->hfocor >= 0.0)
         comtt += param->aconf *(rmu-c123)*(rmu-c123);
       else if (param->hfocor < 0.0)
         comtt += param->aconf *(4.0-(rmu-c123)*(rmu-c123));
     }
 
     return 0.5 * fck * comtt;
   }
 
   return 0.0;
 }
 
 /* ----------------------------------------------------------------------
    Legendre polynomial bond angle correction to forces
 ------------------------------------------------------------------------- */
 
 void PairComb::flp(Param *param, double rsqij, double rsqik,
                    double *delrij, double *delrik, double *drilp,
                    double *drjlp, double *drklp)
 {
   double ffj1,ffj2,ffk1,ffk2;
   ffj1 = 0.0; ffj2 = 0.0; ffk1 = 0.0; ffk2 = 0.0;
 
   if (param->aconf > 1.0e-4 || param->plp1 > 1.0e-6 ||
       param->plp3 > 1.0e-6 || param->plp6 > 1.0e-6) {
     double rij,rik,costheta,lp1,lp1_d,lp3,lp3_d,lp6,lp6_d;
     double rmu,rmu2,comtt,comtt_d,com4k,com5,fcj,fck,fck_d;
 
     double pplp1 = param->plp1;
     double pplp3 = param->plp3;
     double pplp6 = param->plp6;
     double c123 = cos(param->a123*MY_PI/180.0);
 
     // fck_d = derivative of cutoff function
 
     rij = sqrt(rsqij); rik = sqrt(rsqik);
     costheta = vec3_dot(delrij,delrik) / (rij*rik);
     fcj = comb_fc(rij,param);
     fck = comb_fc(rik,param);
     fck_d = comb_fc_d(rik,param);
     rmu = costheta;
 
     // Legendre Polynomial functions and derivatives
 
     if (param->plp1 > 1.0e-6 || param->plp3 > 1.0e-6 || param->plp6 > 1.0e-6) {
       rmu2 = rmu*rmu;
       lp1 = rmu; lp3 = (2.5*rmu2*rmu-1.5*rmu);
       lp6 = (231.0*rmu2*rmu2*rmu2-315.0*rmu2*rmu2+105.0*rmu2-5.0)/16.0;
       lp1_d = 1.0;lp3_d = (7.5*rmu2-1.5);
       lp6_d = (1386.0*rmu2*rmu2*rmu-1260.0*rmu2*rmu+210.0)/16.0;
       comtt   = pplp1*lp1   + pplp3*lp3   + pplp6*lp6;
       comtt_d = pplp1*lp1_d + pplp3*lp3_d + pplp6*lp6_d;
     } else {
       comtt = 0.0;
       comtt_d = 0.0;
     }
 
     // bond-bending terms derivatives
 
     if (param->aconf > 1.0e-4) {
       if (param->hfocor >= 0.0) {
         comtt += param->aconf *(rmu-c123)*(rmu-c123);
         comtt_d += 2.0*param->aconf*(rmu-c123);
       } else if (param->hfocor < 0.0) {
         comtt += param->aconf *(4.0-(rmu-c123)*(rmu-c123));
         comtt_d += -2.0*param->aconf*(rmu-c123);
       }
     }
 
     com4k = fcj * fck_d * comtt;
     com5 = fcj * fck * comtt_d;
 
     ffj1 =-0.5*(com5/(rij*rik));
     ffj2 = 0.5*(com5*rmu/rsqij);
     ffk1 = ffj1;
     ffk2 = 0.5*(-com4k/rik+com5*rmu/rsqik);
 
   } else {
     ffj1 = 0.0; ffj2 = 0.0;
     ffk1 = 0.0; ffk2 = 0.0;
   }
 
   // j-atom
 
   vec3_scale(ffj1,delrik,drjlp);             // (k,x[],y[]), y[]=k*x[]
   vec3_scaleadd(ffj2,delrij,drjlp,drjlp);   // (k,x[],y[],z[]), z[]=k*x[]+y[]
 
   // k-atom
 
   vec3_scale(ffk1,delrij,drklp);
   vec3_scaleadd(ffk2,delrik,drklp,drklp);
 
   // i-atom
 
   vec3_add(drjlp,drklp,drilp);                    // (x[],y[],z[]), z[]=x[]+y[]
   vec3_scale(-1.0,drilp,drilp);
 }
 
 /* ---------------------------------------------------------------------- */
 
 void PairComb::force_zeta(Param *param, int eflag, int i, int j, double rsq,
                 double zeta_ij, double iq, double jq, double &fforce,
                 double &prefactor, double &eng)
 {
   double r,fa,fa_d,bij;
 
   r = sqrt(rsq);
   if (r > param->bigr+param->bigd) return;
   fa = comb_fa(r,param,iq,jq);
   fa_d = comb_fa_d(r,param,iq,jq);
   bij = comb_bij(zeta_ij,param);
   bbij[i][j] = bij;
 
   // force
   fforce = 0.5*bij*fa_d / r;
   prefactor = -0.5*fa * comb_bij_d(zeta_ij,param);
 
   // eng = attractive energy
   if (eflag) eng = 0.5*bij*fa;
 }
 
 /* ---------------------------------------------------------------------- */
 
 double PairComb::comb_fc(double r, Param *param)
 {
   double comb_R = param->bigr;
   double comb_D = param->bigd;
 
   if (r < comb_R-comb_D) return 1.0;
   if (r > comb_R+comb_D) return 0.0;
   return 0.5*(1.0 + cos(MY_PI*(r - comb_R)/comb_D));
 }
 
 /* ---------------------------------------------------------------------- */
 
 double PairComb::comb_fc_d(double r, Param *param)
 {
   double comb_R = param->bigr;
   double comb_D = param->bigd;
 
   if (r < comb_R-comb_D) return 0.0;
   if (r > comb_R+comb_D) return 0.0;
   return -(MY_PI2/comb_D) * sin(MY_PI*(r - comb_R)/comb_D);
 }
 
 /* ---------------------------------------------------------------------- */
 
 double PairComb::comb_fc2(double r)
 {
   double comb_R = 1.89350;
   double comb_D = comb_R + 0.050;
 
   if (r < comb_R) return 0.0;
   if (r > comb_D) return 1.0;
   return 0.5*(1.0 + cos(MY_PI*(r - comb_R)/(comb_D-comb_R)));
 }
 
 /* ---------------------------------------------------------------------- */
 
 double PairComb::comb_fc2_d(double r)
 {
   double comb_R = 1.89350;
   double comb_D = comb_R + 0.050;
 
   if (r < comb_R) return 0.0;
   if (r > comb_D) return 0.0;
   return -(MY_PI2/(comb_D-comb_R)) * sin(MY_PI*(r - comb_R)/(comb_D-comb_R));
 }
 
 /* ---------------------------------------------------------------------- */
 
 double PairComb::comb_fc3(double r)
 {
   double comb_R = 2.51350;
   double comb_D = comb_R + 0.050;
 
   if (r < comb_R) return 1.0;
   if (r > comb_D) return 0.0;
   return 0.5*(1.0 + cos(MY_PI*(r - comb_R)/(comb_D-comb_R)));
 }
 
 /* ---------------------------------------------------------------------- */
 
 double PairComb::comb_fc3_d(double r)
 {
   double comb_R = 2.51350;
   double comb_D = comb_R + 0.050;
 
   if (r < comb_R) return 0.0;
   if (r > comb_D) return 0.0;
   return -(MY_PI2/(comb_D-comb_R)) * sin(MY_PI*(r - comb_R)/(comb_D-comb_R));
 }
 
 /* ---------------------------------------------------------------------- */
 
 double PairComb::self(Param *param, double qi, double selfpot)
 {
  double self_tmp, cmin, cmax, qmin, qmax;
  double s1=param->chi, s2=param->dj, s3=param->dk, s4=param->dl, s5=param->dm;
 
  self_tmp = 0.0;
  qmin = param->QL1*0.90;
  qmax = param->QU1*0.90;
  cmin = cmax = 1000.0;
 
  self_tmp = qi*(s1+qi*(s2+selfpot+qi*(s3+qi*(s4+qi*qi*s5))));
 
  if (qi < qmin) self_tmp += cmin * pow((qi-qmin),4.0);
  if (qi > qmax) self_tmp += cmax * pow((qi-qmax),4.0);
 
  return self_tmp;
 }
 
 /* ---------------------------------------------------------------------- */
 
 double PairComb::comb_fa(double r, Param *param, double iq, double jq)
 {
   double bigB,Bsi,Bsj;
   double qi,qj,Di,Dj;
 
   if (r > param->bigr + param->bigd) return 0.0;
   qi = iq; qj = jq;
   Di = Dj = Bsi = Bsj = bigB = 0.0;
   Di = param->DU1 + pow(fabs(param->bD1*(param->QU1-qi)),param->nD1);
   Dj = param->DU2 + pow(fabs(param->bD2*(param->QU2-qj)),param->nD2);
   Bsi = param->bigb1 * exp(param->lam21*Di)*
        (param->aB1-fabs(pow(param->bB1*(qi-param->Qo1),10.0)));
   Bsj = param->bigb2 * exp(param->lam22*Dj)*
        (param->aB2-fabs(pow(param->bB2*(qj-param->Qo2),10.0)));
   if (Bsi > 0.0 && Bsj > 0.0) bigB = sqrt(Bsi*Bsj)*param->romigb;
   else bigB = 0.0;
 
   return -bigB * exp(-param->rlm2 * r) * comb_fc(r,param);
 }
 
 /* ---------------------------------------------------------------------- */
 
 double PairComb::comb_fa_d(double r, Param *param, double iq, double jq)
 {
   double bigB,Bsi,Bsj;
   double qi,qj,Di,Dj;
 
   if (r > param->bigr + param->bigd) return 0.0;
   qi = iq; qj = jq;
   Di = Dj = Bsi = Bsj = bigB = 0.0;
   Di = param->DU1 + pow(fabs(param->bD1*(param->QU1-qi)),param->nD1);
   Dj = param->DU2 + pow(fabs(param->bD2*(param->QU2-qj)),param->nD2);
   Bsi = param->bigb1 * exp(param->lam21*Di)*
        (param->aB1-fabs(pow(param->bB1*(qi-param->Qo1),10.0)));
   Bsj = param->bigb2 * exp(param->lam22*Dj)*
        (param->aB2-fabs(pow(param->bB2*(qj-param->Qo2),10.0)));
   if (Bsi > 0.0 && Bsj > 0.0) bigB = sqrt(Bsi*Bsj)*param->romigb;
   else bigB = 0.0;
 
   return bigB * exp(-param->rlm2 * r) *
     (param->rlm2 * comb_fc(r,param) - comb_fc_d(r,param));
 }
 
 /* ---------------------------------------------------------------------- */
 
 double PairComb::comb_bij(double zeta, Param *param)
 {
   double tmp = param->beta * zeta;
   if (tmp > param->c1) return 1.0/sqrt(tmp);
   if (tmp > param->c2)
     return (1.0 - pow(tmp,-1.0*param->powern) / (2.0*param->powern))/sqrt(tmp);
   if (tmp < param->c4) return 1.0;
   if (tmp < param->c3)
     return 1.0 - pow(tmp,param->powern)/(2.0*param->powern);
   return pow(1.0 + pow(tmp,param->powern), -1.0/(2.0*param->powern));
 }
 
 /* ---------------------------------------------------------------------- */
 
 double PairComb::comb_bij_d(double zeta, Param *param)
 {
   double tmp = param->beta * zeta;
   if (tmp > param->c1) return param->beta * -0.5*pow(tmp,-1.5);
   if (tmp > param->c2)
     return param->beta * (-0.5*pow(tmp,-1.5) *
                           (1.0 - 0.5*(1.0 +  1.0/(2.0*param->powern)) *
                            pow(tmp,-param->powern)));
   if (tmp < param->c4) return 0.0;
   if (tmp < param->c3)
     return -0.5*param->beta * pow(tmp,param->powern-1.0);
 
   double tmp_n = pow(tmp,param->powern);
   return -0.5 * pow(1.0+tmp_n, -1.0-(1.0/(2.0*param->powern)))*tmp_n / zeta;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void PairComb::attractive(Param *param, double prefactor,
                           double rsqij, double rsqik,
                           double *delrij, double *delrik,
                           double *fi, double *fj, double *fk)
 {
   double rij_hat[3],rik_hat[3];
   double rij,rijinv,rik,rikinv;
 
   rij = sqrt(rsqij);
   rijinv = 1.0/rij;
   vec3_scale(rijinv,delrij,rij_hat);
 
   rik = sqrt(rsqik);
   rikinv = 1.0/rik;
   vec3_scale(rikinv,delrik,rik_hat);
 
   comb_zetaterm_d(prefactor,rij_hat,rij,rik_hat,rik,fi,fj,fk,param);
 }
 
 /* ---------------------------------------------------------------------- */
 
 void PairComb::comb_zetaterm_d(double prefactor, double *rij_hat, double rij,
                                double *rik_hat, double rik, double *dri,
                                double *drj, double *drk, Param *param)
 {
   double gijk,gijk_d,ex_delr,ex_delr_d,fc,dfc,cos_theta,tmp;
   double dcosdri[3],dcosdrj[3],dcosdrk[3];
 
   fc = comb_fc(rik,param);
   dfc = comb_fc_d(rik,param);
   if (param->powermint == 3) tmp = pow(param->rlm2 * (rij-rik),3.0);
   else tmp = param->rlm2 * (rij-rik);
 
   if (tmp > 69.0776) ex_delr = 1.e30;
   else if (tmp < -69.0776) ex_delr = 0.0;
   else ex_delr = exp(tmp); // ex_delr is Ygexp
 
   if (param->powermint == 3)
     ex_delr_d = 3.0*pow(param->rlm2,3.0) * pow(rij-rik,2.0)*ex_delr; // com3
   else ex_delr_d = param->rlm2 * ex_delr; // com3
 
   cos_theta = vec3_dot(rij_hat,rik_hat);
   gijk = comb_gijk(cos_theta,param);
   gijk_d = comb_gijk_d(cos_theta,param);
   costheta_d(rij_hat,rij,rik_hat,rik,dcosdri,dcosdrj,dcosdrk);
 
   // compute the derivative wrt Ri
   // dri = -dfc*gijk*ex_delr*rik_hat;
   // dri += fc*gijk_d*ex_delr*dcosdri;
   // dri += fc*gijk*ex_delr_d*(rik_hat - rij_hat);
   // (k,x[],y[]), y[]=k*x[]
   // (k,x[],y[],z[]), z[]=k*x[]+y[]
 
   vec3_scale(-dfc*gijk*ex_delr,rik_hat,dri);
   vec3_scaleadd(fc*gijk_d*ex_delr,dcosdri,dri,dri);
   vec3_scaleadd(fc*gijk*ex_delr_d,rik_hat,dri,dri);
   vec3_scaleadd(-fc*gijk*ex_delr_d,rij_hat,dri,dri);
   vec3_scale(prefactor,dri,dri);
 
   // compute the derivative wrt Rj
   // drj = fc*gijk_d*ex_delr*dcosdrj;
   // drj += fc*gijk*ex_delr_d*rij_hat;
 
   vec3_scale(fc*gijk_d*ex_delr,dcosdrj,drj);
   vec3_scaleadd(fc*gijk*ex_delr_d,rij_hat,drj,drj);
   vec3_scale(prefactor,drj,drj);
 
   // compute the derivative wrt Rk
   // drk = dfc*gijk*ex_delr*rik_hat;
   // drk += fc*gijk_d*ex_delr*dcosdrk;
   // drk += -fc*gijk*ex_delr_d*rik_hat;
 
   vec3_scale(dfc*gijk*ex_delr,rik_hat,drk);
   vec3_scaleadd(fc*gijk_d*ex_delr,dcosdrk,drk,drk);
   vec3_scaleadd(-fc*gijk*ex_delr_d,rik_hat,drk,drk);
   vec3_scale(prefactor,drk,drk);
 }
 
 /* ---------------------------------------------------------------------- */
 
 void PairComb::costheta_d(double *rij_hat, double rij,
                              double *rik_hat, double rik,
                              double *dri, double *drj, double *drk)
 {
   // first element is devative wrt Ri, second wrt Rj, third wrt Rk
 
   double cos_theta = vec3_dot(rij_hat,rik_hat);
 
   vec3_scaleadd(-cos_theta,rij_hat,rik_hat,drj);
   vec3_scale(1.0/rij,drj,drj);
   vec3_scaleadd(-cos_theta,rik_hat,rij_hat,drk);
   vec3_scale(1.0/rik,drk,drk);
   vec3_add(drj,drk,dri);
   vec3_scale(-1.0,dri,dri);
 }
 
 /* ---------------------------------------------------------------------- */
 
 void PairComb::sm_table()
 {
   int i,j,k,m,nntypes,ncoul;
   int inty, itype, jtype;
   int iparam_i, iparam_ij, iparam_ji;
   double r,dra,drin,rc,z,zr,zrc,ea,eb,ea3,eb3,alf;
   double exp2er,exp2ersh,fafash,dfafash,F1,dF1,ddF1,E1,E2,E3,E4;
   double exp2ear,exp2ebr,exp2earsh,exp2ebrsh,fafbsh,dfafbsh;
 
   int n = atom->ntypes;
   int nmax = atom->nmax;
 
   dra  = 0.001;  // lookup table step size
   drin = 0.1;    // starting distance of 1/r
   rc = cutmax;
   alf = 0.20;
 
   nntypes = int((n+1)*n/2); // interaction types
   ncoul = int((rc-drin)/dra)+1;
 
   // allocate arrays
 
   memory->create(intype,n,n,"pair:intype");
   memory->create(fafb,ncoul,nntypes,"pair:fafb");
   memory->create(dfafb,ncoul,nntypes,"pair:dfafb");
   memory->create(ddfafb,ncoul,nntypes,"pair:ddfafb");
   memory->create(phin,ncoul,nntypes,"pair:phin");
   memory->create(dphin,ncoul,nntypes,"pair:dphin");
   memory->create(erpaw,25000,2,"pair:erpaw");
   memory->create(NCo,nmax,"pair:NCo");
   memory->create(bbij,nmax,MAXNEIGH,"pair:bbij");
   memory->create(sht_num,nmax,"pair:sht_num");
-  sht_first = (int **) memory->smalloc(nmax*sizeof(int *),
-            "pair:sht_first");
+  sht_first = (int **) memory->smalloc(nmax*sizeof(int *),"pair:sht_first");
 
   // set interaction number: 0-0=0, 1-1=1, 0-1=1-0=2
 
   m = 0; k = n;
   for (i = 0; i < n; i++) {
     for (j = 0; j < n; j++) {
       if (j == i) {
         intype[i][j] = m;
         m += 1;
       } else if (j != i && j > i) {
         intype[i][j] = k;
         k += 1;
       } else if (j != i && j < i) {
         intype[i][j] = intype[j][i];
       }
     }
   }
 
   // default arrays to zero
 
   for (i = 0; i < ncoul; i ++) {
     for (j = 0; j < nntypes; j ++) {
       fafb[i][j] = 0.0;
       dfafb[i][j] = 0.0;
       ddfafb[i][j] = 0.0;
       phin[i][j] = 0.0;
       dphin[i][j] = 0.0;
     }
   }
 
   // direct 1/r energy with Slater 1S orbital overlap
 
   for (i = 0; i < n; i++) {
     r = drin;
     itype = params[i].ielement;
     iparam_i = elem2param[itype][itype][itype];
     z = params[iparam_i].esm1;
     for (j = 0; j < ncoul; j++) {
       exp2er = exp(-2.0 * z * r);
       phin[j][i] = 1.0 - exp2er * (1.0 + 2.0 * z * r * (1.0 + z * r));
       dphin[j][i] = (4.0 * exp2er * z * z * z * r * r);
       r += dra;
     }
   }
 
   for (i = 0; i < n; i ++) {
     for (j = 0; j < n; j ++) {
       r = drin;
       if (j == i) {
         itype = params[i].ielement;
         inty = intype[itype][itype];
         iparam_i = elem2param[itype][itype][itype];
         z = params[iparam_i].esm1;
         zrc = z * rc;
         exp2ersh = exp(-2.0 * zrc);
         fafash = -exp2ersh * (1.0 / rc +
                               z * (11.0/8.0 + 3.0/4.0*zrc + zrc*zrc/6.0));
         dfafash = exp2ersh * (1.0/(rc*rc) + 2.0*z/rc +
                               z*z*(2.0 + 7.0/6.0*zrc + zrc*zrc/3.0));
         for (k = 0; k < ncoul; k ++) {
           zr = z * r;
           exp2er = exp(-2.0*zr);
           F1 = -exp2er * (1.0 / r +
                           z * (11.0/8.0 + 3.0/4.0*zr + zr*zr/6.0));
           dF1 = exp2er * (1.0/(r*r) + 2.0*z/r +
                           z*z*(2.0 + 7.0/6.0*zr + zr*zr/3.0));
           ddF1 = -exp2er * (2.0/(r*r*r) + 4.0*z/(r*r) -
                             z*z*z/3.0*(17.0/2.0 + 5.0*zr + 2.0*zr*zr));
           fafb[k][inty] = F1-fafash-(r-rc)*dfafash;
           dfafb[k][inty] = (dF1 - dfafash);
           ddfafb[k][inty] = ddF1;
           r += dra;
         }
       } else if (j != i) {
         itype = params[i].ielement;
         jtype = params[j].ielement;
         inty = intype[itype][jtype];
         iparam_ij = elem2param[itype][jtype][jtype];
         ea = params[iparam_ij].esm1;
         ea3 = ea*ea*ea;
         iparam_ji = elem2param[jtype][itype][itype];
         eb = params[iparam_ji].esm1;
         eb3 = eb*eb*eb;
         E1 = ea*eb3*eb/((ea+eb)*(ea+eb)*(ea-eb)*(ea-eb));
         E2 = eb*ea3*ea/((ea+eb)*(ea+eb)*(eb-ea)*(eb-ea));
         E3 = (3.0*ea*ea*eb3*eb-eb3*eb3) /
           ((ea+eb)*(ea+eb)*(ea+eb)*(ea-eb)*(ea-eb)*(ea-eb));
         E4 = (3.0*eb*eb*ea3*ea-ea3*ea3) /
           ((ea+eb)*(ea+eb)*(ea+eb)*(eb-ea)*(eb-ea)*(eb-ea));
         exp2earsh = exp(-2.0*ea*rc);
         exp2ebrsh = exp(-2.0*eb*rc);
         fafbsh = -exp2earsh*(E1 + E3/rc)-exp2ebrsh*(E2 + E4/rc);
         dfafbsh =
           exp2earsh*(2.0*ea*(E1+E3/rc)+E3/(rc*rc)) +
           exp2ebrsh*(2.0*eb*(E2+E4/rc)+E4/(rc*rc));
         for (k = 0; k < ncoul; k ++) {
           exp2ear = exp(-2.0*ea*r);
           exp2ebr = exp(-2.0*eb*r);
           fafb[k][inty] =
             - exp2ear*(E1+E3/r) - exp2ebr*(E2+E4/r)
             - fafbsh - (r-rc) * dfafbsh;
           dfafb[k][inty] = (exp2ear*(2.0*ea*(E1+E3/r) + E3/(r*r))
                             + exp2ebr*(2.0*eb*(E2+E4/r) + E4/(r*r))- dfafbsh);
           ddfafb[k][inty] = (- exp2ear*(E3/(r*r)*(1.0/r+2.0*ea/r+2.0/(r*r))
                                         + 2.0*ea*(E1+E3/r))-
                              exp2ebr*(E4/(r*r)
                                       *(1.0/r+2.0*eb/r+2.0/(r*r)) +
                                       2.0*eb*(E2+E4/r)));
           r += dra;
         }
       }
     }
   }
 
   for (i = 0; i < 25000; i ++) {
     r = dra * i + drin;
     erpaw[i][0] = erfc(r*alf);
     erpaw[i][1] = exp(-r*r*alf*alf);
   }
 }
 
 /* ---------------------------------------------------------------------- */
 
 void PairComb::potal_calc(double &calc1, double &calc2, double &calc3)
 {
   double alf,rcoul,esucon;
   int m;
 
   rcoul = 0.0;
   for (m = 0; m < nparams; m++)
     if (params[m].lcut > rcoul) rcoul = params[m].lcut;
 
   alf = 0.20;
   esucon = force->qqr2e;
 
   calc2 = (erfc(rcoul*alf)/rcoul/rcoul+2.0*alf/MY_PIS*
            exp(-alf*alf*rcoul*rcoul)/rcoul)*esucon/rcoul;
   calc3 = (erfc(rcoul*alf)/rcoul)*esucon;
   calc1 = -(alf/MY_PIS*esucon+calc3*0.5);
 }
 
 /* ---------------------------------------------------------------------- */
 
 void PairComb::tri_point(double rsq, int &mr1, int &mr2,
                          int &mr3, double &sr1, double &sr2,
                          double &sr3, int &itype)
 {
  double r, rin, dr, dd, rr1, rridr, rridr2;
 
  rin = 0.10; dr = 0.0010;
  r = sqrt(rsq);
  if (r < rin + 2.0*dr) r = rin + 2.0*dr;
  if (r > cutmax - 2.0*dr) r = cutmax - 2.0*dr;
  rridr = (r-rin)/dr;
 
  mr1 = int(rridr)-1;
  dd = rridr - float(mr1);
  if (dd > 0.5) mr1 += 1;
  mr2 = mr1 + 1;
  mr3 = mr2 + 1;
 
  rr1 = float(mr1)*dr;
  rridr = (r - rin - rr1)/dr;
  rridr2 = rridr * rridr;
 
  sr1 = (rridr2 - rridr) * 0.50;
  sr2 = 1.0 - rridr2;
  sr3 = (rridr2 + rridr) * 0.50;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void PairComb::direct(int inty, int mr1, int mr2, int mr3, double rsq,
                       double sr1, double sr2, double sr3,
                       double iq, double jq,
                       double potal, double fac11, double fac11e,
                       double &pot_tmp, double &pot_d)
 {
  double r,erfcc,fafbn1,potij,sme2,esucon;
  double r3,erfcd,dfafbn1,smf2,dvdrr,alf,alfdpi;
 
  r = sqrt(rsq);
  r3 = r * rsq;
  alf = 0.20;
  alfdpi = 2.0*alf/MY_PIS;
  esucon = force->qqr2e;
  pot_tmp = 0.0;
  pot_d = 0.0;
 
  // 1/r energy
 
  erfcc = sr1*erpaw[mr1][0] + sr2*erpaw[mr2][0] + sr3*erpaw[mr3][0];
  fafbn1= sr1*fafb[mr1][inty] + sr2*fafb[mr2][inty] + sr3*fafb[mr3][inty];
  potij = (erfcc/r * esucon - fac11e);
  sme2 = potij + fafbn1 * esucon;
  pot_tmp = 1.0 * iq * jq *sme2;
 
  // 1/r force (wrt r)
 
  erfcd = sr1*erpaw[mr1][1] + sr2*erpaw[mr2][1] + sr3*erpaw[mr3][1];
  dfafbn1= sr1*dfafb[mr1][inty] + sr2*dfafb[mr2][inty] + sr3*dfafb[mr3][inty];
  dvdrr = (erfcc/r3+alfdpi*erfcd/rsq)*esucon-fac11;
  smf2 = dvdrr - dfafbn1 * esucon/r;
  pot_d =  1.0 * iq * jq * smf2;
 
 }
 
 /* ---------------------------------------------------------------------- */
 
 void PairComb::field(Param *param, double rsq, double iq,double jq,
                      double &vionij,double &fvionij)
 {
  double r,r5,r6,rc,rc5,rc6,rf5,drf6,smpn,smpl,rfx1,rfx2;
  double cmi1,cmi2,cmj1,cmj2;
 
  r = sqrt(rsq);
  r5 = r*r*r*r*r;
  r6 = r5 * r;
  rc = param->lcut;
  rc5 = rc*rc*rc*rc*rc;
  rc6 = rc5 * rc;
  cmi1 = param->cmn1;
  cmi2 = param->cmn2;
  cmj1 = param->cml1;
  cmj2 = param->cml2;
  rf5 = 1.0/r5 - 1.0/rc5 + 5.0*(r-rc)/rc6;
  drf6 = 5.0/rc6 - 5.0/r6;
 
  // field correction energy
 
  smpn = rf5*jq*(cmi1+jq*cmi2);
  smpl = rf5*iq*(cmj1+iq*cmj2);
  vionij += 1.0 * (smpn + smpl);
 
  // field correction force
 
  rfx1 = jq*drf6*(cmi1+jq*cmi2)/r;
  rfx2 = iq*drf6*(cmj1+iq*cmj2)/r;
  fvionij -= 1.0 * (rfx1 + rfx2);
 }
 
 /* ---------------------------------------------------------------------- */
 
 double PairComb::yasu_char(double *qf_fix, int &igroup)
 {
   int i,j,ii,jj,jnum,itag,jtag;
   int itype,jtype,iparam_i,iparam_ij;
   double xtmp,ytmp,ztmp;
   double rsq1,delr1[3];
   int *ilist,*jlist,*numneigh,**firstneigh;
   double iq,jq,fqi,fqj,fqij,fqjj;
   double potal,fac11,fac11e,sr1,sr2,sr3;
   int mr1,mr2,mr3,inty,nj;
 
 
   double **x = atom->x;
   double *q = atom->q;
   int *type = atom->type;
   int *tag = atom->tag;
 
   int inum = list->inum;
   ilist = list->ilist;
   numneigh = list->numneigh;
   firstneigh = list->firstneigh;
 
   int *mask = atom->mask;
   int groupbit = group->bitmask[igroup];
 
   qf = qf_fix;
   for (ii = 0; ii < inum; ii++) {
     i = ilist[ii];
     if (mask[i] & groupbit)
       qf[i] = 0.0;
   }
 
   // communicating charge force to all nodes, first forward then reverse
 
   comm->forward_comm_pair(this);
 
   // self energy correction term: potal
 
   potal_calc(potal,fac11,fac11e);
 
   // loop over full neighbor list of my atoms
 
   fqi = fqj = fqij = fqjj = 0.0;
 
   for (ii = 0; ii < inum; ii ++) {
     i = ilist[ii];
     itag = tag[i];
     nj = 0;
     if (mask[i] & groupbit) {
       itype = map[type[i]];
       xtmp = x[i][0];
       ytmp = x[i][1];
       ztmp = x[i][2];
       iq = q[i];
       iparam_i = elem2param[itype][itype][itype];
 
       // charge force from self energy
 
       fqi = qfo_self(&params[iparam_i],iq,potal);
 
       // two-body interactions
 
       jlist = firstneigh[i];
       jnum = numneigh[i];
 
       for (jj = 0; jj < jnum; jj++) {
         j = jlist[jj];
         j &= NEIGHMASK;
         jtag = tag[j];
 
         if (itag > jtag) {
           if ((itag+jtag) % 2 == 0) continue;
         } else if (itag < jtag) {
           if ((itag+jtag) % 2 == 1) continue;
         } else {
           if (x[j][2] < x[i][2]) continue;
           if (x[j][2] == ztmp && x[j][1] < ytmp) continue;
           if (x[j][2] == ztmp && x[j][1] == ytmp && x[j][0] < xtmp) continue;
         }
 
         jtype = map[type[j]];
         jq = q[j];
 
         delr1[0] = x[j][0] - xtmp;
         delr1[1] = x[j][1] - ytmp;
         delr1[2] = x[j][2] - ztmp;
         rsq1 = vec3_dot(delr1,delr1);
 
         iparam_ij = elem2param[itype][jtype][jtype];
 
         // long range q-dependent
 
         if (rsq1 > params[iparam_ij].lcutsq) continue;
 
         inty = intype[itype][jtype];
 
         // polynomial three-point interpolation
 
         tri_point(rsq1,mr1,mr2,mr3,sr1,sr2,sr3,itype);
 
         // 1/r charge forces
 
         qfo_direct(inty,mr1,mr2,mr3,rsq1,sr1,sr2,sr3,fac11e,fqij);
         fqi += jq * fqij;  qf[j] += iq * fqij;
 
         // field correction to self energy and charge force
 
         qfo_field(&params[iparam_ij],rsq1,iq,jq,fqij,fqjj);
         fqi += fqij;
         qf[j] += fqjj;
       }
 
         // three-body interactions
 
       for (jj = 0; jj < jnum; jj++) {
         j = jlist[jj];
         j &= NEIGHMASK;
         jtype = map[type[j]];
         jq = q[j];
 
         delr1[0] = x[j][0] - xtmp;
         delr1[1] = x[j][1] - ytmp;
         delr1[2] = x[j][2] - ztmp;
         rsq1 = vec3_dot(delr1,delr1);
 
         iparam_ij = elem2param[itype][jtype][jtype];
 
         if (rsq1 > params[iparam_ij].cutsq) continue;
         nj ++;
 
         // charge force in Aij and Bij
 
         qfo_short(&params[iparam_ij],i,nj,rsq1,iq,jq,fqij,fqjj);
         fqi += fqij;  qf[j] += fqjj;
       }
       qf[i] += fqi;
     }
   }
 
   comm->reverse_comm_pair(this);
 
   // sum charge force on each node and return it
 
   double eneg = 0.0;
   for (ii = 0; ii < inum; ii++) {
     i = ilist[ii];
     if (mask[i] & groupbit)
       eneg += qf[i];
   }
   double enegtot;
   MPI_Allreduce(&eneg,&enegtot,1,MPI_DOUBLE,MPI_SUM,world);
   return enegtot;
 }
 
 /* ---------------------------------------------------------------------- */
 
 double PairComb::qfo_self(Param *param, double qi, double selfpot)
 {
  double self_d,cmin,cmax,qmin,qmax;
  double s1 = param->chi;
  double s2 = param->dj;
  double s3 = param->dk;
  double s4 = param->dl;
  double s5 = param->dm;
 
  self_d = 0.0;
  qmin = param->QL1*0.90;
  qmax = param->QU1*0.90;
  if (qmax > 4.50 ) qmax = -0.70;
  cmin = cmax = 1000.0;
 
  self_d = s1+qi*(2.0*(s2+selfpot)+qi*(3.0*s3+qi*(4.0*s4+qi*qi*6.0*s5)));
 
  if (qi < qmin) {
    // char str[128];
    // sprintf(str,"Pair COMB charge %.10f with force %.10f hit min barrier",
    // qi,self_d);
    // error->warning(FLERR,str,0);
    self_d += 4.0 * cmin * pow((qi-qmin),3.0);
  }
  if (qi > qmax) {
    // char str[128];
    // sprintf(str,"Pair COMB charge %.10f with force %.10f hit max barrier",
    //           qi,self_d);
    // error->warning(FLERR,str,0);
    self_d += 4.0 * cmax * pow((qi-qmax),3.0);
  }
 
  return self_d;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void PairComb::qfo_direct(int inty, int mr1, int mr2, int mr3,
                           double rsq, double sr1, double sr2,
                           double sr3, double fac11e, double &fqij)
 {
  double r, erfcc, fafbn1, vm, esucon;
 
  r = sqrt(rsq);
  esucon=force->qqr2e;
 
  // 1/r force (wrt q)
 
  erfcc = sr1*erpaw[mr1][0]   + sr2*erpaw[mr2][0]   + sr3*erpaw[mr3][0];
  fafbn1= sr1*fafb[mr1][inty] + sr2*fafb[mr2][inty] + sr3*fafb[mr3][inty];
  vm = (erfcc/r * esucon - fac11e);
  fqij = 1.0 * (vm+esucon*fafbn1);
 }
 
 /* ---------------------------------------------------------------------- */
 
 void PairComb::qfo_field(Param *param, double rsq,double iq,double jq,
                          double &fqij, double &fqjj)
 {
  double r,r5,r6,rc,rc5,rc6;
  double cmi1,cmi2,cmj1,cmj2,rf5;
 
  fqij = fqjj = 0.0;
  r  = sqrt(rsq);
  r5 = r*r*r*r*r;
  r6 = r5 * r;
  rc = param->lcut;
  rc5 = rc*rc*rc*rc*rc;
  rc6 = rc5 * rc;
  cmi1 = param->cmn1;
  cmi2 = param->cmn2;
  cmj1 = param->cml1;
  cmj2 = param->cml2;
  rf5 = 1.0/r5 - 1.0/rc5 + 5.0*(r-rc)/rc6;
 
  // field correction charge force
 
  fqij = 1.0 * rf5 * (cmj1 + 2.0 * iq * cmj2);
  fqjj = 1.0 * rf5 * (cmi1 + 2.0 * jq * cmi2);
 }
 
 /* ---------------------------------------------------------------------- */
 
 void PairComb::qfo_short(Param *param, int i, int j, double rsq,
                          double iq, double jq, double &fqij, double &fqjj)
 {
   double r,tmp_fc,tmp_fc_d,tmp_exp1,tmp_exp2;
   double bigA,Asi,Asj,vrcs;
   double romi = param->addrep,rrcs = param->bigr + param->bigd;
   double qi,qj,Di,Dj,bigB,Bsi,Bsj;
   double QUchi,QOchi,QUchj,QOchj,YYDiqp,YYDjqp;
   double YYAsiqp,YYAsjqp,YYBsiqp,YYBsjqp;
   double caj,cbj,bij,cfqr,cfqs;
   double romie = param->romiga;
   double romib = param->romigb;
   double ca1,ca2,ca3,ca4;
   double rslp,rslp2,rslp4,arr1,arr2,fc2j,fc3j,fcp2j,fcp3j;
 
   qi = iq; qj = jq; r = sqrt(rsq);
   Di = Dj = Asi = Asj = bigA = Bsi = Bsj = bigB = 0.0;
   QUchi = QOchi = QUchj = QOchj = YYDiqp = YYDjqp =0.0;
   YYAsiqp = YYAsjqp = YYBsiqp = YYBsjqp = 0.0;
   caj = cbj = vrcs = cfqr = cfqs = 0.0;
 
   tmp_fc = comb_fc(r,param);
   tmp_fc_d = comb_fc_d(r,param);
   tmp_exp1 = exp(-param->rlm1 * r);
   tmp_exp2 = exp(-param->rlm2 * r);
   bij = bbij[i][j]; //comb_bij(zeta_ij,param);
 
   arr1 = 2.22850; arr2 = 1.89350;
   fc2j = comb_fc2(r);
   fc3j = comb_fc3(r);
   fcp2j = comb_fc2_d(r);
   fcp3j = comb_fc3_d(r);
 
   vrcs = 0.0;
   if (romi > 0.0) {
     if (!cor_flag) vrcs = romi * pow((1.0-r/rrcs),2.0);
     else if (cor_flag) {
       rslp = ((arr1-r)/(arr1-arr2));
       rslp2 = rslp * rslp; rslp4 = rslp2 * rslp2;
       vrcs = fc2j * fc3j * romi * ((50.0*rslp4-30.0*rslp2+4.50))/8.0;
     }
   }
 
   Di = param->DU1 + pow(fabs(param->bD1*(param->QU1-qi)),param->nD1);
   Dj = param->DU2 + pow(fabs(param->bD2*(param->QU2-qj)),param->nD2);
 
   Asi = param->biga1 * exp(param->lam11*Di);
   Asj = param->biga2 * exp(param->lam12*Dj);
   Bsi = param->bigb1 * exp(param->lam21*Di)*
     (param->aB1-fabs(pow(param->bB1*(qi-param->Qo1),10.0)));
   Bsj = param->bigb2 * exp(param->lam22*Dj)*
     (param->aB2-fabs(pow(param->bB2*(qj-param->Qo2),10.0)));
 
   QUchi = (param->QU1-qi)*param->bD1;
   QUchj = (param->QU2-qj)*param->bD2;
   QOchi = (qi-param->Qo1)*param->bB1;
   QOchj = (qj-param->Qo2)*param->bB2;
 
   if (QUchi == 0.0) YYDiqp = 0.0;
   else YYDiqp = -param->nD1 * QUchi * param->bD1 *
          pow(fabs(QUchi),(param->nD1-2.0));
 
   if (QUchj == 0.0) YYDjqp = 0.0;
   else YYDjqp = -param->nD2 * QUchj * param->bD2 *
          pow(fabs(QUchj),(param->nD2-2.0));
 
   YYAsiqp = Asi * param->lam11 * YYDiqp;
   YYAsjqp = Asj * param->lam12 * YYDjqp;
 
   if (QOchi == 0.0)
     YYBsiqp=Bsi*param->lam21*YYDiqp;
   else
     YYBsiqp=Bsi*param->lam21*YYDiqp-param->bigb1*exp(param->lam21*Di)*
       10.0*QOchi*param->bB1*pow(fabs(QOchi),(10.0-2.0));
 
   if (QOchj == 0.0)
     YYBsjqp=Bsj*param->lam22*YYDjqp;
   else
     YYBsjqp=Bsj*param->lam22*YYDjqp-param->bigb2*exp(param->lam22*Dj)*
       10.0*QOchj*param->bB2*pow(fabs(QOchj),(10.0-2.0));
 
   if (Asi > 0.0 && Asj > 0.0) caj = 1.0/(2.0*sqrt(Asi*Asj)) * romie;
   else caj = 0.0;
 
   if (Bsi > 0.0 && Bsj > 0.0) cbj = 1.0/(2.0*sqrt(Bsi*Bsj)) * romib ;
   else cbj = 0.0;
 
   cfqr =  0.50 * tmp_fc * (1.0 + vrcs); // 0.5 b/c full atom loop
   cfqs = -0.50 * tmp_fc *  bij;
 
   ca1 = Asj * caj * YYAsiqp;
   ca2 = Bsj * cbj * YYBsiqp;
   ca3 = Asi * caj * YYAsjqp;
   ca4 = Bsi * cbj * YYBsjqp;
 
   fqij  = cfqr * tmp_exp1 * ca1;
   fqij += cfqs * tmp_exp2 * ca2;
   fqjj  = cfqr * tmp_exp1 * ca3;
   fqjj += cfqs * tmp_exp2 * ca4;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void PairComb::Over_cor(Param *param, double rsq1, int NCoi,
                         double &Eov, double &Fov)
 {
   double ECo,BCo,tmp_fc,tmp_fc_d;
   double r = sqrt(rsq1);
   int NCon = NCoi - 7;
 
   tmp_fc = comb_fc(r,param);
   tmp_fc_d = comb_fc(r,param);
   Eov = 0.0; Fov = 0.0;
   ECo = param->hfocor;
   BCo = 0.1;
 
   if (NCon >= 0.20) {
     Eov = tmp_fc * ECo * NCon/(1.0+exp(BCo*NCon));
     Fov = -(tmp_fc_d*Eov + tmp_fc*ECo/(1.0+exp(BCo*NCon)) -
             (tmp_fc*ECo*NCon*BCo*exp(BCo*NCon)) /
             ((1.0+exp(BCo*NCon))*(1.0+exp(BCo*NCon))));
     Fov /= r;
   }
 }
 
 /* ---------------------------------------------------------------------- */
 
 int PairComb::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++] = qf[j];
   }
   return 1;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void PairComb::unpack_comm(int n, int first, double *buf)
 {
   int i,m,last;
 
   m = 0;
   last = first + n ;
   for (i = first; i < last; i++) qf[i] = buf[m++];
 }
 
 /* ---------------------------------------------------------------------- */
 
 int PairComb::pack_reverse_comm(int n, int first, double *buf)
 {
   int i,m,last;
 
   m = 0;
   last = first + n;
   for (i = first; i < last; i++) buf[m++] = qf[i];
   return 1;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void PairComb::unpack_reverse_comm(int n, int *list, double *buf)
 {
   int i,j,m;
 
   m = 0;
   for (i = 0; i < n; i++) {
     j = list[i];
     qf[j] += buf[m++];
   }
 }
 
-/* ----------------------------------------------------------------------
-   memory usage of local atom-based arrays
-------------------------------------------------------------------------- */
-
-double PairComb::memory_usage()
-{
-  double bytes = maxeatom * sizeof(double);
-  bytes += maxvatom*6 * sizeof(double);
-  bytes += nmax * sizeof(int);
-  bytes += MAXNEIGH * nmax * sizeof(int);
-  return bytes;
-}
 /* ---------------------------------------------------------------------- */
 
 void PairComb::Short_neigh()
 {
   int nj,itype,jtype,iparam_ij;
   int inum,jnum,i,j,ii,jj;
   int *neighptrj,*ilist,*jlist,*numneigh;
   int **firstneigh;
   double xtmp,ytmp,ztmp,rr,rsq,delrj[3];
 
   double **x = atom->x;
   int *type  = atom->type;
   int nlocal = atom->nlocal;
   int ntype = atom->ntypes;
 
   if (atom->nmax > nmax) {
     memory->sfree(sht_first);
     nmax = atom->nmax;
     sht_first = (int **) memory->smalloc(nmax*sizeof(int *),
                                          "pair:sht_first");
     memory->grow(sht_num,nmax,"pair:sht_num");
     memory->grow(NCo,nmax,"pair:NCo");
     memory->grow(bbij,nmax,MAXNEIGH,"pair:bbij");
   }
 
   inum = list->inum;
   ilist = list->ilist;
   numneigh = list->numneigh;
   firstneigh = list->firstneigh;
-  int npntj = 0;
-  int npage = 0;
+
+  // create Comb neighbor list
+
+  ipage->reset();
 
   for (ii = 0; ii < inum; ii++) {
     i = ilist[ii];
     itype = type[i];
 
-    if (pgsize - npntj < oneatom) {
-      npntj = 0;
-      npage++;
-      if (npage == maxpage) add_pages();
-    }
-
     nj = 0;
-    neighptrj = &pages[npage][npntj];
+    neighptrj = ipage->vget();
 
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     jlist = firstneigh[i];
     jnum = numneigh[i];
 
     for (jj = 0; jj < jnum; jj++) {
       j = jlist[jj];
       j &= NEIGHMASK;
       jtype = type[j];
 
       delrj[0] = xtmp - x[j][0];
       delrj[1] = ytmp - x[j][1];
       delrj[2] = ztmp - x[j][2];
       rsq = vec3_dot(delrj,delrj);
 
       if (rsq > cutmin) continue;
       neighptrj[nj++] = j;
     }
 
     sht_first[i] = neighptrj;
     sht_num[i] = nj;
-    npntj += nj;
+    ipage->vgot(nj);
+    if (ipage->status())
+      error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
 }
 
-/* ---------------------------------------------------------------------- */
+/* ----------------------------------------------------------------------
+   memory usage of local atom-based arrays
+------------------------------------------------------------------------- */
 
-void PairComb::add_pages(int howmany)
+double PairComb::memory_usage()
 {
-  int toppage = maxpage;
-  maxpage += howmany*PGDELTA;
+  double bytes = maxeatom * sizeof(double);
+  bytes += maxvatom*6 * sizeof(double);
+  bytes += nmax * sizeof(int);
+  bytes += nmax * sizeof(int *);
+
+  for (int i=0; i < comm->nthreads; ++i)
+    bytes += ipage[i].size();
 
-  pages = (int **)
-    memory->srealloc(pages,maxpage*sizeof(int *),"pair:pages");
-  for (int i = toppage; i < maxpage; i++)
-    memory->create(pages[i],pgsize,"pair:pages[i]");
+  bytes += nmax * sizeof(int);
+  bytes += MAXNEIGH*nmax * sizeof(double);
+  return bytes;
 }
diff --git a/src/MANYBODY/pair_comb.h b/src/MANYBODY/pair_comb.h
index 3131c95b1..cd3947a3d 100644
--- a/src/MANYBODY/pair_comb.h
+++ b/src/MANYBODY/pair_comb.h
@@ -1,247 +1,248 @@
 /* ----------------------------------------------------------------------
    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(comb,PairComb)
 
 #else
 
 #ifndef LMP_PAIR_COMB_H
 #define LMP_PAIR_COMB_H
 
 #include "pair.h"
+#include "my_page.h"
 
 namespace LAMMPS_NS {
 
 class PairComb : public Pair {
  public:
   PairComb(class LAMMPS *);
   virtual ~PairComb();
   virtual void compute(int, int);
   void settings(int, char **);
   void coeff(int, char **);
   void init_style();
   double init_one(int, int);
   double memory_usage();
 
   virtual double yasu_char(double *, int &);
 
  protected:
   struct Param {
     double lam11,lam12,lam21,lam22;
     double c,d,h;
     double gamma,powerm;
     double powern,beta;
     double biga1,biga2,bigb1,bigb2;
     double bigd,bigr;
     double cut,cutsq;
     double c1,c2,c3,c4;
     double plp1,plp3,plp6,a123,aconf;
     double rlm1,rlm2;
     double romiga,romigb,romigc,romigd,addrep;
     double QU1,QL1,DU1,DL1,Qo1,dQ1,aB1,bB1,nD1,bD1;
     double QU2,QL2,DU2,DL2,Qo2,dQ2,aB2,bB2,nD2,bD2;
     double chi,dj,dk,dl,dm,esm1,esm2,cmn1,cmn2,cml1,cml2;
     double coulcut, lcut, lcutsq, hfocor;
     int ielement,jelement,kelement;
     int powermint;
   };
 
   double cutmax;                // max cutoff for all elements
   int nelements;                // # of unique elements
   char **elements;              // names of unique elements
   int ***elem2param;            // mapping from element triplets to parameters
   int *map;                     // mapping from atom types to elements
   int nparams;                  // # of stored parameter sets
   int maxparam;                 // max # of parameter sets
   double precision;
   Param *params;                // parameter set for an I-J-K interaction
 
   int nmax;
   double *qf;
 
   double *esm, **fafb, **dfafb, **ddfafb, **phin, **dphin, **erpaw;
   double *charge;
   int **intype, *typeno;
   int *NCo, cor_flag, cuo_flag, cuo_flag1, cuo_flag2;
   double **bbij;
 
+  int pgsize;                      // size of neighbor page
+  int oneatom;                     // max # of neighbors for one atom
+  int *sht_num,**sht_first;        // short-range neighbor list
+  MyPage<int> *ipage;              // neighbor list pages
+  double cutmin;
+
   void allocate();
   virtual void read_file(char *);
   void setup();
   virtual void repulsive(Param *, double, double &, int,
                          double &, double, double);
   double zeta(Param *, double, double, double *, double *);
   void force_zeta(Param *, int, int, int, double, double, double, double,
                   double &, double &, double &);
   void attractive(Param *, double, double, double, double *, double *,
                   double *, double *, double *);
   double elp(Param *, double, double, double *, double *);
   void flp(Param *, double, double, double *, double *, double *,
            double *, double *);
   double comb_fc(double, Param *);
   double comb_fc_d(double, Param *);
   double comb_fc2(double);
   double comb_fc2_d(double);
   double comb_fc3(double);
   double comb_fc3_d(double);
   virtual double comb_fa(double, Param *, double,double);
   virtual double comb_fa_d(double, Param *, double,double);
   double comb_bij(double, Param *);
   double comb_bij_d(double, Param *);
 
   inline double comb_gijk(const double costheta,
                           const Param * const param) const {
     const double comb_c = param->c * param->c;
     const double comb_d = param->d * param->d;
     const double hcth = param->h - costheta;
 
     return param->gamma*(1.0 + comb_c/comb_d - comb_c / (comb_d + hcth*hcth));
   }
 
   inline double comb_gijk_d(const double costheta,
                             const Param * const param) const {
     const double comb_c = param->c * param->c;
     const double comb_d = param->d * param->d;
     const double hcth = param->h - costheta;
     const double numerator = -2.0 * comb_c * hcth;
     const double denominator = 1.0/(comb_d + hcth*hcth);
     return param->gamma*numerator*denominator*denominator;
   }
 
   void comb_zetaterm_d(double, double *, double, double *, double,
                                double *, double *, double *, Param *);
   void costheta_d(double *, double, double *, double,
                   double *, double *, double *);
   double self(Param *, double, double);
   void sm_table();
   void potal_calc(double &, double &, double &);
   void tri_point(double, int &, int &, int &, double &, double &,
                  double &, int &);
   void direct(int,int,int,int,double,double,double,double,double,double,
         double,double,double,double &,double &);
   void field(Param *,double,double,double,double &,double &);
   double qfo_self(Param *, double, double);
   void qfo_short(Param *, int, int, double, double, double,
                   double &, double &);
   void qfo_direct (int, int, int, int, double, double, double, double,
         double, double &);
   void qfo_field(Param *, double,double ,double ,double &, double &);
   void qsolve(double *);
   void Over_cor(Param *, double, int, double &, double &);
   int pack_reverse_comm(int, int, double *);
   void unpack_reverse_comm(int, int *, double *);
   int pack_comm(int , int *, double *, int, int *);
   void unpack_comm(int , int , double *);
 
-  // short range neighbor list
-
-  void add_pages(int howmany = 1);
   void Short_neigh();
-  int maxpage, pgsize, oneatom, **pages;
-  int *sht_num, **sht_first;        // short-range neighbor list
-  double cutmin;
 
   // vector functions, inline for efficiency
 
   inline double vec3_dot(const double x[3], const double y[3]) const {
     return x[0]*y[0] + x[1]*y[1] + x[2]*y[2];
   }
 
   inline void vec3_add(const double x[3], const double y[3],
                        double * const z) const {
     z[0] = x[0]+y[0];  z[1] = x[1]+y[1];  z[2] = x[2]+y[2];
   }
 
   inline void vec3_scale(const double k, const double x[3],
                          double y[3]) const {
     y[0] = k*x[0];  y[1] = k*x[1];  y[2] = k*x[2];
   }
 
   inline void vec3_scaleadd(const double k, const double x[3],
                             const double y[3], double * const z) const {
     z[0] = k*x[0]+y[0];
     z[1] = k*x[1]+y[1];
     z[2] = k*x[2]+y[2];
   }
 };
 
 }
 
 #endif
 #endif
 
 /* ERROR/WARNING messages:
 
 E: Illegal ... command
 
 Self-explanatory.  Check the input script syntax and compare to the
 documentation for the command.  You can use -echo screen as a
 command-line option when running LAMMPS to see the offending line.
 
 E: Incorrect args for pair coefficients
 
 Self-explanatory.  Check the input script or data file.
 
 E: Pair style COMB requires atom IDs
 
 This is a requirement to use the AIREBO potential.
 
 E: Pair style COMB requires newton pair on
 
 See the newton command.  This is a restriction to use the COMB
 potential.
 
 E: Pair style COMB requires atom attribute q
 
 Self-explanatory.
 
 E: All pair coeffs are not set
 
 All pair coefficients must be set in the data file or by the
 pair_coeff command before running a simulation.
 
 E: Cannot open COMB potential file %s
 
 The specified COMB potential file cannot be opened.  Check that the
 path and name are correct.
 
 E: Incorrect format in COMB potential file
 
 Incorrect number of words per line in the potential file.
 
 E: Illegal COMB parameter
 
 One or more of the coefficients defined in the potential file is
 invalid.
 
 E: Potential file has duplicate entry
 
 The potential file for a SW or Tersoff potential has more than
 one entry for the same 3 ordered elements.
 
 E: Potential file is missing an entry
 
 The potential file for a SW or Tersoff potential does not have a
 needed entry.
 
 W: Pair COMB charge %.10f with force %.10f hit min barrier
 
 Something is possibly wrong with your model.
 
 W: Pair COMB charge %.10f with force %.10f hit max barrier
 
 Something is possibly wrong with your model.
 
 */
diff --git a/src/MANYBODY/pair_lcbop.cpp b/src/MANYBODY/pair_lcbop.cpp
index 5e7c6974c..091a15ace 100644
--- a/src/MANYBODY/pair_lcbop.cpp
+++ b/src/MANYBODY/pair_lcbop.cpp
@@ -1,1297 +1,1289 @@
 /* ----------------------------------------------------------------------
    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: Dominik Wójt (Wroclaw University of Technology)
      based on pair_airebo by Ase Henry (MIT)
 ------------------------------------------------------------------------- */
 
 #include "math.h"
 #include "stdio.h"
 #include "stdlib.h"
 #include "string.h"
 #include "mpi.h"
 #include "pair_lcbop.h"
 #include "atom.h"
 #include "neighbor.h"
 #include "neigh_request.h"
 #include "force.h"
 #include "comm.h"
 #include "neighbor.h"
 #include "neigh_list.h"
 #include "neigh_request.h"
+#include "my_page.h"
 #include "math_const.h"
 #include "memory.h"
 #include "error.h"
 
 using namespace LAMMPS_NS;
 using namespace MathConst;
 
 #define MAXLINE 1024
 #define TOL 1.0e-9
 #define PGDELTA 1
 
 /* ---------------------------------------------------------------------- */
 
 PairLCBOP::PairLCBOP(LAMMPS *lmp) : Pair(lmp) {
   single_enable = 0;
   one_coeff = 1;
   manybody_flag = 1;
   ghostneigh = 1;
 
   maxlocal = 0;
   SR_numneigh = NULL;
   SR_firstneigh = NULL;
-  maxpage = 0;
-  pages = NULL;
+  ipage = NULL;
+  pgsize = oneatom = 0;
+
   N = NULL;
   M = NULL;
 }
 
 /* ----------------------------------------------------------------------
    check if allocated, since class can be destructed when incomplete
 ------------------------------------------------------------------------- */
 
-PairLCBOP::~PairLCBOP() {
+PairLCBOP::~PairLCBOP()
+{
   memory->destroy(SR_numneigh);
   memory->sfree(SR_firstneigh);
-  for (int i = 0; i < maxpage; i++) memory->destroy(pages[i]);
-  memory->sfree(pages);
+  delete[] ipage;
   memory->destroy(N);
   memory->destroy(M);
 
   if (allocated) {
     memory->destroy(setflag);
     memory->destroy(cutsq);
     memory->destroy(cutghost);
 
     delete [] map;
   }
 }
 
 /* ---------------------------------------------------------------------- */
 
 void PairLCBOP::compute(int eflag, int vflag)
 {
   if (eflag || vflag) ev_setup(eflag,vflag);
   else evflag = vflag_fdotr = vflag_atom = 0;
 
   SR_neigh();
   FSR(eflag,vflag);
   FLR(eflag,vflag);
 
   if (vflag_fdotr) virial_fdotr_compute();
 }
 
 /* ----------------------------------------------------------------------
    allocate all arrays
 ------------------------------------------------------------------------- */
 
 void PairLCBOP::allocate()
 {
   allocated = 1;
   int n = atom->ntypes;
 
   memory->create(setflag,n+1,n+1,"pair:setflag");
   for (int i = 1; i <= n; i++)
     for (int j = i; j <= n; j++)
       setflag[i][j] = 0;
 
   memory->create(cutsq,n+1,n+1,"pair:cutsq");
   memory->create(cutghost,n+1,n+1,"pair:cutghost");
 
   map = new int[n+1];
 }
 
 /* ----------------------------------------------------------------------
    global settings
 ------------------------------------------------------------------------- */
 
 void PairLCBOP::settings(int narg, char **arg) {
   if( narg != 0 ) error->all(FLERR,"Illegal pair_style command");
 }
 
 /* ----------------------------------------------------------------------
    set coeffs for one or more type pairs
 ------------------------------------------------------------------------- */
 
 void PairLCBOP::coeff(int narg, char **arg)
 {
   if (!allocated) allocate();
 
   if (narg != 3 + atom->ntypes)
     error->all(FLERR,"Incorrect args for pair coefficients");
 
   // insure I,J args are * *
 
   if (strcmp(arg[0],"*") != 0 || strcmp(arg[1],"*") != 0)
     error->all(FLERR,"Incorrect args for pair coefficients");
 
   // read args that map atom types to C and NULL
   // map[i] = which element (0 for C) the Ith atom type is, -1 if NULL
 
   for (int i = 3; i < narg; i++) {
     if (strcmp(arg[i],"NULL") == 0) {
       map[i-2] = -1;
     } else if (strcmp(arg[i],"C") == 0) {
       map[i-2] = 0;
     } else error->all(FLERR,"Incorrect args for pair coefficients");
   }
 
   // read potential file and initialize fitting splines
 
   read_file(arg[2]);
   spline_init();
 
   // clear setflag since coeff() called once with I,J = * *
 
   int n = atom->ntypes;
   for (int i = 1; i <= n; i++)
     for (int j = i; j <= n; j++)
       setflag[i][j] = 0;
 
   // set setflag i,j for type pairs where both are mapped to elements
 
   int count = 0;
   for (int i = 1; i <= n; i++)
     for (int j = i; j <= n; j++)
       if (map[i] >= 0 && map[j] >= 0) {
         setflag[i][j] = 1;
         count++;
       }
 
   if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
 }
 
 /* ----------------------------------------------------------------------
    init specific to this pair style
 ------------------------------------------------------------------------- */
 
 void PairLCBOP::init_style()
 {
   if (atom->tag_enable == 0)
     error->all(FLERR,"Pair style LCBOP requires atom IDs");
   if (force->newton_pair == 0)
     error->all(FLERR,"Pair style LCBOP requires newton pair on");
 
   // need a full neighbor list, including neighbors of ghosts
 
   int irequest = neighbor->request(this);
   neighbor->requests[irequest]->half = 0;
   neighbor->requests[irequest]->full = 1;
   neighbor->requests[irequest]->ghost = 1;
 
-  // local SR neighbor list memory
+  // local SR neighbor list
+  // create pages if first time or if neighbor pgsize/oneatom has changed
+
+  int create = 0;
+  if (ipage == NULL) create = 1;
+  if (pgsize != neighbor->pgsize) create = 1;
+  if (oneatom != neighbor->oneatom) create = 1;
+
+  if (create) {
+    pgsize = neighbor->pgsize;
+    oneatom = neighbor->oneatom;
 
-  pgsize = neighbor->pgsize;
-  oneatom = neighbor->oneatom;
-  if (maxpage == 0) add_pages();
+    delete[] ipage;
+    int nmypage = comm->nthreads;
+    ipage = new MyPage<int>[nmypage];
+    for (int i=0; i < nmypage; ++i)
+      ipage[i].init(oneatom,pgsize,PGDELTA);
+  }
 }
 
 /* ----------------------------------------------------------------------
    init for one type pair i,j and corresponding j,i
 ------------------------------------------------------------------------- */
 
 double PairLCBOP::init_one(int i, int j)
 {
   if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
 
   // cut3rebo = 3 SR distances
 
   cut3rebo = 3.0 * r_2;
 
   // cutmax = furthest distance from an owned atom
   //          at which another atom will feel force, i.e. the ghost cutoff
   // for SR term in potential:
   //   interaction = M-K-I-J-L-N with I = owned and J = ghost
   //   I to N is max distance = 3 SR distances
   // for V_LR term in potential:
   //   r_2_LR
   // cutghost = SR cutoff used in SR_neigh() for neighbors of ghosts
 
   double cutmax = MAX( cut3rebo,r_2_LR );
 
   cutghost[i][j] = r_2;
   cutLRsq = r_2_LR*r_2_LR;
 
   cutghost[j][i] = cutghost[i][j];
 
   r_2_sq = r_2*r_2;
 
   return cutmax;
 }
 
 /* ----------------------------------------------------------------------
    create SR neighbor list from main neighbor list
    SR neighbor list stores neighbors of ghost atoms
 ------------------------------------------------------------------------- */
 
 void PairLCBOP::SR_neigh()
 {
-  int i,j,ii,jj,n,
-    allnum,           // number of atoms(both local and ghost) neighbors are stored for
-    jnum;
+  int i,j,ii,jj,n,allnum,jnum;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq,dS;
   int *ilist,*jlist,*numneigh,**firstneigh;
   int *neighptr;
 
   double **x = atom->x;
   int nlocal = atom->nlocal;
   int nall = nlocal + atom->nghost;
 
   if (atom->nmax > maxlocal) {  // ensure ther is enough space
     maxlocal = atom->nmax;      // for atoms and ghosts allocated
     memory->destroy(SR_numneigh);
     memory->sfree(SR_firstneigh);
     memory->destroy(N);
     memory->destroy(M);
     memory->create(SR_numneigh,maxlocal,"LCBOP:numneigh");
     SR_firstneigh = (int **) memory->smalloc(maxlocal*sizeof(int *),
                            "LCBOP:firstneigh");
     memory->create(N,maxlocal,"LCBOP:N");
     memory->create(M,maxlocal,"LCBOP:M");
   }
 
   allnum = list->inum + list->gnum;
   ilist = list->ilist;
   numneigh = list->numneigh;
   firstneigh = list->firstneigh;
 
   // store all SR neighs of owned and ghost atoms
   // scan full neighbor list of I
 
-  int npage = 0;
-  int npnt = 0; // position in current page
+  ipage->reset();
 
   for (ii = 0; ii < allnum; ii++) {
     i = ilist[ii];
 
-    if (pgsize - npnt < oneatom) { // ensure at least oneatom space free at current page
-      npnt = 0;
-      npage++;
-      if (npage == maxpage) add_pages();
-    }
-    neighptr = &pages[npage][npnt];
     n = 0;
+    neighptr = ipage->vget();
 
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
     N[i] = 0.0;
     jlist = firstneigh[i];
     jnum = numneigh[i];
 
     for (jj = 0; jj < jnum; jj++) {
       j = jlist[jj];
       j &= NEIGHMASK;
       delx = xtmp - x[j][0];
       dely = ytmp - x[j][1];
       delz = ztmp - x[j][2];
       rsq = delx*delx + dely*dely + delz*delz;
 
       if (rsq < r_2_sq) {
         neighptr[n++] = j;
         N[i] += f_c(sqrt(rsq),r_1,r_2,&dS);
       }
     }
 
     SR_firstneigh[i] = neighptr;
     SR_numneigh[i] = n;
-    npnt += n;
-    if( npnt >= pgsize )
-      error->one(FLERR,
-                 "Neighbor list overflow, boost neigh_modify one or page");
+    ipage->vgot(n);
+    if (ipage->status())
+      error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
 
-
   // calculate M_i
+
   for (ii = 0; ii < allnum; ii++) {
     i = ilist[ii];
 
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
     M[i] = 0.0;
 
     jlist = SR_firstneigh[i];
     jnum = SR_numneigh[i];
 
     for (jj = 0; jj < jnum; jj++) {
       j = jlist[jj];
       delx = xtmp - x[j][0];
       dely = ytmp - x[j][1];
       delz = ztmp - x[j][2];
       rsq = delx*delx + dely*dely + delz*delz;
 
       if (rsq < r_2_sq) {
         double f_c_ij = f_c(sqrt(rsq),r_1,r_2,&dS);
         double Nji = N[j]-f_c_ij;
         // F(xij) = 1-f_c_LR(Nji, 2,3,&dummy)
         M[i] += f_c_ij * ( 1-f_c_LR(Nji, 2,3,&dS) );
       }
     }
   }
 }
 
 /* ----------------------------------------------------------------------
   Short range forces and energy
 ------------------------------------------------------------------------- */
 
 void PairLCBOP::FSR(int eflag, int vflag)
 {
   int i,j,jj,ii,inum,itag,jtag;
   double delx,dely,delz,fpair,xtmp,ytmp,ztmp;
   double r_sq,rijmag,f_c_ij,df_c_ij;
   double VR,dVRdi,VA,Bij,dVAdi,dVA;
   double d_f_c_ij,del[3];
   int *ilist,*SR_neighs;
 
   double **x = atom->x;
   double **f = atom->f;
   int *tag = atom->tag;
   int nlocal = atom->nlocal;
   int newton_pair = force->newton_pair;
 
   inum = list->inum;
   ilist = list->ilist;
 
   // two-body interactions from SR neighbor list, skip half of them
 
   for (ii = 0; ii < inum; ii++) {
     i = ilist[ii];
     itag = tag[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
     SR_neighs = SR_firstneigh[i];
 
     for (jj = 0; jj < SR_numneigh[i]; jj++) {
       j = SR_neighs[jj];
       jtag = tag[j];
 
       if (itag > jtag) {
         if ((itag+jtag) % 2 == 0) continue;
       } else if (itag < jtag) {
         if ((itag+jtag) % 2 == 1) continue;
       } else {
         if (x[j][2] < ztmp) continue;
         if (x[j][2] == ztmp && x[j][1] < ytmp) continue;
         if (x[j][2] == ztmp && x[j][1] == ytmp && x[j][0] < xtmp) continue;
       }
 
       delx = x[i][0] - x[j][0];
       dely = x[i][1] - x[j][1];
       delz = x[i][2] - x[j][2];
       r_sq = delx*delx + dely*dely + delz*delz;
       rijmag = sqrt(r_sq);
       f_c_ij = f_c( rijmag,r_1,r_2,&df_c_ij );
       if( f_c_ij <= TOL ) continue;
 
       VR = A*exp(-alpha*rijmag);
       dVRdi = -alpha*VR;
       dVRdi = dVRdi*f_c_ij + df_c_ij*VR; // VR -> VR * f_c_ij
       VR *= f_c_ij;
 
       VA = dVA = 0.0;
       {
         double term = B_1 * exp(-beta_1*rijmag);
         VA += term;
         dVA += -beta_1 * term;
         term = B_2 * exp(-beta_2*rijmag);
         VA += term;
         dVA += -beta_2 * term;
       }
       dVA = dVA*f_c_ij + df_c_ij*VA; // VA -> VA * f_c_ij
       VA *= f_c_ij;
       del[0] = delx;
       del[1] = dely;
       del[2] = delz;
       Bij = bondorder(i,j,del,rijmag,VA,f,vflag_atom);
       dVAdi = Bij*dVA;
 
       // F = (dVRdi+dVAdi)*(-grad rijmag)
       // grad_i rijmag =  \vec{rij} /rijmag
       // grad_j rijmag = -\vec{rij} /rijmag
       fpair = -(dVRdi-dVAdi) / rijmag;
       f[i][0] += delx*fpair;
       f[i][1] += dely*fpair;
       f[i][2] += delz*fpair;
       f[j][0] -= delx*fpair;
       f[j][1] -= dely*fpair;
       f[j][2] -= delz*fpair;
 
       double evdwl=0.0;
       if (eflag) evdwl = VR - Bij*VA;
       if (evflag) ev_tally(i,j,nlocal,newton_pair,
         evdwl,0.0,fpair,delx,dely,delz);
     }
   }
 }
 
 /* ----------------------------------------------------------------------
    compute long range forces and energy
 ------------------------------------------------------------------------- */
 
 void PairLCBOP::FLR(int eflag, int vflag)
 {
 
   int i,j,jj,m,ii,itag,jtag;
   double delx,dely,delz,fpair,xtmp,ytmp,ztmp;
   double r_sq,rijmag,f_c_ij,df_c_ij;
   double V,dVdi;
 
   double **x = atom->x;
   double **f = atom->f;
   int *tag = atom->tag;
   int nlocal = atom->nlocal;
   int newton_pair = force->newton_pair;
 
 
   int inum = list->inum;
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
 
   // two-body interactions from full neighbor list, skip half of them
 
   for (ii = 0; ii < inum; ii++) {
     i = ilist[ii];
     itag = tag[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
     int *neighs = firstneigh[i];
 
     for (jj = 0; jj < numneigh[i]; jj++) {
       j = neighs[jj];
       j &= NEIGHMASK;
       jtag = tag[j];
 
       if (itag > jtag) {
         if ((itag+jtag) % 2 == 0) continue;
       } else if (itag < jtag) {
         if ((itag+jtag) % 2 == 1) continue;
       } else {
         if (x[j][2] < ztmp) continue;
         if (x[j][2] == ztmp && x[j][1] < ytmp) continue;
         if (x[j][2] == ztmp && x[j][1] == ytmp && x[j][0] < xtmp) continue;
       }
 
       delx = x[i][0] - x[j][0];
       dely = x[i][1] - x[j][1];
       delz = x[i][2] - x[j][2];
       r_sq = delx*delx + dely*dely + delz*delz;
       rijmag = sqrt(r_sq);
       f_c_ij = 1-f_c( rijmag,r_1,r_2,&df_c_ij );
       df_c_ij = -df_c_ij;
       // derivative may be inherited from previous call, see f_c_LR definition
       f_c_ij *= f_c_LR( rijmag, r_1_LR, r_2_LR, &df_c_ij );
       if( f_c_ij <= TOL ) continue;
 
       V = dVdi = 0;
       if( rijmag<r_0 ) {
         double exp_part = exp( -lambda_1*(rijmag-r_0) );
         V = eps_1*( exp_part*exp_part - 2*exp_part) + v_1;
         dVdi = 2*eps_1*lambda_1*exp_part*( 1-exp_part );
       } else {
         double exp_part = exp( -lambda_2*(rijmag-r_0) );
         V = eps_2*( exp_part*exp_part - 2*exp_part) + v_2;
         dVdi = 2*eps_2*lambda_2*exp_part*( 1-exp_part );
       }
       dVdi = dVdi*f_c_ij + df_c_ij*V; // V -> V * f_c_ij
       V *= f_c_ij;
 
       // F = (dVdi)*(-grad rijmag)
       // grad_i rijmag =  \vec{rij} /rijmag
       // grad_j rijmag = -\vec{rij} /rijmag
       fpair = -dVdi / rijmag;
       f[i][0] += delx*fpair;
       f[i][1] += dely*fpair;
       f[i][2] += delz*fpair;
       f[j][0] -= delx*fpair;
       f[j][1] -= dely*fpair;
       f[j][2] -= delz*fpair;
 
       double evdwl=0.0;
       if (eflag) evdwl = V;
       if (evflag) ev_tally(i,j,nlocal,newton_pair,
         evdwl,0.0,fpair,delx,dely,delz);
     }
   }
 }
 
 /* ----------------------------------------------------------------------
    forces for Nij and Mij
 ------------------------------------------------------------------------- */
 
 void PairLCBOP::FNij( int i, int j, double factor, double **f, int vflag_atom ) {
   int atomi = i;
   int atomj = j;
   int *SR_neighs = SR_firstneigh[i];
   double **x = atom->x;
   for( int k=0; k<SR_numneigh[i]; k++ ) {
     int atomk = SR_neighs[k];
     if (atomk != atomj) {
       double rik[3];
       rik[0] = x[atomi][0]-x[atomk][0];
       rik[1] = x[atomi][1]-x[atomk][1];
       rik[2] = x[atomi][2]-x[atomk][2];
       double riksq = (rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2]);
       if( riksq > r_1*r_1 ) { // &&  riksq < r_2*r_2, if second condition not fulfilled neighbor would not be in the list
         double rikmag = sqrt(riksq);
         double df_c_ik;
         double f_c_ik = f_c( rikmag, r_1, r_2, &df_c_ik );
 
         // F = factor*df_c_ik*(-grad rikmag)
         // grad_i rikmag =  \vec{rik} /rikmag
         // grad_k rikmag = -\vec{rik} /rikmag
         double fpair = -factor*df_c_ik / rikmag;
         f[atomi][0] += rik[0]*fpair;
         f[atomi][1] += rik[1]*fpair;
         f[atomi][2] += rik[2]*fpair;
         f[atomk][0] -= rik[0]*fpair;
         f[atomk][1] -= rik[1]*fpair;
         f[atomk][2] -= rik[2]*fpair;
 
         if (vflag_atom) v_tally2(atomi,atomk,fpair,rik);
       }
     }
   }
 }
 
 /* ---------------------------------------------------------------------- */
 
 void PairLCBOP::FMij( int i, int j, double factor, double **f, int vflag_atom ) {
   int atomi = i;
   int atomj = j;
   int *SR_neighs = SR_firstneigh[i];
   double **x = atom->x;
   for( int k=0; k<SR_numneigh[i]; k++ ) {
     int atomk = SR_neighs[k];
     if (atomk != atomj) {
       double rik[3];
       rik[0] = x[atomi][0]-x[atomk][0];
       rik[1] = x[atomi][1]-x[atomk][1];
       rik[2] = x[atomi][2]-x[atomk][2];
       double rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2]));
       double df_c_ik;
       double f_c_ik = f_c( rikmag, r_1, r_2, &df_c_ik );
       double Nki = N[k]-(f_c_ik);
 //      double Mij = M[i] - f_c_ij*( 1-f_c(Nji, 2,3,&dummy) );
       double dF=0;
       double Fx = 1-f_c_LR(Nki, 2,3,&dF);
       dF = -dF;
 
       if( df_c_ik > TOL ) {
         double factor2 = factor*df_c_ik*Fx;
         // F = factor2*(-grad rikmag)
         // grad_i rikmag =  \vec{rik} /rikmag
         // grad_k rikmag = -\vec{rik} /rikmag
         double fpair = -factor2 / rikmag;
         f[atomi][0] += rik[0]*fpair;
         f[atomi][1] += rik[1]*fpair;
         f[atomi][2] += rik[2]*fpair;
         f[atomk][0] -= rik[0]*fpair;
         f[atomk][1] -= rik[1]*fpair;
         f[atomk][2] -= rik[2]*fpair;
         if (vflag_atom) v_tally2(atomi,atomk,fpair,rik);
       }
 
       if( dF > TOL ) {
         double factor2 = factor*f_c_ik*dF;
         FNij( atomk, atomi, factor2, f, vflag_atom );
       }
     }
   }
 }
 
 /* ----------------------------------------------------------------------
    Bij function
 ------------------------------------------------------------------------- */
 
 double PairLCBOP::bondorder(int i, int j, double rij[3],
     double rijmag, double VA,
     double **f, int vflag_atom)
 {
 
   double bij, bji;
   /* bij & bji */{
     double rji[3];
     rji[0] = -rij[0]; rji[1] = -rij[1]; rji[2] = -rij[2];
     bij = b(i,j,rij,rijmag,VA,f,vflag_atom);
     bji = b(j,i,rji,rijmag,VA,f,vflag_atom);
   }
 
   double Fij_conj;
   /* F_conj */{
     double dummy;
 
     double df_c_ij;
     double f_c_ij = f_c( rijmag, r_1, r_2, &df_c_ij );
     double Nij = MIN( 3, N[i]-(f_c_ij) );
     double Nji = MIN( 3, N[j]-(f_c_ij) );
 
     // F(xij) = 1-f_c(Nji, 2,3,&dummy)
     double Mij = M[i] - f_c_ij*( 1-f_c(Nji, 2,3,&dummy) );
     double Mji = M[j] - f_c_ij*( 1-f_c(Nij, 2,3,&dummy) );
     Mij = MIN( Mij, 3 );
     Mji = MIN( Mji, 3 );
 
     double Nij_el, dNij_el_dNij, dNij_el_dMij;
     double Nji_el, dNji_el_dNji, dNji_el_dMji;
     {
       double num_Nij_el = 4 - Mij;
       double num_Nji_el = 4 - Mji;
       double den_Nij_el = Nij + 1 - Mij;
       double den_Nji_el = Nji + 1 - Mji;
       Nij_el = num_Nij_el / den_Nij_el;
       Nji_el = num_Nji_el / den_Nji_el;
       dNij_el_dNij = -Nij_el/den_Nij_el;
       dNji_el_dNji = -Nji_el/den_Nji_el;
       dNij_el_dMij = ( -1 + Nij_el ) /den_Nij_el;
       dNji_el_dMji = ( -1 + Nji_el ) /den_Nji_el;
     }
 
     double Nconj;
     double dNconj_dNij;
     double dNconj_dNji;
     double dNconj_dNel;
     {
       double num_Nconj = ( Nij+1 )*( Nji+1 )*( Nij_el+Nji_el ) - 4*( Nij+Nji+2);
       double den_Nconj = Nij*( 3-Nij )*( Nji+1 ) + Nji*( 3-Nji )*( Nij+1 ) + eps;
       Nconj = num_Nconj / den_Nconj;
       if( Nconj <= 0 ) {
         Nconj = 0;
         dNconj_dNij = 0;
         dNconj_dNji = 0;
         dNconj_dNel = 0;
       } else if( Nconj >= 1 ) {
         Nconj = 1;
         dNconj_dNij = 0;
         dNconj_dNji = 0;
         dNconj_dNel = 0;
       } else {
         dNconj_dNij = (
             ( (Nji+1)*(Nij_el + Nji_el)-4)
             - Nconj*( (Nji+1)*(3-2*Nij) + Nji*(3-Nji) )
           ) /den_Nconj;
         dNconj_dNji = (
             ( (Nij+1)*(Nji_el + Nij_el)-4)
             - Nconj*( (Nij+1)*(3-2*Nji) + Nij*(3-Nij) )
           ) /den_Nconj;
         dNconj_dNel = (Nij+1)*(Nji+1) / den_Nconj;
       }
     }
 
     double dF_dNij, dF_dNji, dF_dNconj;
     Fij_conj = F_conj( Nij, Nji, Nconj, &dF_dNij, &dF_dNji, &dF_dNconj );
 
     /*forces for Nij*/
     if( 3-Nij > TOL ) {
       double factor = -VA*0.5*( dF_dNij + dF_dNconj*( dNconj_dNij + dNconj_dNel*dNij_el_dNij ) );
       FNij( i, j, factor, f, vflag_atom );
     }
     /*forces for Nji*/
     if( 3-Nji > TOL ) {
       double factor = -VA*0.5*( dF_dNji + dF_dNconj*( dNconj_dNji + dNconj_dNel*dNji_el_dNji ) );
       FNij( j, i, factor, f, vflag_atom );
     }
     /*forces for Mij*/
     if( 3-Mij > TOL ) {
       double factor = -VA*0.5*( dF_dNconj*dNconj_dNel*dNij_el_dMij );
       FMij( i, j, factor, f, vflag_atom );
     }
     if( 3-Mji > TOL ) {
       double factor = -VA*0.5*( dF_dNconj*dNconj_dNel*dNji_el_dMji );
       FMij( j, i, factor, f, vflag_atom );
     }
   }
 
 
   double Bij = 0.5*( bij + bji + Fij_conj );
   return Bij;
 }
 
 /* ----------------------------------------------------------------------
   bij function
 ------------------------------------------------------------------------- */
 
 double PairLCBOP::b(int i, int j, double rij[3],
                  double rijmag, double VA,
                  double **f, int vflag_atom) {
   int *SR_neighs = SR_firstneigh[i];
   double **x = atom->x;
   int atomi = i;
   int atomj = j;
 
   //calculate bij magnitude
   double bij = 1.0;
   for (int k = 0; k < SR_numneigh[i]; k++) {
     int atomk = SR_neighs[k];
     if (atomk != atomj) {
       double rik[3];
       rik[0] = x[atomi][0]-x[atomk][0];
       rik[1] = x[atomi][1]-x[atomk][1];
       rik[2] = x[atomi][2]-x[atomk][2];
       double rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2]));
       double delta_ijk = rijmag-rikmag;
       double dummy;
       double f_c_ik = f_c( rikmag, r_1, r_2, &dummy );
       double cos_ijk = ((rij[0]*rik[0])+(rij[1]*rik[1])+(rij[2]*rik[2]))
                 / (rijmag*rikmag);
       cos_ijk = MIN(cos_ijk,1.0);
       cos_ijk = MAX(cos_ijk,-1.0);
 
       double G = gSpline(cos_ijk,   &dummy);
       double H = hSpline(delta_ijk, &dummy);
       bij += (f_c_ik*G*H);
     }
   }
   bij = pow( bij, -delta );
 
   // bij forces
 
   for (int k = 0; k < SR_numneigh[i]; k++) {
     int atomk = SR_neighs[k];
     if (atomk != atomj) {
       double rik[3];
       rik[0] = x[atomi][0]-x[atomk][0];
       rik[1] = x[atomi][1]-x[atomk][1];
       rik[2] = x[atomi][2]-x[atomk][2];
       double rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2]));
       double delta_ijk = rijmag-rikmag;
       double df_c_ik;
       double f_c_ik = f_c( rikmag, r_1, r_2, &df_c_ik );
       double cos_ijk = ((rij[0]*rik[0])+(rij[1]*rik[1])+(rij[2]*rik[2]))
                 / (rijmag*rikmag);
       cos_ijk = MIN(cos_ijk,1.0);
       cos_ijk = MAX(cos_ijk,-1.0);
 
       double dcos_ijk_dri[3],dcos_ijk_drj[3],dcos_ijk_drk[3];
       dcos_ijk_drj[0] = -rik[0] / (rijmag*rikmag)
              + cos_ijk * rij[0] / (rijmag*rijmag);
       dcos_ijk_drj[1] = -rik[1] / (rijmag*rikmag)
              + cos_ijk * rij[1] / (rijmag*rijmag);
       dcos_ijk_drj[2] = -rik[2] / (rijmag*rikmag)
              + cos_ijk * rij[2] / (rijmag*rijmag);
 
       dcos_ijk_drk[0] = -rij[0] / (rijmag*rikmag)
              + cos_ijk * rik[0] / (rikmag*rikmag);
       dcos_ijk_drk[1] = -rij[1] / (rijmag*rikmag)
              + cos_ijk * rik[1] / (rikmag*rikmag);
       dcos_ijk_drk[2] = -rij[2] / (rijmag*rikmag)
              + cos_ijk * rik[2] / (rikmag*rikmag);
 
       dcos_ijk_dri[0] = -dcos_ijk_drk[0] - dcos_ijk_drj[0];
       dcos_ijk_dri[1] = -dcos_ijk_drk[1] - dcos_ijk_drj[1];
       dcos_ijk_dri[2] = -dcos_ijk_drk[2] - dcos_ijk_drj[2];
 
       double dG, dH;
       double G = gSpline( cos_ijk,   &dG );
       double H = hSpline( delta_ijk, &dH );
       double tmp = -VA*0.5*(-0.5*bij*bij*bij);
 
       double fi[3], fj[3], fk[3];
 
       double tmp2 = -tmp*df_c_ik*G*H/rikmag;
       // F = tmp*df_c_ik*G*H*(-grad rikmag)
       // grad_i rikmag =  \vec{rik} /rikmag
       // grad_k rikmag = -\vec{rik} /rikmag
       fi[0] =  tmp2*rik[0];
       fi[1] =  tmp2*rik[1];
       fi[2] =  tmp2*rik[2];
       fk[0] = -tmp2*rik[0];
       fk[1] = -tmp2*rik[1];
       fk[2] = -tmp2*rik[2];
 
 
       tmp2 = -tmp*f_c_ik*dG*H;
       // F = tmp*f_c_ik*dG*H*(-grad cos_ijk)
       // grad_i cos_ijk = dcos_ijk_dri
       // grad_j cos_ijk = dcos_ijk_drj
       // grad_k cos_ijk = dcos_ijk_drk
       fi[0] += tmp2*dcos_ijk_dri[0];
       fi[1] += tmp2*dcos_ijk_dri[1];
       fi[2] += tmp2*dcos_ijk_dri[2];
       fj[0] =  tmp2*dcos_ijk_drj[0];
       fj[1] =  tmp2*dcos_ijk_drj[1];
       fj[2] =  tmp2*dcos_ijk_drj[2];
       fk[0] += tmp2*dcos_ijk_drk[0];
       fk[1] += tmp2*dcos_ijk_drk[1];
       fk[2] += tmp2*dcos_ijk_drk[2];
 
       tmp2 = -tmp*f_c_ik*G*dH;
       // F = tmp*f_c_ik*G*dH*(-grad delta_ijk)
       // grad_i delta_ijk =  \vec{rij} /rijmag - \vec{rik} /rijmag
       // grad_j delta_ijk = -\vec{rij} /rijmag
       // grad_k delta_ijk =  \vec{rik} /rikmag
       fi[0] += tmp2*( rij[0]/rijmag - rik[0]/rikmag );
       fi[1] += tmp2*( rij[1]/rijmag - rik[1]/rikmag );
       fi[2] += tmp2*( rij[2]/rijmag - rik[2]/rikmag );
       fj[0] += tmp2*( -rij[0]/rijmag );
       fj[1] += tmp2*( -rij[1]/rijmag );
       fj[2] += tmp2*( -rij[2]/rijmag );
       fk[0] += tmp2*( rik[0]/rikmag );
       fk[1] += tmp2*( rik[1]/rikmag );
       fk[2] += tmp2*( rik[2]/rikmag );
 
       f[atomi][0] += fi[0]; f[atomi][1] += fi[1]; f[atomi][2] += fi[2];
       f[atomj][0] += fj[0]; f[atomj][1] += fj[1]; f[atomj][2] += fj[2];
       f[atomk][0] += fk[0]; f[atomk][1] += fk[1]; f[atomk][2] += fk[2];
 
       if (vflag_atom) {
         double rji[3], rki[3];
         rji[0] = -rij[0]; rji[1] = -rij[1]; rji[2] = -rij[2];
         rki[0] = -rik[0]; rki[1] = -rik[1]; rki[2] = -rik[2];
         v_tally3(atomi,atomj,atomk,fj,fk,rji,rki);
       }
     }
   }
 
   return bij;
 }
 
-/* ----------------------------------------------------------------------
-   add pages to SR neighbor list
-------------------------------------------------------------------------- */
-
-void PairLCBOP::add_pages(int howmany)
-{
-  int toppage = maxpage;
-  maxpage += howmany*PGDELTA;
-
-  pages = (int **)
-    memory->srealloc(pages,maxpage*sizeof(int *),"LCBOP:pages");
-  for (int i = toppage; i < maxpage; i++)
-    memory->create(pages[i],pgsize,"LCBOP:pages[i]");
-}
-
 /* ----------------------------------------------------------------------
    spline interpolation for G
 ------------------------------------------------------------------------- */
 
 void PairLCBOP::g_decompose_x( double x, size_t *field_idx, double *offset ) {
   size_t i=0;
   while( i<(6-1) && !( x<gX[i+1] ) )
     i++;
   *field_idx = i;
   *offset = ( x - gX[i] );
 }
 
 /* ---------------------------------------------------------------------- */
 
 double PairLCBOP::gSpline( double x, double *dgdc ) {
   size_t i;
   double x_n;
   g_decompose_x( x, &i, &x_n );
   double sum = 0;
   *dgdc = 0;
   double pow_x_n = 1.0;
   for( size_t j=0; j<5; j++ ) {
       sum += gC[j][i]*pow_x_n;
       *dgdc += gC[j+1][i]*(j+1)*pow_x_n;
       pow_x_n *= x_n;
   }
   sum += gC[5][i]*pow_x_n;
   return sum;
 }
 
 /* ---------------------------------------------------------------------- */
 
 double PairLCBOP::hSpline( double x, double *dhdx ) {
   if( x < -d ) {
       double z = kappa*( x+d );
       double y = pow(z, 10.0);
       double w = pow( 1+y, -0.1 );
       *dhdx = kappa*L*w/(1+y);
       return L*( 1 + z*w );
     }
     if( x > d ) {
       *dhdx = R_1;
       return R_0 + R_1*( x-d );
     }
 
       double result = 1 + C_1*x;
       *dhdx    = C_1*result;
     double pow_x = x*x;
       result  += 0.5*C_1*C_1*pow_x;
     pow_x *= x;// == x^3
       *dhdx   += 4*C_4*pow_x;
     pow_x *= x;// == x^4
       result  += C_4*pow_x;
     pow_x *= x;// == x^5
       *dhdx   += 6*C_6*pow_x;
     pow_x *= x;// == x^5
       result += C_6*pow_x;
     return result;
 }
 
 /* ---------------------------------------------------------------------- */
 
 double PairLCBOP::F_conj( double N_ij, double N_ji, double N_conj_ij, double *dFN_ij, double *dFN_ji, double *dFN_ij_conj ) {
   size_t N_ij_int         = MIN( static_cast<size_t>( floor( N_ij ) ), 2 ); // 2 is the highest number of field
   size_t N_ji_int         = MIN( static_cast<size_t>( floor( N_ji ) ), 2 ); // cast to suppress warning
   double x                = N_ij - N_ij_int;
   double y                = N_ji - N_ji_int;
   const TF_conj_field &f0 = F_conj_field[N_ij_int][N_ji_int][0];
   const TF_conj_field &f1 = F_conj_field[N_ij_int][N_ji_int][1];
   double F_0 = 0;
   double F_1 = 0;
   double dF_0_dx = 0, dF_0_dy = 0;
   double dF_1_dx = 0, dF_1_dy = 0;
   double l, r;
   if( N_conj_ij < 1 ) {
     l = (1-y)* (1-x);   r = ( f0.f_00 + x*     x*   f0.f_x_10   + y*     y*   f0.f_y_01 );    F_0 += l*r;   dF_0_dx += -(1-y)*r +l*2*x*    f0.f_x_10;    dF_0_dy += -(1-x)*r +l*2*y*    f0.f_y_01;
     l = (1-y)*  x;      r = ( f0.f_10 + (1-x)*(1-x)*f0.f_x_00   + y*     y*   f0.f_y_11 );    F_0 += l*r;   dF_0_dx +=  (1-y)*r -l*2*(1-x)*f0.f_x_00;    dF_0_dy += -x*    r +l*2*y*    f0.f_y_11;
     l = y*     (1-x);   r = ( f0.f_01 + x*     x*   f0.f_x_11   + (1-y)*(1-y)*f0.f_y_00 );    F_0 += l*r;   dF_0_dx += -y*    r +l*2*x*    f0.f_x_11;    dF_0_dy +=  (1-x)*r -l*2*(1-y)*f0.f_y_00;
     l = y*      x;      r = ( f0.f_11 + (1-x)*(1-x)*f0.f_x_01   + (1-y)*(1-y)*f0.f_y_10 );    F_0 += l*r;   dF_0_dx +=  y*    r -l*2*(1-x)*f0.f_x_01;    dF_0_dy +=  x*    r -l*2*(1-y)*f0.f_y_10;
   }
   if( N_conj_ij > 0 ) {
     l = (1-y)* (1-x);   r = ( f0.f_00 + x*     x*   f1.f_x_10   + y*     y*   f1.f_y_01 );    F_1 += l*r;   dF_1_dx += -(1-y)*r +l*2*x*    f1.f_x_10;    dF_1_dy += -(1-x)*r +l*2*y*    f1.f_y_01;
     l = (1-y)*  x;      r = ( f1.f_10 + (1-x)*(1-x)*f1.f_x_00   + y*     y*   f1.f_y_11 );    F_1 += l*r;   dF_1_dx +=  (1-y)*r -l*2*(1-x)*f1.f_x_00;    dF_1_dy += -x*    r +l*2*y*    f1.f_y_11;
     l = y*     (1-x);   r = ( f1.f_01 + x*     x*   f1.f_x_11   + (1-y)*(1-y)*f1.f_y_00 );    F_1 += l*r;   dF_1_dx += -y*    r +l*2*x*    f1.f_x_11;    dF_1_dy +=  (1-x)*r -l*2*(1-y)*f1.f_y_00;
     l = y*      x;      r = ( f1.f_11 + (1-x)*(1-x)*f1.f_x_01   + (1-y)*(1-y)*f1.f_y_10 );    F_1 += l*r;   dF_1_dx +=  y*    r -l*2*(1-x)*f1.f_x_01;    dF_1_dy +=  x*    r -l*2*(1-y)*f1.f_y_10;
   }
   double result = (1-N_conj_ij)*F_0 + N_conj_ij*F_1;
   *dFN_ij = (1-N_conj_ij)*dF_0_dx + N_conj_ij*dF_1_dx;
   *dFN_ji = (1-N_conj_ij)*dF_0_dy + N_conj_ij*dF_1_dy;
   *dFN_ij_conj = -F_0 + F_1;
 
   return result;
 }
 
 /* ----------------------------------------------------------------------
    read LCBOP potential file
 ------------------------------------------------------------------------- */
 
 void PairLCBOP::read_file(char *filename)
 {
   int i,j,k,l,limit;
   char s[MAXLINE];
 
   MPI_Comm_rank(world,&me);
 
   // read file on proc 0
 
   if (me == 0) {
     FILE *fp = open_potential(filename);
     if (fp == NULL) {
       char str[128];
       sprintf(str,"Cannot open LCBOP potential file %s",filename);
       error->one(FLERR,str);
     }
 
     // skip initial comment lines
 
     while (1) {
       fgets(s,MAXLINE,fp);
       if (s[0] != '#') break;
     }
 
     // read parameters
 
     fgets(s,MAXLINE,fp);    sscanf(s,"%lg",&r_1);
     fgets(s,MAXLINE,fp);    sscanf(s,"%lg",&r_2);
     fgets(s,MAXLINE,fp);    sscanf(s,"%lg",&gamma_1);
     fgets(s,MAXLINE,fp);    sscanf(s,"%lg",&A);
     fgets(s,MAXLINE,fp);    sscanf(s,"%lg",&B_1);
     fgets(s,MAXLINE,fp);    sscanf(s,"%lg",&B_2);
     fgets(s,MAXLINE,fp);    sscanf(s,"%lg",&alpha);
     fgets(s,MAXLINE,fp);    sscanf(s,"%lg",&beta_1);
     fgets(s,MAXLINE,fp);    sscanf(s,"%lg",&beta_2);
     fgets(s,MAXLINE,fp);    sscanf(s,"%lg",&d);
     fgets(s,MAXLINE,fp);    sscanf(s,"%lg",&C_1);
     fgets(s,MAXLINE,fp);    sscanf(s,"%lg",&C_4);
     fgets(s,MAXLINE,fp);    sscanf(s,"%lg",&C_6);
     fgets(s,MAXLINE,fp);    sscanf(s,"%lg",&L);
     fgets(s,MAXLINE,fp);    sscanf(s,"%lg",&kappa);
     fgets(s,MAXLINE,fp);    sscanf(s,"%lg",&R_0);
     fgets(s,MAXLINE,fp);    sscanf(s,"%lg",&R_1);
     fgets(s,MAXLINE,fp);    sscanf(s,"%lg",&r_0);
     fgets(s,MAXLINE,fp);    sscanf(s,"%lg",&r_1_LR);
     fgets(s,MAXLINE,fp);    sscanf(s,"%lg",&r_2_LR);
     fgets(s,MAXLINE,fp);    sscanf(s,"%lg",&v_1);
     fgets(s,MAXLINE,fp);    sscanf(s,"%lg",&v_2);
     fgets(s,MAXLINE,fp);    sscanf(s,"%lg",&eps_1);
     fgets(s,MAXLINE,fp);    sscanf(s,"%lg",&eps_2);
     fgets(s,MAXLINE,fp);    sscanf(s,"%lg",&lambda_1);
     fgets(s,MAXLINE,fp);    sscanf(s,"%lg",&lambda_2);
     fgets(s,MAXLINE,fp);    sscanf(s,"%lg",&eps);
     fgets(s,MAXLINE,fp);    sscanf(s,"%lg",&delta);
 
     while (1) {
       fgets(s,MAXLINE,fp);
       if (s[0] != '#') break;
     }
 
     // F_conj spline
 
     for (k = 0; k < 2; k++) { // 2 values of N_ij_conj
       for (l = 0; l < 3; l++) { // 3 types of data: f, dfdx, dfdy
         for (i = 0; i < 4; i++) { // 4x4 matrix
           fgets(s,MAXLINE,fp);
           sscanf(s,"%lg %lg %lg %lg",
             &F_conj_data[i][0][k][l],
             &F_conj_data[i][1][k][l],
             &F_conj_data[i][2][k][l],
             &F_conj_data[i][3][k][l]);
         }
         while (1) { fgets(s,MAXLINE,fp); if (s[0] != '#') break; }
       }
     }
 
     // G spline
 
     // x coordinates of mesh points
     fgets(s,MAXLINE,fp);
     sscanf( s,"%lg %lg %lg %lg %lg %lg",
       &gX[0], &gX[1], &gX[2],
       &gX[3], &gX[4], &gX[5] );
 
     for (i = 0; i < 6; i++) { // for each power in polynomial
       fgets(s,MAXLINE,fp);
       sscanf( s,"%lg %lg %lg %lg %lg",
         &gC[i][0], &gC[i][1], &gC[i][2],
         &gC[i][3], &gC[i][4] );
     }
 
     fclose(fp);
   }
 
   // broadcast read-in and setup values
 
   MPI_Bcast(&r_1      ,1,MPI_DOUBLE,0,world);
   MPI_Bcast(&r_2      ,1,MPI_DOUBLE,0,world);
   MPI_Bcast(&gamma_1  ,1,MPI_DOUBLE,0,world);
   MPI_Bcast(&A        ,1,MPI_DOUBLE,0,world);
   MPI_Bcast(&B_1      ,1,MPI_DOUBLE,0,world);
   MPI_Bcast(&B_2      ,1,MPI_DOUBLE,0,world);
   MPI_Bcast(&alpha    ,1,MPI_DOUBLE,0,world);
   MPI_Bcast(&beta_1   ,1,MPI_DOUBLE,0,world);
   MPI_Bcast(&beta_2   ,1,MPI_DOUBLE,0,world);
   MPI_Bcast(&d        ,1,MPI_DOUBLE,0,world);
   MPI_Bcast(&C_1      ,1,MPI_DOUBLE,0,world);
   MPI_Bcast(&C_4      ,1,MPI_DOUBLE,0,world);
   MPI_Bcast(&C_6      ,1,MPI_DOUBLE,0,world);
   MPI_Bcast(&L        ,1,MPI_DOUBLE,0,world);
   MPI_Bcast(&kappa    ,1,MPI_DOUBLE,0,world);
   MPI_Bcast(&R_0      ,1,MPI_DOUBLE,0,world);
   MPI_Bcast(&R_1      ,1,MPI_DOUBLE,0,world);
   MPI_Bcast(&r_0      ,1,MPI_DOUBLE,0,world);
   MPI_Bcast(&r_1_LR   ,1,MPI_DOUBLE,0,world);
   MPI_Bcast(&r_2_LR   ,1,MPI_DOUBLE,0,world);
   MPI_Bcast(&v_1      ,1,MPI_DOUBLE,0,world);
   MPI_Bcast(&v_2      ,1,MPI_DOUBLE,0,world);
   MPI_Bcast(&eps_1    ,1,MPI_DOUBLE,0,world);
   MPI_Bcast(&eps_2    ,1,MPI_DOUBLE,0,world);
   MPI_Bcast(&lambda_1 ,1,MPI_DOUBLE,0,world);
   MPI_Bcast(&lambda_2 ,1,MPI_DOUBLE,0,world);
   MPI_Bcast(&eps      ,1,MPI_DOUBLE,0,world);
   MPI_Bcast(&delta    ,1,MPI_DOUBLE,0,world);
 
   MPI_Bcast(&gX[0]    ,6,MPI_DOUBLE,0,world);
   MPI_Bcast(&gC[0][0] ,(6-1)*(5+1),MPI_DOUBLE,0,world);
 
   MPI_Bcast(&F_conj_data[0],6*4*4,MPI_DOUBLE,0,world);
 }
 
 /* ----------------------------------------------------------------------
    init coefficients for TF_conj
 ------------------------------------------------------------------------- */
 
 #include <iostream>
 #include <fstream>
 #include <functional>
 template< class function > void print_function( double x_0, double x_1, size_t n, function f, std::ostream &stream ) {
   double dx = (x_1-x_0)/n;
   for( double x=x_0; x<=x_1+0.0001; x+=dx ) {
     double f_val, df;
     f_val = f(x, &df);
     stream << x << " " << f_val << "   " << df << std::endl;
   }
   stream << std::endl;
 }
 
 void PairLCBOP::spline_init() {
   for( size_t N_conj_ij=0; N_conj_ij<2; N_conj_ij++ ) // N_conj_ij
   for( size_t N_ij=0; N_ij<4-1; N_ij++ )
   for( size_t N_ji=0; N_ji<4-1; N_ji++ ) {
     TF_conj_field &field = F_conj_field[N_ij][N_ji][N_conj_ij];
     field.f_00 = F_conj_data[N_ij  ][N_ji  ][N_conj_ij][0];
     field.f_01 = F_conj_data[N_ij  ][N_ji+1][N_conj_ij][0];
     field.f_10 = F_conj_data[N_ij+1][N_ji  ][N_conj_ij][0];
     field.f_11 = F_conj_data[N_ij+1][N_ji+1][N_conj_ij][0];
 
     field.f_x_00 =   F_conj_data[N_ij  ][N_ji  ][N_conj_ij][1] - field.f_10 + field.f_00;
     field.f_x_01 =   F_conj_data[N_ij  ][N_ji+1][N_conj_ij][1] - field.f_11 + field.f_01;
     field.f_x_10 = -(F_conj_data[N_ij+1][N_ji  ][N_conj_ij][1] - field.f_10 + field.f_00);
     field.f_x_11 = -(F_conj_data[N_ij+1][N_ji+1][N_conj_ij][1] - field.f_11 + field.f_01);
 
     field.f_y_00 =   F_conj_data[N_ij  ][N_ji  ][N_conj_ij][2] - field.f_01 + field.f_00;
     field.f_y_01 = -(F_conj_data[N_ij  ][N_ji+1][N_conj_ij][2] - field.f_01 + field.f_00);
     field.f_y_10 =   F_conj_data[N_ij+1][N_ji  ][N_conj_ij][2] - field.f_11 + field.f_10;
     field.f_y_11 = -(F_conj_data[N_ij+1][N_ji+1][N_conj_ij][2] - field.f_11 + field.f_10);
   }
 
   //some testing:
 //  std::ofstream file( "test.txt" );
 //    file << "gX:\n";
 //    file  << gX[0] << " "
 //          << gX[1] << " "
 //          << gX[2] << " "
 //          << gX[3] << " "
 //          << gX[4] << " "
 //          << gX[5] << std::endl;
 //    file << "gC:\n";
 //    for( int i=0; i<6; i++ )
 //      file  << gC[i][0] << " "
 //            << gC[i][1] << " "
 //            << gC[i][2] << " "
 //            << gC[i][3] << " "
 //            << gC[i][4] << std::endl;
 //    file << std::endl;
 //
 //    file << "gamma_1 = " << gamma_1 << std::endl;
 //    file << "r_1 = " << r_1 << std::endl;
 //    file << "r_2 = " << r_2 << std::endl;
 //    file << "A = " << A << std::endl;
 //    file << "B_1 = " << B_1 << std::endl;
 //    file << "B_2 = " << B_2 << std::endl;
 //    file << "alpha = " << alpha << std::endl;
 //    file << "beta_1 = " << beta_1 << std::endl;
 //    file << "beta_2 = " << beta_2 << std::endl;
 //    file << "d = " << d << std::endl;
 //    file << "C_1 = " << C_1 << std::endl;
 //    file << "C_4 = " << C_4 << std::endl;
 //    file << "C_6 = " << C_6 << std::endl;
 //    file << "L = " << L << std::endl;
 //    file << "kappa = " << kappa << std::endl;
 //    file << "R_0 = " << R_0 << std::endl;
 //    file << "R_1 = " << R_1 << std::endl;
 //    file << "r_0 = " << r_0 << std::endl;
 //    file << "r_1_LR = " << r_1_LR << std::endl;
 //    file << "r_2_LR = " << r_2_LR << std::endl;
 //    file << "v_1 = " << v_1 << std::endl;
 //    file << "v_2 = " << v_2 << std::endl;
 //    file << "eps_1 = " << eps_1 << std::endl;
 //    file << "eps_2 = " << eps_2 << std::endl;
 //    file << "lambda_1 = " << lambda_1 << std::endl;
 //    file << "lambda_2 = " << lambda_2 << std::endl;
 //    file << "eps = " << eps << std::endl;
 //    file << "delta = " << delta << std::endl;
 //    file << "r_2_sq = " << r_2_sq << std::endl;
 //    file << std::endl;
 //
 //
 //    file << "gSpline:" << std::endl;
 //    double x_1 = 1, x_0 = -1;
 //    int n=1000;
 //    double dx = (x_1-x_0)/n;
 //    for( double x=x_0; x<=x_1+0.0001; x+=dx ) {
 //      double g, dg;
 //      g = gSpline(x, &dg);
 //      file << x << " " << g << " " << dg << std::endl;
 //    }
 //    file << std::endl;
 //
 //  file << "hSpline:" << std::endl;
 //  double x_1 = 1, x_0 = -1;
 //  int n=1000;
 //  double dx = (x_1-x_0)/n;
 //  for( double x=x_0; x<=x_1+0.0001; x+=dx ) {
 //    double h, dh;
 //    h = hSpline(x, &dh);
 //    file << x << " " << h << " " << dh << std::endl;
 //  }
 //  file << std::endl;
 //
 //
 //  file << "f_c:" << std::endl;
 //  double x_1 = 4, x_0 = 0;
 //  int n=1000;
 //  double dx = (x_1-x_0)/n;
 //  for( double x=x_0; x<=x_1+0.0001; x+=dx ) {
 //    double f, df;
 //    f = f_c(x, r_1, r_2, &df);
 //    file << x << " " << f << " " << df << std::endl;
 //  }
 //  file << std::endl;
 
 //  file << "F_conj_data\n";
 //  for (int k = 0; k < 2; k++) { // 2 values of N_ij_conj
 //    for (int l = 0; l < 3; l++) { // 3 types of data: f, dfdx, dfdy
 //      for (int i = 0; i < 4; i++) { // 4x4 matrix
 //        file
 //          << F_conj_data[i][0][k][l] << " "
 //          << F_conj_data[i][1][k][l] << " "
 //          << F_conj_data[i][2][k][l] << " "
 //          << F_conj_data[i][3][k][l] << std::endl;
 //      }
 //    file << std::endl;
 //    }
 //  }
 //
 //
 //  file << "F_conj_0 ";
 //  double dummy;
 //  for( double y=0; y<=3.0+0.0001; y+=0.1 )
 //    file << y << " ";
 //  file << std::endl;
 //  for( double x=0; x<=3.0+0.0001; x+=0.1 ){
 //    file << x << " ";
 //    for( double y=0; y<=3.0+0.0001; y+=0.1 )
 //      file << F_conj( x, y, 0, &dummy, &dummy, &dummy ) << " ";
 //    file << std::endl;
 //  }
 //
 //  file << "dF0_dx ";
 //  for( double y=0; y<=3.0+0.0001; y+=0.1 )
 //    file << y << " ";
 //  file << std::endl;
 //  for( double x=0; x<=3.0+0.0001; x+=0.1 ){
 //    file << x << " ";
 //    for( double y=0; y<=3.0+0.0001; y+=0.1 ) {
 //      double dF_dx;
 //      F_conj( x, y, 0, &dF_dx, &dummy, &dummy );
 //      file << dF_dx << " ";
 //    }
 //    file << std::endl;
 //  }
 //
 //
 //
 //  file << "F_conj_1 ";
 //  for( double y=0; y<=3.0+0.0001; y+=0.1 )
 //    file << y << " ";
 //  file << std::endl;
 //  for( double x=0; x<=3.0+0.0001; x+=0.1 ){
 //    file << x << " ";
 //    for( double y=0; y<=3.0+0.0001; y+=0.1 )
 //      file << F_conj( x, y, 0, &dummy, &dummy, &dummy ) << " ";
 //    file << std::endl;
 //  }
 
 }
 
 /* ----------------------------------------------------------------------
    memory usage of local atom-based arrays
 ------------------------------------------------------------------------- */
 
-double PairLCBOP::memory_usage() {
+double PairLCBOP::memory_usage()
+{
   double bytes = 0.0;
   bytes += maxlocal * sizeof(int);
   bytes += maxlocal * sizeof(int *);
-  bytes += maxpage * neighbor->pgsize * sizeof(int);
-  bytes += 3 * maxlocal * sizeof(double);
+  bytes += ipage->size();
+  bytes += 3*maxlocal * sizeof(double);
   return bytes;
 }
diff --git a/src/MANYBODY/pair_lcbop.h b/src/MANYBODY/pair_lcbop.h
index 71567cec9..dc0ad61c7 100644
--- a/src/MANYBODY/pair_lcbop.h
+++ b/src/MANYBODY/pair_lcbop.h
@@ -1,204 +1,207 @@
 /* ----------------------------------------------------------------------
    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(lcbop,PairLCBOP)
 
 #else
 
 #ifndef LMP_PAIR_LCBOP_H
 #define LMP_PAIR_LCBOP_H
 
 #include "pair.h"
+#include "my_page.h"
 #include "math.h"
 #include "math_const.h"
 
 namespace LAMMPS_NS {
 
 class PairLCBOP : public Pair {
  public:
   PairLCBOP(class LAMMPS *);
   virtual ~PairLCBOP();
   virtual void compute(int, int);
   virtual void settings(int, char **);
   void coeff(int, char **);
   void init_style();
   double init_one(int, int);
   double memory_usage();
 
  protected:
   int **pages;                     // neighbor list pages
   int *map;                        // 0 (C) or -1 (NULL) for each type
 
   int me;
-  int maxlocal;                    // size of numneigh, firstneigh arrays
-  int maxpage;                     // # of pages currently allocated
-  int pgsize;                      // size of neighbor page
-  int oneatom;                     // max # of neighbors for one atom
 
   double cutLR;                    // LR cutoff
 
   double cutLRsq;                  // LR cutoff squared
   double cut3rebo;                 // maximum distance for 3rd SR neigh
 
+  int maxlocal;                    // size of numneigh, firstneigh arrays
+  int maxpage;                     // # of pages currently allocated
+  int pgsize;                      // size of neighbor page
+  int oneatom;                     // max # of neighbors for one atom
+  MyPage<int> *ipage;              // neighbor list pages
   int *SR_numneigh;                // # of pair neighbors for each atom
   int **SR_firstneigh;             // ptr to 1st neighbor of each atom
+
   double *N;                       // sum of cutoff fns ( f_C ) with SR neighs
   double *M;                       // sum_j f_C_ij*F(N_j - f_C_ij)
 
   double
     r_1, r_2, gamma_1, A, B_1, B_2, alpha, beta_1, beta_2,
     d, C_1, C_4, C_6, L, kappa, R_0, R_1,
     r_0, r_1_LR, r_2_LR,
     v_1, v_2, eps_1, eps_2, lambda_1, lambda_2, eps, delta;
   double r_2_sq;
 
   // splines coefficients
   struct TF_conj_field {
     double
         f_00,
         f_01,
         f_10,
         f_11,
         f_x_00,
         f_x_01,
         f_x_10,
         f_x_11,
         f_y_00,
         f_y_01,
         f_y_10,
         f_y_11;
   } F_conj_field[3][3][2];
+
   double F_conj_data[4][4][2][3]; // temporary data from file
   double gX[6];        // x coordinates for described points[# of points];
   double gC[5+1][6-1]; // coefficients for each period between described points [degree of polynomial+1][# of points-1]
 
   void SR_neigh();
   void FSR(int, int);
   void FLR(int, int);
 
   void FNij( int, int, double, double**, int );
   void FMij( int, int, double, double**, int );
   double bondorder( int, int, double*, double, double, double**, int );
   double b        ( int, int, double*, double, double, double**, int );
 
   double gSpline( double, double* );
   double hSpline( double, double* );
   void g_decompose_x( double, size_t*, double* );
   double F_conj( double, double, double, double*, double*, double* );
 
-  void add_pages(int howmany = 1);
   void read_file( char * );
 
   void spline_init();
 
   void allocate();
 
   // ----------------------------------------------------------------------
   // S'(t) and S(t) cutoff functions
   // added to header for inlining
   // ----------------------------------------------------------------------
 
   /* ----------------------------------------------------------------------
      short range cutoff function
      return cutoff and dX = derivative
      no side effects
   ------------------------------------------------------------------------- */
 
   inline double f_c(double Xij, double Xmin, double Xmax, double *dX) const {
     double cutoff;
 
     double t = (Xij-Xmin) / (Xmax-Xmin);
     if (t <= 0.0) {
       cutoff = 1.0;
       *dX = 0.0;
     } else if (t >= 1.0) {
       cutoff = 0.0;
       *dX = 0.0;
     } else {
       double z = t*t*t-1;
       cutoff = exp( gamma_1*t*t*t/z );
       *dX = cutoff * (-3*gamma_1*t*t)/z/z / (Xmax-Xmin);
     }
     return cutoff;
   };
 
   /* ----------------------------------------------------------------------
      long range cutoff function
      return cutoff and dX = derivative
      no side effects
   ------------------------------------------------------------------------- */
 
   inline double f_c_LR(double Xij, double Xmin, double Xmax, double *dX) const {
     double cutoff;
 
     double t = (Xij-Xmin) / (Xmax-Xmin);
     if (t <= 0.0) {
       cutoff = 1.0;
       //dX = 0.0; this way the derivative is inherited from previous cut off function call
     } else if (t >= 1.0) {
       cutoff = 0.0;
       *dX = 0.0;
     } else {
       cutoff = ( 1.0+cos(MathConst::MY_PI*t) )/2.0;
       *dX = -MathConst::MY_PI*sin(MathConst::MY_PI*t)/2/(Xmax-Xmin);
     }
     return cutoff;
   };
 
 };
 
 }
 
 #endif
 #endif
 
 /* ERROR/WARNING messages:
 
 E: Illegal ... command
 
 Self-explanatory.  Check the input script syntax and compare to the
 documentation for the command.  You can use -echo screen as a
 command-line option when running LAMMPS to see the offending line.
 
 E: Incorrect args for pair coefficients
 
 Self-explanatory.  Check the input script or data file.
 
 E: Pair style LCBOP requires atom IDs
 
 This is a requirement to use the LCBOP potential.
 
 E: Pair style LCBOP requires newton pair on
 
 See the newton command.  This is a restriction to use the LCBOP
 potential.
 
 E: All pair coeffs are not set
 
 All pair coefficients must be set in the data file or by the
 pair_coeff command before running a simulation.
 
 E: Neighbor list overflow, boost neigh_modify one or page
 
 There are too many neighbors of a single atom.  Use the neigh_modify
 command to increase the neighbor page size and the max number of
 neighbors allowed for one atom.
 
 E: Cannot open LCBOP potential file %s
 
 The specified LCBOP potential file cannot be opened.  Check that the
 path and name are correct.
 
 */
diff --git a/src/USER-OMP/fix_shear_history_omp.cpp b/src/USER-OMP/fix_shear_history_omp.cpp
index e4b659945..b74e9ef8d 100644
--- a/src/USER-OMP/fix_shear_history_omp.cpp
+++ b/src/USER-OMP/fix_shear_history_omp.cpp
@@ -1,152 +1,173 @@
 /* ----------------------------------------------------------------------
    LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
    http://lammps.sandia.gov, Sandia National Laboratories
    Steve Plimpton, sjplimp@sandia.gov
 
    Copyright (2003) Sandia Corporation.  Under the terms of Contract
    DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
    certain rights in this software.  This software is distributed under
    the GNU General Public License.
 
    See the README file in the top-level LAMMPS directory.
 ------------------------------------------------------------------------- */
 
 #include "string.h"
 #include "stdio.h"
 #include "fix_shear_history_omp.h"
 #include "atom.h"
 #include "comm.h"
 #include "neighbor.h"
 #include "neigh_list.h"
 #include "force.h"
 #include "pair.h"
 #include "update.h"
 #include "modify.h"
 #include "error.h"
 
 #if defined(_OPENMP)
 #include <omp.h>
 #endif
 
 using namespace LAMMPS_NS;
 using namespace FixConst;
 
-#define MAXTOUCH 15
-
 /* ----------------------------------------------------------------------
    copy shear partner info from neighbor lists to atom arrays
    so can be migrated or stored with atoms
 ------------------------------------------------------------------------- */
 
 void FixShearHistoryOMP::pre_exchange()
 {
 
   const int nlocal = atom->nlocal;
   const int nghost = atom->nghost;
   const int nall = nlocal + nghost;
   const int nthreads = comm->nthreads;
-
-  int flag = 0;
+  maxtouch = 0;
+  
 #if defined(_OPENMP)
-#pragma omp parallel default(none) shared(flag)
+#pragma omp parallel default(none)
 #endif
   {
 
 #if defined(_OPENMP)
     const int tid = omp_get_thread_num();
 #else
     const int tid = 0;
 #endif
 
     // each thread works on a fixed chunk of local and ghost atoms.
     const int ldelta = 1 + nlocal/nthreads;
     const int lfrom = tid*ldelta;
     const int lmax = lfrom +ldelta;
     const int lto = (lmax > nlocal) ? nlocal : lmax;
 
-    const int gdelta = 1 + nghost/nthreads;
-    const int gfrom = nlocal + tid*gdelta;
-    const int gmax = gfrom + gdelta;
-    const int gto = (gmax > nall) ? nall : gmax;
-
-
-    int i,j,ii,jj,m,inum,jnum;
+    int i,j,ii,jj,m,n,inum,jnum;
     int *ilist,*jlist,*numneigh,**firstneigh;
     int *touch,**firsttouch;
     double *shear,*allshear,**firstshear;
 
-    // zero npartners for all current atoms
+    // zero npartners for all current atoms and
+    // clear page data structures for this thread
 
     for (i = lfrom; i < lto; i++) npartner[i] = 0;
 
-    // copy shear info from neighbor list atoms to atom arrays
+    MyPage <int> &ipg = ipage[tid];
+    MyPage <double[3]> &dpg = dpage[tid];
+    ipg.reset();
+    dpg.reset();
+
+    // 1st loop over neighbor list
+    // calculate nparter for each owned atom
 
     int *tag = atom->tag;
 
     NeighList *list = pair->list;
     inum = list->inum;
     ilist = list->ilist;
     numneigh = list->numneigh;
     firstneigh = list->firstneigh;
     firsttouch = list->listgranhistory->firstneigh;
     firstshear = list->listgranhistory->firstdouble;
 
     for (ii = 0; ii < inum; ii++) {
       i = ilist[ii];
       jlist = firstneigh[i];
-      allshear = firstshear[i];
       jnum = numneigh[i];
       touch = firsttouch[i];
 
       for (jj = 0; jj < jnum; jj++) {
         if (touch[jj]) {
+          if ((i >= lfrom) && (i < lto))
+            npartner[i]++;
+
           j = jlist[jj];
           j &= NEIGHMASK;
+          if ((j >= lfrom) && (j < lto))
+            npartner[j]++;
+        }
+      }
+    }
+
+    // get page chunks to store atom IDs and shear history for my atoms
+
+    for (ii = lfrom; ii < lto; ii++) {
+      i = ilist[ii];
+      n = npartner[i];
+      partner[i] = ipg.get(n);
+      shearpartner[i] = dpg.get(n);
+      if (partner[i] == NULL || shearpartner[i] == NULL)
+        error->one(FLERR,"Shear history overflow, boost neigh_modify one");
+    }
+
+    // 2nd loop over neighbor list
+    // store atom IDs and shear history for my atoms
+    // re-zero npartner to use as counter for all my atoms
+
+    for (i = lfrom; i < lto; i++) npartner[i] = 0;
+
+    for (ii = 0; ii < inum; ii++) {
+      i = ilist[ii];
+      jlist = firstneigh[i];
+      allshear = firstshear[i];
+      jnum = numneigh[i];
+      touch = firsttouch[i];
+
+      for (jj = 0; jj < jnum; jj++) {
+        if (touch[jj]) {
           shear = &allshear[3*jj];
+          j = jlist[jj];
+          j &= NEIGHMASK;
 
           if ((i >= lfrom) && (i < lto)) {
-            if (npartner[i] < MAXTOUCH) {
-              m = npartner[i];
-              partner[i][m] = tag[j];
-              shearpartner[i][m][0] = shear[0];
-              shearpartner[i][m][1] = shear[1];
-              shearpartner[i][m][2] = shear[2];
-            }
+            m = npartner[i];
+            partner[i][m] = tag[j];
+            shearpartner[i][m][0] = shear[0];
+            shearpartner[i][m][1] = shear[1];
+            shearpartner[i][m][2] = shear[2];
             npartner[i]++;
           }
 
           if ((j >= lfrom) && (j < lto)) {
-            if (npartner[j] < MAXTOUCH) {
-              m = npartner[j];
-              partner[j][m] = tag[i];
-              shearpartner[j][m][0] = -shear[0];
-              shearpartner[j][m][1] = -shear[1];
-              shearpartner[j][m][2] = -shear[2];
-            }
-            npartner[j]++;
-          }
-
-          if ((j >= gfrom) && (j < gto)) {
+            m = npartner[j];
+            partner[j][m] = tag[i];
+            shearpartner[j][m][0] = -shear[0];
+            shearpartner[j][m][1] = -shear[1];
+            shearpartner[j][m][2] = -shear[2];
             npartner[j]++;
           }
         }
       }
     }
 
-    // test for too many touching neighbors
-    int myflag = 0;
+    // set maxtouch = max # of partners of any owned atom
+    m = 0;
     for (i = lfrom; i < lto; i++)
-      if (npartner[i] >= MAXTOUCH) myflag = 1;
+      m = MAX(m,npartner[i]);
 
-    if (myflag)
 #if defined(_OPENMP)
-#pragma omp atomic
+#pragma omp critical
 #endif
-      ++flag;
+    maxtouch = MAX(m,maxtouch);
   }
-
-  int flag_all;
-  MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_SUM,world);
-  if (flag_all)
-    error->all(FLERR,"Too many touching neighbors - boost MAXTOUCH");
 }
diff --git a/src/USER-OMP/neigh_derive_omp.cpp b/src/USER-OMP/neigh_derive_omp.cpp
index 4356f17b6..8f5fa05e8 100644
--- a/src/USER-OMP/neigh_derive_omp.cpp
+++ b/src/USER-OMP/neigh_derive_omp.cpp
@@ -1,183 +1,162 @@
 /* ----------------------------------------------------------------------
    LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
    http://lammps.sandia.gov, Sandia National Laboratories
    Steve Plimpton, sjplimp@sandia.gov
 
    Copyright (2003) Sandia Corporation.  Under the terms of Contract
    DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
    certain rights in this software.  This software is distributed under
    the GNU General Public License.
 
    See the README file in the top-level LAMMPS directory.
 ------------------------------------------------------------------------- */
 
 #include "neighbor.h"
 #include "neighbor_omp.h"
 #include "neigh_list.h"
 #include "atom.h"
 #include "comm.h"
+#include "my_page.h"
 #include "error.h"
 
 using namespace LAMMPS_NS;
 
 /* ----------------------------------------------------------------------
    build half list from full list
    pair stored once if i,j are both owned and i < j
    pair stored by me if j is ghost (also stored by proc owning j)
    works if full list is a skip list
 ------------------------------------------------------------------------- */
 
 void Neighbor::half_from_full_no_newton_omp(NeighList *list)
 {
   const int inum_full = list->listfull->inum;
 
   NEIGH_OMP_INIT;
 
 #if defined(_OPENMP)
 #pragma omp parallel default(none) shared(list)
 #endif
   NEIGH_OMP_SETUP(inum_full);
 
   int i,j,ii,jj,n,jnum,joriginal;
   int *neighptr,*jlist;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
   int *ilist_full = list->listfull->ilist;
   int *numneigh_full = list->listfull->numneigh;
   int **firstneigh_full = list->listfull->firstneigh;
 
-  // each thread works on its own page
-  int npage = tid;
-  int npnt = 0;
+  // each thread has its own page allocator
+  MyPage<int> &ipage = list->ipage[tid];
+  ipage.reset();
 
   // loop over atoms in full list
 
   for (ii = ifrom; ii < ito; ii++) {
 
-#if defined(_OPENMP)
-#pragma omp critical
-#endif
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage += nthreads;
-      // only one thread at a time may check whether we
-      // need new neighbor list pages and then add to them.
-      if (npage >= list->maxpage) list->add_pages(nthreads);
-    }
-
-    neighptr = &(list->pages[npage][npnt]);
     n = 0;
+    neighptr = ipage.vget();
 
     // loop over parent full list
 
     i = ilist_full[ii];
     jlist = firstneigh_full[i];
     jnum = numneigh_full[i];
 
     for (jj = 0; jj < jnum; jj++) {
       joriginal = jlist[jj];
       j = joriginal & NEIGHMASK;
       if (j > i) neighptr[n++] = joriginal;
     }
 
     ilist[ii] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage.vgot(n);
+    if (ipage.status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
   NEIGH_OMP_CLOSE;
   list->inum = inum_full;
 }
 
 /* ----------------------------------------------------------------------
    build half list from full list
    pair stored once if i,j are both owned and i < j
    if j is ghost, only store if j coords are "above and to the right" of i
    works if full list is a skip list
 ------------------------------------------------------------------------- */
 
 void Neighbor::half_from_full_newton_omp(NeighList *list)
 {
   const int inum_full = list->listfull->inum;
 
   NEIGH_OMP_INIT;
 #if defined(_OPENMP)
 #pragma omp parallel default(none) shared(list)
 #endif
   NEIGH_OMP_SETUP(inum_full);
 
   int i,j,ii,jj,n,jnum,joriginal;
   int *neighptr,*jlist;
   double xtmp,ytmp,ztmp;
 
   double **x = atom->x;
   int nlocal = atom->nlocal;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
   int *ilist_full = list->listfull->ilist;
   int *numneigh_full = list->listfull->numneigh;
   int **firstneigh_full = list->listfull->firstneigh;
 
-  // each thread works on its own page
-  int npage = tid;
-  int npnt = 0;
+  // each thread has its own page allocator
+  MyPage<int> &ipage = list->ipage[tid];
+  ipage.reset();
 
   // loop over parent full list
 
   for (ii = ifrom; ii < ito; ii++) {
 
-#if defined(_OPENMP)
-#pragma omp critical
-#endif
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage += nthreads;
-      // only one thread at a time may check  whether we
-      // need new neighbor list pages and then add to them.
-      if (npage >= list->maxpage) list->add_pages(nthreads);
-    }
-
-    neighptr = &(list->pages[npage][npnt]);
     n = 0;
+    neighptr = ipage.vget();
 
     i = ilist_full[ii];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over full neighbor list
 
     jlist = firstneigh_full[i];
     jnum = numneigh_full[i];
 
     for (jj = 0; jj < jnum; jj++) {
       joriginal = jlist[jj];
       j = joriginal & NEIGHMASK;
       if (j < nlocal) {
         if (i > j) continue;
       } else {
         if (x[j][2] < ztmp) continue;
         if (x[j][2] == ztmp) {
           if (x[j][1] < ytmp) continue;
           if (x[j][1] == ytmp && x[j][0] < xtmp) continue;
         }
       }
       neighptr[n++] = joriginal;
     }
 
     ilist[ii] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage.vgot(n);
+    if (ipage.status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
   NEIGH_OMP_CLOSE;
   list->inum = inum_full;
 }
diff --git a/src/USER-OMP/neigh_full_omp.cpp b/src/USER-OMP/neigh_full_omp.cpp
index 8ba2ffaf2..e60962789 100644
--- a/src/USER-OMP/neigh_full_omp.cpp
+++ b/src/USER-OMP/neigh_full_omp.cpp
@@ -1,579 +1,540 @@
 /* ----------------------------------------------------------------------
    LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
    http://lammps.sandia.gov, Sandia National Laboratories
    Steve Plimpton, sjplimp@sandia.gov
 
    Copyright (2003) Sandia Corporation.  Under the terms of Contract
    DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
    certain rights in this software.  This software is distributed under
    the GNU General Public License.
 
    See the README file in the top-level LAMMPS directory.
 ------------------------------------------------------------------------- */
 
 #include "neighbor.h"
 #include "neighbor_omp.h"
 #include "neigh_list.h"
 #include "atom.h"
 #include "comm.h"
 #include "domain.h"
 #include "group.h"
+#include "my_page.h"
 #include "error.h"
 
 using namespace LAMMPS_NS;
 
 /* ----------------------------------------------------------------------
    N^2 search for all neighbors
    every neighbor pair appears in list of both atoms i and j
 ------------------------------------------------------------------------- */
 
 void Neighbor::full_nsq_omp(NeighList *list)
 {
   const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal;
   const int bitmask = (includegroup) ? group->bitmask[includegroup] : 0;
 
   NEIGH_OMP_INIT;
 #if defined(_OPENMP)
 #pragma omp parallel default(none) shared(list)
 #endif
   NEIGH_OMP_SETUP(nlocal);
 
   int i,j,n,itype,jtype,which;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int *neighptr;
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int nall = atom->nlocal + atom->nghost;
   int molecular = atom->molecular;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
 
-  int npage = tid;
-  int npnt = 0;
+  // each thread has its own page allocator
+  MyPage<int> &ipage = list->ipage[tid];
+  ipage.reset();
 
   // loop over owned atoms, storing neighbors
 
   for (i = ifrom; i < ito; i++) {
 
-#if defined(_OPENMP)
-#pragma omp critical
-#endif
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage += nthreads;
-      if (npage >= list->maxpage) list->add_pages(nthreads);
-    }
-
-    neighptr = &(list->pages[npage][npnt]);
     n = 0;
+    neighptr = ipage.vget();
 
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over all atoms, owned and ghost
     // skip i = j
 
     for (j = 0; j < nall; j++) {
       if (includegroup && !(mask[j] & bitmask)) continue;
       if (i == j) continue;
       jtype = type[j];
       if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
       delx = xtmp - x[j][0];
       dely = ytmp - x[j][1];
       delz = ztmp - x[j][2];
       rsq = delx*delx + dely*dely + delz*delz;
       if (rsq <= cutneighsq[itype][jtype]) {
         if (molecular) {
           which = find_special(special[i],nspecial[i],tag[j]);
           if (which == 0) neighptr[n++] = j;
           else if (domain->minimum_image_check(delx,dely,delz))
             neighptr[n++] = j;
           else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
         } else neighptr[n++] = j;
       }
     }
 
     ilist[i] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage.vgot(n);
+    if (ipage.status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
   NEIGH_OMP_CLOSE;
   list->inum = nlocal;
   list->gnum = 0;
 }
 
 /* ----------------------------------------------------------------------
    N^2 search for all neighbors
    include neighbors of ghost atoms, but no "special neighbors" for ghosts
    every neighbor pair appears in list of both atoms i and j
 ------------------------------------------------------------------------- */
 
 void Neighbor::full_nsq_ghost_omp(NeighList *list)
 {
   const int nlocal = atom->nlocal;
   const int nall = nlocal + atom->nghost;
 
   NEIGH_OMP_INIT;
 #if defined(_OPENMP)
 #pragma omp parallel default(none) shared(list)
 #endif
   NEIGH_OMP_SETUP(nall);
 
   int i,j,n,itype,jtype,which;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int *neighptr;
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int molecular = atom->molecular;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
 
-  int npage = tid;
-  int npnt = 0;
+  // each thread has its own page allocator
+  MyPage<int> &ipage = list->ipage[tid];
+  ipage.reset();
 
   // loop over owned & ghost atoms, storing neighbors
 
   for (i = ifrom; i < ito; i++) {
 
-#if defined(_OPENMP)
-#pragma omp critical
-#endif
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage += nthreads;
-      if (npage >= list->maxpage) list->add_pages(nthreads);
-    }
-
-    neighptr = &(list->pages[npage][npnt]);
     n = 0;
+    neighptr = ipage.vget();
 
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over all atoms, owned and ghost
     // skip i = j
     // no molecular test when i = ghost atom
 
     if (i < nlocal) {
       for (j = 0; j < nall; j++) {
         if (i == j) continue;
         jtype = type[j];
         if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
         delx = xtmp - x[j][0];
         dely = ytmp - x[j][1];
         delz = ztmp - x[j][2];
         rsq = delx*delx + dely*dely + delz*delz;
         if (rsq <= cutneighsq[itype][jtype]) {
           if (molecular) {
             which = find_special(special[i],nspecial[i],tag[j]);
             if (which == 0) neighptr[n++] = j;
             else if (domain->minimum_image_check(delx,dely,delz))
               neighptr[n++] = j;
             else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
           } else neighptr[n++] = j;
         }
       }
     } else {
       for (j = 0; j < nall; j++) {
         if (i == j) continue;
         jtype = type[j];
         if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
         delx = xtmp - x[j][0];
         dely = ytmp - x[j][1];
         delz = ztmp - x[j][2];
         rsq = delx*delx + dely*dely + delz*delz;
 
         if (rsq <= cutneighghostsq[itype][jtype]) neighptr[n++] = j;
       }
     }
 
     ilist[i] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage.vgot(n);
+    if (ipage.status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
   NEIGH_OMP_CLOSE;
   list->inum = nlocal;
   list->gnum = nall - nlocal;
 }
 
 /* ----------------------------------------------------------------------
    binned neighbor list construction for all neighbors
    every neighbor pair appears in list of both atoms i and j
 ------------------------------------------------------------------------- */
 
 void Neighbor::full_bin_omp(NeighList *list)
 {
   // bin owned & ghost atoms
 
   bin_atoms();
 
   const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal;
 
   NEIGH_OMP_INIT;
 #if defined(_OPENMP)
 #pragma omp parallel default(none) shared(list)
 #endif
   NEIGH_OMP_SETUP(nlocal);
 
   int i,j,k,n,itype,jtype,ibin,which;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int *neighptr;
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int molecular = atom->molecular;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
   int nstencil = list->nstencil;
   int *stencil = list->stencil;
 
-  int npage = tid;
-  int npnt = 0;
+  // each thread has its own page allocator
+  MyPage<int> &ipage = list->ipage[tid];
+  ipage.reset();
 
   // loop over owned atoms, storing neighbors
 
   for (i = ifrom; i < ito; i++) {
 
-#if defined(_OPENMP)
-#pragma omp critical
-#endif
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage += nthreads;
-      if (npage >= list->maxpage) list->add_pages(nthreads);
-    }
-
-    neighptr = &(list->pages[npage][npnt]);
     n = 0;
+    neighptr = ipage.vget();
 
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over all atoms in surrounding bins in stencil including self
     // skip i = j
 
     ibin = coord2bin(x[i]);
 
     for (k = 0; k < nstencil; k++) {
       for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
         if (i == j) continue;
 
         jtype = type[j];
         if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
         delx = xtmp - x[j][0];
         dely = ytmp - x[j][1];
         delz = ztmp - x[j][2];
         rsq = delx*delx + dely*dely + delz*delz;
 
         if (rsq <= cutneighsq[itype][jtype]) {
           if (molecular) {
             which = find_special(special[i],nspecial[i],tag[j]);
             if (which == 0) neighptr[n++] = j;
             else if (domain->minimum_image_check(delx,dely,delz))
               neighptr[n++] = j;
             else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
           } else neighptr[n++] = j;
         }
       }
     }
 
     ilist[i] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage.vgot(n);
+    if (ipage.status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
   NEIGH_OMP_CLOSE;
   list->inum = nlocal;
   list->gnum = 0;
 }
 
 /* ----------------------------------------------------------------------
    binned neighbor list construction for all neighbors
    include neighbors of ghost atoms, but no "special neighbors" for ghosts
    every neighbor pair appears in list of both atoms i and j
 ------------------------------------------------------------------------- */
 
 void Neighbor::full_bin_ghost_omp(NeighList *list)
 {
   // bin owned & ghost atoms
 
   bin_atoms();
 
   const int nlocal = atom->nlocal;
   const int nall = nlocal + atom->nghost;
 
   NEIGH_OMP_INIT;
 #if defined(_OPENMP)
 #pragma omp parallel default(none) shared(list)
 #endif
   NEIGH_OMP_SETUP(nall);
 
   int i,j,k,n,itype,jtype,ibin,which;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int xbin,ybin,zbin,xbin2,ybin2,zbin2;
   int *neighptr;
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int molecular = atom->molecular;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
   int nstencil = list->nstencil;
   int *stencil = list->stencil;
   int **stencilxyz = list->stencilxyz;
 
-  int npage = tid;
-  int npnt = 0;
+  // each thread has its own page allocator
+  MyPage<int> &ipage = list->ipage[tid];
+  ipage.reset();
 
   // loop over owned & ghost atoms, storing neighbors
 
   for (i = ifrom; i < ito; i++) {
 
-#if defined(_OPENMP)
-#pragma omp critical
-#endif
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage += nthreads;
-      if (npage >= list->maxpage) list->add_pages(nthreads);
-    }
-
-    neighptr = &(list->pages[npage][npnt]);
     n = 0;
+    neighptr = ipage.vget();
 
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over all atoms in surrounding bins in stencil including self
     // when i is a ghost atom, must check if stencil bin is out of bounds
     // skip i = j
     // no molecular test when i = ghost atom
 
     if (i < nlocal) {
       ibin = coord2bin(x[i]);
       for (k = 0; k < nstencil; k++) {
         for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
           if (i == j) continue;
 
           jtype = type[j];
           if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
           delx = xtmp - x[j][0];
           dely = ytmp - x[j][1];
           delz = ztmp - x[j][2];
           rsq = delx*delx + dely*dely + delz*delz;
 
           if (rsq <= cutneighsq[itype][jtype]) {
             if (molecular) {
               which = find_special(special[i],nspecial[i],tag[j]);
               if (which == 0) neighptr[n++] = j;
               else if (domain->minimum_image_check(delx,dely,delz))
                 neighptr[n++] = j;
               else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
             } else neighptr[n++] = j;
           }
         }
       }
 
     } else {
       ibin = coord2bin(x[i],xbin,ybin,zbin);
       for (k = 0; k < nstencil; k++) {
         xbin2 = xbin + stencilxyz[k][0];
         ybin2 = ybin + stencilxyz[k][1];
         zbin2 = zbin + stencilxyz[k][2];
         if (xbin2 < 0 || xbin2 >= mbinx ||
             ybin2 < 0 || ybin2 >= mbiny ||
             zbin2 < 0 || zbin2 >= mbinz) continue;
         for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
           if (i == j) continue;
 
           jtype = type[j];
           if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
           delx = xtmp - x[j][0];
           dely = ytmp - x[j][1];
           delz = ztmp - x[j][2];
           rsq = delx*delx + dely*dely + delz*delz;
 
           if (rsq <= cutneighghostsq[itype][jtype]) neighptr[n++] = j;
         }
       }
     }
 
     ilist[i] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage.vgot(n);
+    if (ipage.status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
   NEIGH_OMP_CLOSE;
   list->inum = nlocal;
   list->gnum = nall - nlocal;
 }
 
 /* ----------------------------------------------------------------------
    binned neighbor list construction for all neighbors
    multi-type stencil is itype dependent and is distance checked
    every neighbor pair appears in list of both atoms i and j
 ------------------------------------------------------------------------- */
 
 void Neighbor::full_multi_omp(NeighList *list)
 {
   // bin local & ghost atoms
 
   bin_atoms();
 
   const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal;
 
   NEIGH_OMP_INIT;
 #if defined(_OPENMP)
 #pragma omp parallel default(none) shared(list)
 #endif
   NEIGH_OMP_SETUP(nlocal);
 
   int i,j,k,n,itype,jtype,ibin,which,ns;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int *neighptr,*s;
   double *cutsq,*distsq;
 
   // loop over each atom, storing neighbors
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int molecular = atom->molecular;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
   int *nstencil_multi = list->nstencil_multi;
   int **stencil_multi = list->stencil_multi;
   double **distsq_multi = list->distsq_multi;
 
-  int npage = tid;
-  int npnt = 0;
+  // each thread has its own page allocator
+  MyPage<int> &ipage = list->ipage[tid];
+  ipage.reset();
 
   for (i = ifrom; i < ito; i++) {
 
-#if defined(_OPENMP)
-#pragma omp critical
-#endif
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage += nthreads;
-      if (npage >= list->maxpage) list->add_pages(nthreads);
-    }
-
-    neighptr = &(list->pages[npage][npnt]);
     n = 0;
+    neighptr = ipage.vget();
 
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over all atoms in other bins in stencil, including self
     // skip if i,j neighbor cutoff is less than bin distance
     // skip i = j
 
     ibin = coord2bin(x[i]);
     s = stencil_multi[itype];
     distsq = distsq_multi[itype];
     cutsq = cutneighsq[itype];
     ns = nstencil_multi[itype];
     for (k = 0; k < ns; k++) {
       for (j = binhead[ibin+s[k]]; j >= 0; j = bins[j]) {
         jtype = type[j];
         if (cutsq[jtype] < distsq[k]) continue;
         if (i == j) continue;
 
         if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
         delx = xtmp - x[j][0];
         dely = ytmp - x[j][1];
         delz = ztmp - x[j][2];
         rsq = delx*delx + dely*dely + delz*delz;
 
         if (rsq <= cutneighsq[itype][jtype]) {
           if (molecular) {
             which = find_special(special[i],nspecial[i],tag[j]);
             if (which == 0) neighptr[n++] = j;
             else if (domain->minimum_image_check(delx,dely,delz))
               neighptr[n++] = j;
             else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
           } else neighptr[n++] = j;
         }
       }
     }
 
     ilist[i] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage.vgot(n);
+    if (ipage.status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
   NEIGH_OMP_CLOSE;
   list->inum = nlocal;
   list->gnum = 0;
 }
diff --git a/src/USER-OMP/neigh_gran_omp.cpp b/src/USER-OMP/neigh_gran_omp.cpp
index 71fee4ec4..5f0402f36 100644
--- a/src/USER-OMP/neigh_gran_omp.cpp
+++ b/src/USER-OMP/neigh_gran_omp.cpp
@@ -1,657 +1,617 @@
 /* ----------------------------------------------------------------------
    LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
    http://lammps.sandia.gov, Sandia National Laboratories
    Steve Plimpton, sjplimp@sandia.gov
 
    Copyright (2003) Sandia Corporation.  Under the terms of Contract
    DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
    certain rights in this software.  This software is distributed under
    the GNU General Public License.
 
    See the README file in the top-level LAMMPS directory.
 ------------------------------------------------------------------------- */
 
 #include "neighbor.h"
 #include "neighbor_omp.h"
 #include "neigh_list.h"
 #include "atom.h"
 #include "comm.h"
 #include "group.h"
 #include "fix_shear_history.h"
 #include "error.h"
 
 using namespace LAMMPS_NS;
 
 /* ----------------------------------------------------------------------
    granular particles
    N^2 / 2 search for neighbor pairs with partial Newton's 3rd law
    shear history must be accounted for when a neighbor pair is added
    pair added to list if atoms i and j are both owned and i < j
    pair added if j is ghost (also stored by proc owning j)
 ------------------------------------------------------------------------- */
 
 void Neighbor::granular_nsq_no_newton_omp(NeighList *list)
 {
   const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal;
   const int bitmask = (includegroup) ? group->bitmask[includegroup] : 0;
 
   FixShearHistory * const fix_history = list->fix_history;
   NeighList * listgranhistory = list->listgranhistory;
 
   NEIGH_OMP_INIT;
 
-  if (fix_history)
-    if (nthreads > listgranhistory->maxpage)
-      listgranhistory->add_pages(nthreads - listgranhistory->maxpage);
-
 #if defined(_OPENMP)
 #pragma omp parallel default(none) shared(list,listgranhistory)
 #endif
   NEIGH_OMP_SETUP(nlocal);
 
   int i,j,m,n,nn;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   double radi,radsum,cutsq;
   int *neighptr,*touchptr;
   double *shearptr;
 
   int *npartner,**partner;
-  double ***shearpartner;
+  double (**shearpartner)[3];
   int **firsttouch;
   double **firstshear;
+  MyPage<int> *ipage_touch;
+  MyPage<double> *dpage_shear;
 
   double **x = atom->x;
   double *radius = atom->radius;
   int *tag = atom->tag;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int nall = atom->nlocal + atom->nghost;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
 
+  // each thread has its own page allocator
+  MyPage<int> &ipage = list->ipage[tid];
+  ipage.reset();
+
   if (fix_history) {
     npartner = fix_history->npartner;
     partner = fix_history->partner;
     shearpartner = fix_history->shearpartner;
     firsttouch = listgranhistory->firstneigh;
     firstshear = listgranhistory->firstdouble;
+    ipage_touch = listgranhistory->ipage+tid;
+    dpage_shear = listgranhistory->dpage+tid;
+    ipage_touch->reset();
+    dpage_shear->reset();
   }
 
-  int npage = tid;
-  int npnt = 0;
-
   for (i = ifrom; i < ito; i++) {
 
-#if defined(_OPENMP)
-#pragma omp critical
-#endif
-    {
-      if (pgsize - npnt < oneatom) {
-        npnt = 0;
-        npage += nthreads;
-        if (npage >= list->maxpage) {
-          list->add_pages(nthreads);
-          if (fix_history)
-            listgranhistory->add_pages(nthreads);
-        }
-      }
-
-      n = nn = 0;
-      neighptr = &(list->pages[npage][npnt]);
-      if (fix_history) {
-        touchptr = &(listgranhistory->pages[npage][npnt]);
-        shearptr = &(listgranhistory->dpages[npage][3*npnt]);
-      }
+    n = 0;
+    neighptr = ipage.vget();
+    if (fix_history) {
+      nn = 0;
+      touchptr = ipage_touch->vget();
+      shearptr = dpage_shear->vget();
     }
-
+    
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
     radi = radius[i];
 
     // loop over remaining atoms, owned and ghost
 
     for (j = i+1; j < nall; j++) {
       if (includegroup && !(mask[j] & bitmask)) continue;
       if (exclude && exclusion(i,j,type[i],type[j],mask,molecule)) continue;
 
       delx = xtmp - x[j][0];
       dely = ytmp - x[j][1];
       delz = ztmp - x[j][2];
       rsq = delx*delx + dely*dely + delz*delz;
       radsum = radi + radius[j];
       cutsq = (radsum+skin) * (radsum+skin);
 
       if (rsq <= cutsq) {
         neighptr[n] = j;
 
         if (fix_history) {
           if (rsq < radsum*radsum) {
             for (m = 0; m < npartner[i]; m++)
               if (partner[i][m] == tag[j]) break;
             if (m < npartner[i]) {
               touchptr[n] = 1;
               shearptr[nn++] = shearpartner[i][m][0];
               shearptr[nn++] = shearpartner[i][m][1];
               shearptr[nn++] = shearpartner[i][m][2];
             } else {
               touchptr[n] = 0;
               shearptr[nn++] = 0.0;
               shearptr[nn++] = 0.0;
               shearptr[nn++] = 0.0;
             }
           } else {
             touchptr[n] = 0;
             shearptr[nn++] = 0.0;
             shearptr[nn++] = 0.0;
             shearptr[nn++] = 0.0;
           }
         }
 
         n++;
       }
     }
 
     ilist[i] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
+    ipage.vgot(n);
+    if (ipage.status())
+      error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
+
     if (fix_history) {
       firsttouch[i] = touchptr;
       firstshear[i] = shearptr;
+      ipage_touch->vgot(n);
+      dpage_shear->vgot(nn);
     }
-    npnt += n;
-    if (n > oneatom)
-      error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
   NEIGH_OMP_CLOSE;
   list->inum = nlocal;
 }
 
 /* ----------------------------------------------------------------------
    granular particles
    N^2 / 2 search for neighbor pairs with full Newton's 3rd law
    no shear history is allowed for this option
    pair added to list if atoms i and j are both owned and i < j
    if j is ghost only me or other proc adds pair
    decision based on itag,jtag tests
 ------------------------------------------------------------------------- */
 
 void Neighbor::granular_nsq_newton_omp(NeighList *list)
 {
   const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal;
   const int bitmask = (includegroup) ? group->bitmask[includegroup] : 0;
 
   NEIGH_OMP_INIT;
 #if defined(_OPENMP)
 #pragma omp parallel default(none) shared(list)
 #endif
   NEIGH_OMP_SETUP(nlocal);
 
   int i,j,n,itag,jtag;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   double radi,radsum,cutsq;
   int *neighptr;
 
   double **x = atom->x;
   double *radius = atom->radius;
   int *tag = atom->tag;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int nall = atom->nlocal + atom->nghost;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
 
-  int npage = tid;
-  int npnt = 0;
+  // each thread has its own page allocator
+  MyPage<int> &ipage = list->ipage[tid];
+  ipage.reset();
 
   for (i = ifrom; i < ito; i++) {
 
-#if defined(_OPENMP)
-#pragma omp critical
-#endif
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage += nthreads;
-      if (npage >= list->maxpage) list->add_pages(nthreads);
-    }
-
-    neighptr = &(list->pages[npage][npnt]);
     n = 0;
+    neighptr = ipage.vget();
 
     itag = tag[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
     radi = radius[i];
 
     // loop over remaining atoms, owned and ghost
 
     for (j = i+1; j < nall; j++) {
       if (includegroup && !(mask[j] & bitmask)) continue;
 
       if (j >= nlocal) {
         jtag = tag[j];
         if (itag > jtag) {
           if ((itag+jtag) % 2 == 0) continue;
         } else if (itag < jtag) {
           if ((itag+jtag) % 2 == 1) continue;
         } else {
           if (x[j][2] < ztmp) continue;
           if (x[j][2] == ztmp) {
             if (x[j][1] < ytmp) continue;
             if (x[j][1] == ytmp && x[j][0] < xtmp) continue;
           }
         }
       }
 
       if (exclude && exclusion(i,j,type[i],type[j],mask,molecule)) continue;
 
       delx = xtmp - x[j][0];
       dely = ytmp - x[j][1];
       delz = ztmp - x[j][2];
       rsq = delx*delx + dely*dely + delz*delz;
       radsum = radi + radius[j];
       cutsq = (radsum+skin) * (radsum+skin);
 
       if (rsq <= cutsq) neighptr[n++] = j;
     }
 
     ilist[i] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage.vgot(n);
+    if (ipage.status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
   NEIGH_OMP_CLOSE;
   list->inum = nlocal;
 }
 
 /* ----------------------------------------------------------------------
    granular particles
    binned neighbor list construction with partial Newton's 3rd law
    shear history must be accounted for when a neighbor pair is added
    each owned atom i checks own bin and surrounding bins in non-Newton stencil
    pair stored once if i,j are both owned and i < j
    pair stored by me if j is ghost (also stored by proc owning j)
 ------------------------------------------------------------------------- */
 
 void Neighbor::granular_bin_no_newton_omp(NeighList *list)
 {
   // bin local & ghost atoms
 
   bin_atoms();
 
   const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal;
 
   FixShearHistory * const fix_history = list->fix_history;
   NeighList * listgranhistory = list->listgranhistory;
 
   NEIGH_OMP_INIT;
 
-  if (fix_history)
-    if (nthreads > listgranhistory->maxpage)
-      listgranhistory->add_pages(nthreads - listgranhistory->maxpage);
-
 #if defined(_OPENMP)
 #pragma omp parallel default(none) shared(list,listgranhistory)
 #endif
   NEIGH_OMP_SETUP(nlocal);
 
   int i,j,k,m,n,nn,ibin;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   double radi,radsum,cutsq;
   int *neighptr,*touchptr;
   double *shearptr;
+  MyPage<int> *ipage_touch;
+  MyPage<double> *dpage_shear;
 
   int *npartner,**partner;
-  double ***shearpartner;
+  double (**shearpartner)[3];
   int **firsttouch;
   double **firstshear;
 
   // loop over each atom, storing neighbors
 
   double **x = atom->x;
   double *radius = atom->radius;
   int *tag = atom->tag;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
   int nstencil = list->nstencil;
   int *stencil = list->stencil;
 
+  // each thread has its own page allocator
+  MyPage<int> &ipage = list->ipage[tid];
+  ipage.reset();
+
   if (fix_history) {
     npartner = fix_history->npartner;
     partner = fix_history->partner;
     shearpartner = fix_history->shearpartner;
     firsttouch = listgranhistory->firstneigh;
     firstshear = listgranhistory->firstdouble;
+    ipage_touch = listgranhistory->ipage+tid;
+    dpage_shear = listgranhistory->dpage+tid;
+    ipage_touch->reset();
+    dpage_shear->reset();
   }
 
-  int npage = tid;
-  int npnt = 0;
-
   for (i = ifrom; i < ito; i++) {
 
-#if defined(_OPENMP)
-#pragma omp critical
-#endif
-    {
-      if (pgsize - npnt < oneatom) {
-        npnt = 0;
-        npage += nthreads;
-        if (npage >= list->maxpage) {
-          list->add_pages(nthreads);
-          if (fix_history)
-            listgranhistory->add_pages(nthreads);
-        }
-      }
-
-      n = nn = 0;
-      neighptr = &(list->pages[npage][npnt]);
-      if (fix_history) {
-        touchptr = &(listgranhistory->pages[npage][npnt]);
-        shearptr = &(listgranhistory->dpages[npage][3*npnt]);
-      }
+    n = 0;
+    neighptr = ipage.vget();
+    if (fix_history) {
+      nn = 0;
+      touchptr = ipage_touch->vget();
+      shearptr = dpage_shear->vget();
     }
 
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
     radi = radius[i];
     ibin = coord2bin(x[i]);
 
     // loop over all atoms in surrounding bins in stencil including self
     // only store pair if i < j
     // stores own/own pairs only once
     // stores own/ghost pairs on both procs
 
     for (k = 0; k < nstencil; k++) {
       for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
         if (j <= i) continue;
         if (exclude && exclusion(i,j,type[i],type[j],mask,molecule)) continue;
 
         delx = xtmp - x[j][0];
         dely = ytmp - x[j][1];
         delz = ztmp - x[j][2];
         rsq = delx*delx + dely*dely + delz*delz;
         radsum = radi + radius[j];
         cutsq = (radsum+skin) * (radsum+skin);
 
         if (rsq <= cutsq) {
           neighptr[n] = j;
 
           if (fix_history) {
             if (rsq < radsum*radsum) {
               for (m = 0; m < npartner[i]; m++)
                 if (partner[i][m] == tag[j]) break;
               if (m < npartner[i]) {
                 touchptr[n] = 1;
                 shearptr[nn++] = shearpartner[i][m][0];
                 shearptr[nn++] = shearpartner[i][m][1];
                 shearptr[nn++] = shearpartner[i][m][2];
               } else {
                 touchptr[n] = 0;
                 shearptr[nn++] = 0.0;
                 shearptr[nn++] = 0.0;
                 shearptr[nn++] = 0.0;
               }
             } else {
               touchptr[n] = 0;
               shearptr[nn++] = 0.0;
               shearptr[nn++] = 0.0;
               shearptr[nn++] = 0.0;
             }
           }
 
           n++;
         }
       }
     }
 
     ilist[i] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
+    ipage.vgot(n);
+    if (ipage.status())
+      error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
+
     if (fix_history) {
       firsttouch[i] = touchptr;
       firstshear[i] = shearptr;
+      ipage_touch->vgot(n);
+      dpage_shear->vgot(nn);
     }
-    npnt += n;
-    if (n > oneatom)
-      error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
   NEIGH_OMP_CLOSE;
   list->inum = nlocal;
 }
 
 /* ----------------------------------------------------------------------
    granular particles
    binned neighbor list construction with full Newton's 3rd law
    no shear history is allowed for this option
    each owned atom i checks its own bin and other bins in Newton stencil
    every pair stored exactly once by some processor
 ------------------------------------------------------------------------- */
 
 void Neighbor::granular_bin_newton_omp(NeighList *list)
 {
   // bin local & ghost atoms
 
   bin_atoms();
 
   const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal;
 
   NEIGH_OMP_INIT;
 #if defined(_OPENMP)
 #pragma omp parallel default(none) shared(list)
 #endif
   NEIGH_OMP_SETUP(nlocal);
 
   int i,j,k,n,ibin;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   double radi,radsum,cutsq;
   int *neighptr;
 
   // loop over each atom, storing neighbors
 
   double **x = atom->x;
   double *radius = atom->radius;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
   int nstencil = list->nstencil;
   int *stencil = list->stencil;
 
-  int npage = tid;
-  int npnt = 0;
+  // each thread has its own page allocator
+  MyPage<int> &ipage = list->ipage[tid];
+  ipage.reset();
 
   for (i = ifrom; i < ito; i++) {
 
-#if defined(_OPENMP)
-#pragma omp critical
-#endif
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage += nthreads;
-      if (npage >= list->maxpage) list->add_pages(nthreads);
-    }
-
     n = 0;
-    neighptr = &(list->pages[npage][npnt]);
+    neighptr = ipage.vget();
 
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
     radi = radius[i];
 
     // loop over rest of atoms in i's bin, ghosts are at end of linked list
     // if j is owned atom, store it, since j is beyond i in linked list
     // if j is ghost, only store if j coords are "above and to the right" of i
 
     for (j = bins[i]; j >= 0; j = bins[j]) {
       if (j >= nlocal) {
         if (x[j][2] < ztmp) continue;
         if (x[j][2] == ztmp) {
           if (x[j][1] < ytmp) continue;
           if (x[j][1] == ytmp && x[j][0] < xtmp) continue;
         }
       }
 
       if (exclude && exclusion(i,j,type[i],type[j],mask,molecule)) continue;
 
       delx = xtmp - x[j][0];
       dely = ytmp - x[j][1];
       delz = ztmp - x[j][2];
       rsq = delx*delx + dely*dely + delz*delz;
       radsum = radi + radius[j];
       cutsq = (radsum+skin) * (radsum+skin);
 
       if (rsq <= cutsq) neighptr[n++] = j;
     }
 
     // loop over all atoms in other bins in stencil, store every pair
 
     ibin = coord2bin(x[i]);
     for (k = 0; k < nstencil; k++) {
       for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
         if (exclude && exclusion(i,j,type[i],type[j],mask,molecule)) continue;
 
         delx = xtmp - x[j][0];
         dely = ytmp - x[j][1];
         delz = ztmp - x[j][2];
         rsq = delx*delx + dely*dely + delz*delz;
         radsum = radi + radius[j];
         cutsq = (radsum+skin) * (radsum+skin);
 
         if (rsq <= cutsq) neighptr[n++] = j;
       }
     }
 
     ilist[i] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage.vgot(n);
+    if (ipage.status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
   NEIGH_OMP_CLOSE;
   list->inum = nlocal;
 }
 
 /* ----------------------------------------------------------------------
    granular particles
    binned neighbor list construction with Newton's 3rd law for triclinic
    no shear history is allowed for this option
    each owned atom i checks its own bin and other bins in triclinic stencil
    every pair stored exactly once by some processor
 ------------------------------------------------------------------------- */
 
 void Neighbor::granular_bin_newton_tri_omp(NeighList *list)
 {
   // bin local & ghost atoms
 
   bin_atoms();
 
   const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal;
 
   NEIGH_OMP_INIT;
 #if defined(_OPENMP)
 #pragma omp parallel default(none) shared(list)
 #endif
   NEIGH_OMP_SETUP(nlocal);
 
   int i,j,k,n,ibin;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   double radi,radsum,cutsq;
   int *neighptr;
 
   // loop over each atom, storing neighbors
 
   double **x = atom->x;
   double *radius = atom->radius;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
   int nstencil = list->nstencil;
   int *stencil = list->stencil;
 
-  int npage = tid;
-  int npnt = 0;
+  // each thread has its own page allocator
+  MyPage<int> &ipage = list->ipage[tid];
+  ipage.reset();
 
   for (i = ifrom; i < ito; i++) {
 
-#if defined(_OPENMP)
-#pragma omp critical
-#endif
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage += nthreads;
-      if (npage >= list->maxpage) list->add_pages(nthreads);
-    }
-
     n = 0;
-    neighptr = &(list->pages[npage][npnt]);
+    neighptr = ipage.vget();
 
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
     radi = radius[i];
 
     // loop over all atoms in bins in stencil
     // pairs for atoms j "below" i are excluded
     // below = lower z or (equal z and lower y) or (equal zy and lower x)
     //         (equal zyx and j <= i)
     // latter excludes self-self interaction but allows superposed atoms
 
     ibin = coord2bin(x[i]);
     for (k = 0; k < nstencil; k++) {
       for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
         if (x[j][2] < ztmp) continue;
         if (x[j][2] == ztmp) {
           if (x[j][1] < ytmp) continue;
           if (x[j][1] == ytmp) {
             if (x[j][0] < xtmp) continue;
             if (x[j][0] == xtmp && j <= i) continue;
           }
         }
 
         if (exclude && exclusion(i,j,type[i],type[j],mask,molecule)) continue;
 
         delx = xtmp - x[j][0];
         dely = ytmp - x[j][1];
         delz = ztmp - x[j][2];
         rsq = delx*delx + dely*dely + delz*delz;
         radsum = radi + radius[j];
         cutsq = (radsum+skin) * (radsum+skin);
 
         if (rsq <= cutsq) neighptr[n++] = j;
       }
     }
 
     ilist[i] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage.vgot(n);
+    if (ipage.status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
   NEIGH_OMP_CLOSE;
   list->inum = nlocal;
 }
diff --git a/src/USER-OMP/neigh_half_bin_omp.cpp b/src/USER-OMP/neigh_half_bin_omp.cpp
index ba0a18041..f501684a1 100644
--- a/src/USER-OMP/neigh_half_bin_omp.cpp
+++ b/src/USER-OMP/neigh_half_bin_omp.cpp
@@ -1,522 +1,487 @@
 /* ----------------------------------------------------------------------
    LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
    http://lammps.sandia.gov, Sandia National Laboratories
    Steve Plimpton, sjplimp@sandia.gov
 
    Copyright (2003) Sandia Corporation.  Under the terms of Contract
    DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
    certain rights in this software.  This software is distributed under
    the GNU General Public License.
 
    See the README file in the top-level LAMMPS directory.
 ------------------------------------------------------------------------- */
 
 #include "neighbor.h"
 #include "neighbor_omp.h"
 #include "neigh_list.h"
 #include "atom.h"
 #include "comm.h"
 #include "domain.h"
+#include "my_page.h"
 #include "error.h"
 
 using namespace LAMMPS_NS;
 
 /* ----------------------------------------------------------------------
    binned neighbor list construction with partial Newton's 3rd law
    each owned atom i checks own bin and other bins in stencil
    pair stored once if i,j are both owned and i < j
    pair stored by me if j is ghost (also stored by proc owning j)
 ------------------------------------------------------------------------- */
 
 void Neighbor::half_bin_no_newton_omp(NeighList *list)
 {
   // bin local & ghost atoms
 
   bin_atoms();
 
   const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal;
 
   NEIGH_OMP_INIT;
 #if defined(_OPENMP)
 #pragma omp parallel default(none) shared(list)
 #endif
   NEIGH_OMP_SETUP(nlocal);
 
   int i,j,k,n,itype,jtype,ibin,which;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int *neighptr;
 
   // loop over each atom, storing neighbors
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int molecular = atom->molecular;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
   int nstencil = list->nstencil;
   int *stencil = list->stencil;
 
-  // each thread works on its own page
-  int npage = tid;
-  int npnt = 0;
+  // each thread has its own page allocator
+  MyPage<int> &ipage = list->ipage[tid];
+  ipage.reset();
 
   for (i = ifrom; i < ito; i++) {
 
-#if defined(_OPENMP)
-#pragma omp critical
-#endif
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage += nthreads;
-      if (npage >= list->maxpage) list->add_pages(nthreads);
-    }
-
-    neighptr = &(list->pages[npage][npnt]);
     n = 0;
+    neighptr = ipage.vget();
 
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over all atoms in other bins in stencil including self
     // only store pair if i < j
     // stores own/own pairs only once
     // stores own/ghost pairs on both procs
 
     ibin = coord2bin(x[i]);
 
     for (k = 0; k < nstencil; k++) {
       for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
         if (j <= i) continue;
 
         jtype = type[j];
         if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
         delx = xtmp - x[j][0];
         dely = ytmp - x[j][1];
         delz = ztmp - x[j][2];
         rsq = delx*delx + dely*dely + delz*delz;
 
         if (rsq <= cutneighsq[itype][jtype]) {
           if (molecular) {
             which = find_special(special[i],nspecial[i],tag[j]);
             if (which == 0) neighptr[n++] = j;
             else if (domain->minimum_image_check(delx,dely,delz))
               neighptr[n++] = j;
             else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
           } else neighptr[n++] = j;
         }
       }
     }
 
     ilist[i] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage.vgot(n);
+    if (ipage.status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
   NEIGH_OMP_CLOSE;
   list->inum = nlocal;
 }
 
 /* ----------------------------------------------------------------------
    binned neighbor list construction with partial Newton's 3rd law
    include neighbors of ghost atoms, but no "special neighbors" for ghosts
    owned and ghost atoms check own bin and other bins in stencil
    pair stored once if i,j are both owned and i < j
    pair stored by me if i owned and j ghost (also stored by proc owning j)
    pair stored once if i,j are both ghost and i < j
 ------------------------------------------------------------------------- */
 
 void Neighbor::half_bin_no_newton_ghost_omp(NeighList *list)
 {
   const int nlocal = atom->nlocal;
   const int nall = nlocal + atom->nghost;
 
   NEIGH_OMP_INIT;
 #if defined(_OPENMP)
 #pragma omp parallel default(none) shared(list)
 #endif
   NEIGH_OMP_SETUP(nall);
 
   int i,j,k,n,itype,jtype,ibin,which;
   int xbin,ybin,zbin,xbin2,ybin2,zbin2;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int *neighptr;
 
   // bin local & ghost atoms
 
   bin_atoms();
 
   // loop over each atom, storing neighbors
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int molecular = atom->molecular;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
   int nstencil = list->nstencil;
   int *stencil = list->stencil;
   int **stencilxyz = list->stencilxyz;
 
-  // each thread works on its own page
-  int npage = tid;
-  int npnt = 0;
+  // each thread has its own page allocator
+  MyPage<int> &ipage = list->ipage[tid];
+  ipage.reset();
 
   for (i = ifrom; i < ito; i++) {
 
-#if defined(_OPENMP)
-#pragma omp critical
-#endif
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage += nthreads;
-      if (npage >= list->maxpage) list->add_pages(nthreads);
-    }
-
-    neighptr = &(list->pages[npage][npnt]);
     n = 0;
+    neighptr = ipage.vget();
 
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over all atoms in other bins in stencil including self
     // when i is a ghost atom, must check if stencil bin is out of bounds
     // only store pair if i < j
     // stores own/own pairs only once
     // stores own/ghost pairs with owned atom only, on both procs
     // stores ghost/ghost pairs only once
     // no molecular test when i = ghost atom
 
     if (i < nlocal) {
       ibin = coord2bin(x[i]);
 
       for (k = 0; k < nstencil; k++) {
         for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
           if (j <= i) continue;
 
           jtype = type[j];
           if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
           delx = xtmp - x[j][0];
           dely = ytmp - x[j][1];
           delz = ztmp - x[j][2];
           rsq = delx*delx + dely*dely + delz*delz;
 
           if (rsq <= cutneighsq[itype][jtype]) {
             if (molecular) {
               which = find_special(special[i],nspecial[i],tag[j]);
               if (which == 0) neighptr[n++] = j;
               else if (domain->minimum_image_check(delx,dely,delz))
                 neighptr[n++] = j;
               else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
             } else neighptr[n++] = j;
           }
         }
       }
 
     } else {
       ibin = coord2bin(x[i],xbin,ybin,zbin);
       for (k = 0; k < nstencil; k++) {
         xbin2 = xbin + stencilxyz[k][0];
         ybin2 = ybin + stencilxyz[k][1];
         zbin2 = zbin + stencilxyz[k][2];
         if (xbin2 < 0 || xbin2 >= mbinx ||
             ybin2 < 0 || ybin2 >= mbiny ||
             zbin2 < 0 || zbin2 >= mbinz) continue;
         for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
           if (j <= i) continue;
 
           jtype = type[j];
           if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
           delx = xtmp - x[j][0];
           dely = ytmp - x[j][1];
           delz = ztmp - x[j][2];
           rsq = delx*delx + dely*dely + delz*delz;
 
           if (rsq <= cutneighghostsq[itype][jtype]) neighptr[n++] = j;
         }
       }
     }
 
     ilist[i] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage.vgot(n);
+    if (ipage.status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
   NEIGH_OMP_CLOSE;
   list->inum = nlocal;
   list->gnum = nall - atom->nlocal;
 }
 
 /* ----------------------------------------------------------------------
    binned neighbor list construction with full Newton's 3rd law
    each owned atom i checks its own bin and other bins in Newton stencil
    every pair stored exactly once by some processor
 ------------------------------------------------------------------------- */
 
 void Neighbor::half_bin_newton_omp(NeighList *list)
 {
   // bin local & ghost atoms
 
   bin_atoms();
 
   const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal;
 
   NEIGH_OMP_INIT;
 #if defined(_OPENMP)
 #pragma omp parallel default(none) shared(list)
 #endif
   NEIGH_OMP_SETUP(nlocal);
 
   int i,j,k,n,itype,jtype,ibin,which;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int *neighptr;
 
   // loop over each atom, storing neighbors
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int molecular = atom->molecular;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
   int nstencil = list->nstencil;
   int *stencil = list->stencil;
 
-  // each thread works on its own page
-  int npage = tid;
-  int npnt = 0;
+  // each thread has its own page allocator
+  MyPage<int> &ipage = list->ipage[tid];
+  ipage.reset();
 
   for (i = ifrom; i < ito; i++) {
 
-#if defined(_OPENMP)
-#pragma omp critical
-#endif
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage += nthreads;
-      if (npage >= list->maxpage) list->add_pages(nthreads);
-    }
-
-    neighptr = &(list->pages[npage][npnt]);
     n = 0;
+    neighptr = ipage.vget();
 
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over rest of atoms in i's bin, ghosts are at end of linked list
     // if j is owned atom, store it, since j is beyond i in linked list
     // if j is ghost, only store if j coords are "above and to the right" of i
 
     for (j = bins[i]; j >= 0; j = bins[j]) {
       if (j >= nlocal) {
         if (x[j][2] < ztmp) continue;
         if (x[j][2] == ztmp) {
           if (x[j][1] < ytmp) continue;
           if (x[j][1] == ytmp && x[j][0] < xtmp) continue;
         }
       }
 
       jtype = type[j];
       if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
       delx = xtmp - x[j][0];
       dely = ytmp - x[j][1];
       delz = ztmp - x[j][2];
       rsq = delx*delx + dely*dely + delz*delz;
 
       if (rsq <= cutneighsq[itype][jtype]) {
         if (molecular) {
           which = find_special(special[i],nspecial[i],tag[j]);
           if (which == 0) neighptr[n++] = j;
           else if (domain->minimum_image_check(delx,dely,delz))
             neighptr[n++] = j;
           else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
           // OLD: if (which >= 0) neighptr[n++] = j ^ (which << SBBITS);
         } else neighptr[n++] = j;
       }
     }
 
     // loop over all atoms in other bins in stencil, store every pair
 
     ibin = coord2bin(x[i]);
     for (k = 0; k < nstencil; k++) {
       for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
         jtype = type[j];
         if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
         delx = xtmp - x[j][0];
         dely = ytmp - x[j][1];
         delz = ztmp - x[j][2];
         rsq = delx*delx + dely*dely + delz*delz;
 
         if (rsq <= cutneighsq[itype][jtype]) {
           if (molecular) {
             which = find_special(special[i],nspecial[i],tag[j]);
             if (which == 0) neighptr[n++] = j;
             else if (domain->minimum_image_check(delx,dely,delz))
               neighptr[n++] = j;
             else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
             // OLD: if (which >= 0) neighptr[n++] = j ^ (which << SBBITS);
           } else neighptr[n++] = j;
         }
       }
     }
 
     ilist[i] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage.vgot(n);
+    if (ipage.status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
   NEIGH_OMP_CLOSE;
   list->inum = nlocal;
 }
 
 /* ----------------------------------------------------------------------
    binned neighbor list construction with Newton's 3rd law for triclinic
    each owned atom i checks its own bin and other bins in triclinic stencil
    every pair stored exactly once by some processor
 ------------------------------------------------------------------------- */
 
 void Neighbor::half_bin_newton_tri_omp(NeighList *list)
 {
   // bin local & ghost atoms
 
   bin_atoms();
 
   const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal;
 
   NEIGH_OMP_INIT;
 #if defined(_OPENMP)
 #pragma omp parallel default(none) shared(list)
 #endif
   NEIGH_OMP_SETUP(nlocal);
 
   int i,j,k,n,itype,jtype,ibin,which;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int *neighptr;
 
   // loop over each atom, storing neighbors
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int molecular = atom->molecular;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
   int nstencil = list->nstencil;
   int *stencil = list->stencil;
 
-  // each thread works on its own page
-  int npage = tid;
-  int npnt = 0;
+  // each thread has its own page allocator
+  MyPage<int> &ipage = list->ipage[tid];
+  ipage.reset();
 
   for (i = ifrom; i < ito; i++) {
 
-#if defined(_OPENMP)
-#pragma omp critical
-#endif
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage += nthreads;
-      if (npage >= list->maxpage) list->add_pages(nthreads);
-    }
-
-    neighptr = &(list->pages[npage][npnt]);
     n = 0;
+    neighptr = ipage.vget();
 
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over all atoms in bins in stencil
     // pairs for atoms j "below" i are excluded
     // below = lower z or (equal z and lower y) or (equal zy and lower x)
     //         (equal zyx and j <= i)
     // latter excludes self-self interaction but allows superposed atoms
 
     ibin = coord2bin(x[i]);
     for (k = 0; k < nstencil; k++) {
       for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
         if (x[j][2] < ztmp) continue;
         if (x[j][2] == ztmp) {
           if (x[j][1] < ytmp) continue;
           if (x[j][1] == ytmp) {
             if (x[j][0] < xtmp) continue;
             if (x[j][0] == xtmp && j <= i) continue;
           }
         }
 
         jtype = type[j];
         if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
         delx = xtmp - x[j][0];
         dely = ytmp - x[j][1];
         delz = ztmp - x[j][2];
         rsq = delx*delx + dely*dely + delz*delz;
 
         if (rsq <= cutneighsq[itype][jtype]) {
           if (molecular) {
             which = find_special(special[i],nspecial[i],tag[j]);
             if (which == 0) neighptr[n++] = j;
             else if (domain->minimum_image_check(delx,dely,delz))
               neighptr[n++] = j;
             else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
           } else neighptr[n++] = j;
         }
       }
     }
 
     ilist[i] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage.vgot(n);
+    if (ipage.status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
   NEIGH_OMP_CLOSE;
   list->inum = nlocal;
 }
diff --git a/src/USER-OMP/neigh_half_multi_omp.cpp b/src/USER-OMP/neigh_half_multi_omp.cpp
index 5cc6ba140..b46594870 100644
--- a/src/USER-OMP/neigh_half_multi_omp.cpp
+++ b/src/USER-OMP/neigh_half_multi_omp.cpp
@@ -1,405 +1,379 @@
 /* ----------------------------------------------------------------------
    LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
    http://lammps.sandia.gov, Sandia National Laboratories
    Steve Plimpton, sjplimp@sandia.gov
 
    Copyright (2003) Sandia Corporation.  Under the terms of Contract
    DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
    certain rights in this software.  This software is distributed under
    the GNU General Public License.
 
    See the README file in the top-level LAMMPS directory.
 ------------------------------------------------------------------------- */
 
 #include "neighbor.h"
 #include "neighbor_omp.h"
 #include "neigh_list.h"
 #include "atom.h"
 #include "comm.h"
 #include "domain.h"
+#include "my_page.h"
 #include "error.h"
 
 using namespace LAMMPS_NS;
 
 /* ----------------------------------------------------------------------
    binned neighbor list construction with partial Newton's 3rd law
    each owned atom i checks own bin and other bins in stencil
    multi-type stencil is itype dependent and is distance checked
    pair stored once if i,j are both owned and i < j
    pair stored by me if j is ghost (also stored by proc owning j)
 ------------------------------------------------------------------------- */
 
 void Neighbor::half_multi_no_newton_omp(NeighList *list)
 {
   // bin local & ghost atoms
 
   bin_atoms();
 
   const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal;
 
   NEIGH_OMP_INIT;
 #if defined(_OPENMP)
 #pragma omp parallel default(none) shared(list)
 #endif
   NEIGH_OMP_SETUP(nlocal);
 
   int i,j,k,n,itype,jtype,ibin,which,ns;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int *neighptr,*s;
   double *cutsq,*distsq;
 
   // loop over each atom, storing neighbors
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int molecular = atom->molecular;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
   int *nstencil_multi = list->nstencil_multi;
   int **stencil_multi = list->stencil_multi;
   double **distsq_multi = list->distsq_multi;
 
-  // each thread works on its own page
-  int npage = tid;
-  int npnt = 0;
+  // each thread has its own page allocator
+  MyPage<int> &ipage = list->ipage[tid];
+  ipage.reset();
 
   for (i = ifrom; i < ito; i++) {
 
-#if defined(_OPENMP)
-#pragma omp critical
-#endif
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage += nthreads;
-      if (npage >= list->maxpage) list->add_pages(nthreads);
-    }
-
-    neighptr = &(list->pages[npage][npnt]);
     n = 0;
+    neighptr = ipage.vget();
 
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over all atoms in other bins in stencil including self
     // only store pair if i < j
     // skip if i,j neighbor cutoff is less than bin distance
     // stores own/own pairs only once
     // stores own/ghost pairs on both procs
 
     ibin = coord2bin(x[i]);
     s = stencil_multi[itype];
     distsq = distsq_multi[itype];
     cutsq = cutneighsq[itype];
     ns = nstencil_multi[itype];
     for (k = 0; k < ns; k++) {
       for (j = binhead[ibin+s[k]]; j >= 0; j = bins[j]) {
         if (j <= i) continue;
         jtype = type[j];
         if (cutsq[jtype] < distsq[k]) continue;
 
         if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
         delx = xtmp - x[j][0];
         dely = ytmp - x[j][1];
         delz = ztmp - x[j][2];
         rsq = delx*delx + dely*dely + delz*delz;
 
         if (rsq <= cutneighsq[itype][jtype]) {
           if (molecular) {
             which = find_special(special[i],nspecial[i],tag[j]);
             if (which == 0) neighptr[n++] = j;
             else if (domain->minimum_image_check(delx,dely,delz))
               neighptr[n++] = j;
             else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
           } else neighptr[n++] = j;
         }
       }
     }
 
     ilist[i] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage.vgot(n);
+    if (ipage.status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
   NEIGH_OMP_CLOSE;
   list->inum = nlocal;
 }
 
 /* ----------------------------------------------------------------------
    binned neighbor list construction with full Newton's 3rd law
    each owned atom i checks its own bin and other bins in Newton stencil
    multi-type stencil is itype dependent and is distance checked
    every pair stored exactly once by some processor
 ------------------------------------------------------------------------- */
 
 void Neighbor::half_multi_newton_omp(NeighList *list)
 {
   // bin local & ghost atoms
 
   bin_atoms();
 
   const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal;
 
   NEIGH_OMP_INIT;
 #if defined(_OPENMP)
 #pragma omp parallel default(none) shared(list)
 #endif
   NEIGH_OMP_SETUP(nlocal);
 
   int i,j,k,n,itype,jtype,ibin,which,ns;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int *neighptr,*s;
   double *cutsq,*distsq;
 
   // loop over each atom, storing neighbors
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int molecular = atom->molecular;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
   int *nstencil_multi = list->nstencil_multi;
   int **stencil_multi = list->stencil_multi;
   double **distsq_multi = list->distsq_multi;
 
-  // each thread works on its own page
-  int npage = tid;
-  int npnt = 0;
+  // each thread has its own page allocator
+  MyPage<int> &ipage = list->ipage[tid];
+  ipage.reset();
 
   for (i = ifrom; i < ito; i++) {
 
-#if defined(_OPENMP)
-#pragma omp critical
-#endif
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage += nthreads;
-      if (npage >= list->maxpage) list->add_pages(nthreads);
-    }
-
-    neighptr = &(list->pages[npage][npnt]);
     n = 0;
+    neighptr = ipage.vget();
 
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over rest of atoms in i's bin, ghosts are at end of linked list
     // if j is owned atom, store it, since j is beyond i in linked list
     // if j is ghost, only store if j coords are "above and to the right" of i
 
     for (j = bins[i]; j >= 0; j = bins[j]) {
       if (j >= nlocal) {
         if (x[j][2] < ztmp) continue;
         if (x[j][2] == ztmp) {
           if (x[j][1] < ytmp) continue;
           if (x[j][1] == ytmp && x[j][0] < xtmp) continue;
         }
       }
 
       jtype = type[j];
       if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
       delx = xtmp - x[j][0];
       dely = ytmp - x[j][1];
       delz = ztmp - x[j][2];
       rsq = delx*delx + dely*dely + delz*delz;
 
       if (rsq <= cutneighsq[itype][jtype]) {
         if (molecular) {
           which = find_special(special[i],nspecial[i],tag[j]);
           if (which == 0) neighptr[n++] = j;
           else if (domain->minimum_image_check(delx,dely,delz))
             neighptr[n++] = j;
           else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
         } else neighptr[n++] = j;
       }
     }
 
     // loop over all atoms in other bins in stencil, store every pair
     // skip if i,j neighbor cutoff is less than bin distance
 
     ibin = coord2bin(x[i]);
     s = stencil_multi[itype];
     distsq = distsq_multi[itype];
     cutsq = cutneighsq[itype];
     ns = nstencil_multi[itype];
     for (k = 0; k < ns; k++) {
       for (j = binhead[ibin+s[k]]; j >= 0; j = bins[j]) {
         jtype = type[j];
         if (cutsq[jtype] < distsq[k]) continue;
 
         if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
         delx = xtmp - x[j][0];
         dely = ytmp - x[j][1];
         delz = ztmp - x[j][2];
         rsq = delx*delx + dely*dely + delz*delz;
 
         if (rsq <= cutneighsq[itype][jtype]) {
           if (molecular) {
             which = find_special(special[i],nspecial[i],tag[j]);
             if (which == 0) neighptr[n++] = j;
             else if (domain->minimum_image_check(delx,dely,delz))
               neighptr[n++] = j;
             else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
           } else neighptr[n++] = j;
         }
       }
     }
 
     ilist[i] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage.vgot(n);
+    if (ipage.status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
   NEIGH_OMP_CLOSE;
   list->inum = nlocal;
 }
 
 /* ----------------------------------------------------------------------
    binned neighbor list construction with Newton's 3rd law for triclinic
    each owned atom i checks its own bin and other bins in triclinic stencil
    multi-type stencil is itype dependent and is distance checked
    every pair stored exactly once by some processor
 ------------------------------------------------------------------------- */
 
 void Neighbor::half_multi_newton_tri_omp(NeighList *list)
 {
   // bin local & ghost atoms
 
   bin_atoms();
 
   const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal;
 
   NEIGH_OMP_INIT;
 #if defined(_OPENMP)
 #pragma omp parallel default(none) shared(list)
 #endif
   NEIGH_OMP_SETUP(nlocal);
 
   int i,j,k,n,itype,jtype,ibin,which,ns;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int *neighptr,*s;
   double *cutsq,*distsq;
 
   // loop over each atom, storing neighbors
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int molecular = atom->molecular;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
   int *nstencil_multi = list->nstencil_multi;
   int **stencil_multi = list->stencil_multi;
   double **distsq_multi = list->distsq_multi;
 
-  // each thread works on its own page
-  int npage = tid;
-  int npnt = 0;
+  // each thread has its own page allocator
+  MyPage<int> &ipage = list->ipage[tid];
+  ipage.reset();
 
   for (i = ifrom; i < ito; i++) {
 
-#if defined(_OPENMP)
-#pragma omp critical
-#endif
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage += nthreads;
-      if (npage >= list->maxpage) list->add_pages(nthreads);
-    }
-
-    neighptr = &(list->pages[npage][npnt]);
     n = 0;
+    neighptr = ipage.vget();
 
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over all atoms in bins, including self, in stencil
     // skip if i,j neighbor cutoff is less than bin distance
     // bins below self are excluded from stencil
     // pairs for atoms j "below" i are excluded
     // below = lower z or (equal z and lower y) or (equal zy and lower x)
     //         (equal zyx and j <= i)
     // latter excludes self-self interaction but allows superposed atoms
 
     ibin = coord2bin(x[i]);
     s = stencil_multi[itype];
     distsq = distsq_multi[itype];
     cutsq = cutneighsq[itype];
     ns = nstencil_multi[itype];
     for (k = 0; k < ns; k++) {
       for (j = binhead[ibin+s[k]]; j >= 0; j = bins[j]) {
         jtype = type[j];
         if (cutsq[jtype] < distsq[k]) continue;
         if (x[j][2] < ztmp) continue;
         if (x[j][2] == ztmp) {
           if (x[j][1] < ytmp) continue;
           if (x[j][1] == ytmp) {
             if (x[j][0] < xtmp) continue;
             if (x[j][0] == xtmp && j <= i) continue;
           }
         }
 
         if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
         delx = xtmp - x[j][0];
         dely = ytmp - x[j][1];
         delz = ztmp - x[j][2];
         rsq = delx*delx + dely*dely + delz*delz;
 
         if (rsq <= cutneighsq[itype][jtype]) {
           if (molecular) {
             which = find_special(special[i],nspecial[i],tag[j]);
             if (which == 0) neighptr[n++] = j;
             else if (domain->minimum_image_check(delx,dely,delz))
               neighptr[n++] = j;
             else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
           } else neighptr[n++] = j;
         }
       }
     }
 
     ilist[i] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage.vgot(n);
+    if (ipage.status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
   NEIGH_OMP_CLOSE;
   list->inum = nlocal;
 }
diff --git a/src/USER-OMP/neigh_half_nsq_omp.cpp b/src/USER-OMP/neigh_half_nsq_omp.cpp
index 6a8bee491..a98c4721f 100644
--- a/src/USER-OMP/neigh_half_nsq_omp.cpp
+++ b/src/USER-OMP/neigh_half_nsq_omp.cpp
@@ -1,350 +1,325 @@
 /* ----------------------------------------------------------------------
    LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
    http://lammps.sandia.gov, Sandia National Laboratories
    Steve Plimpton, sjplimp@sandia.gov
 
    Copyright (2003) Sandia Corporation.  Under the terms of Contract
    DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
    certain rights in this software.  This software is distributed under
    the GNU General Public License.
 
    See the README file in the top-level LAMMPS directory.
 ------------------------------------------------------------------------- */
 
 #include "neighbor.h"
 #include "neighbor_omp.h"
 #include "neigh_list.h"
 #include "atom.h"
 #include "comm.h"
 #include "domain.h"
 #include "group.h"
+#include "my_page.h"
 #include "error.h"
 
 using namespace LAMMPS_NS;
 
 /* ----------------------------------------------------------------------
    N^2 / 2 search for neighbor pairs with partial Newton's 3rd law
    pair stored once if i,j are both owned and i < j
    pair stored by me if j is ghost (also stored by proc owning j)
 ------------------------------------------------------------------------- */
 
 void Neighbor::half_nsq_no_newton_omp(NeighList *list)
 {
   const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal;
   const int bitmask = (includegroup) ? group->bitmask[includegroup] : 0;
   const int nall = atom->nlocal + atom->nghost;
 
   NEIGH_OMP_INIT;
 #if defined(_OPENMP)
 #pragma omp parallel default(none) shared(list)
 #endif
   NEIGH_OMP_SETUP(nlocal);
 
   int i,j,n,itype,jtype,which;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int *neighptr;
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int molecular = atom->molecular;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
 
-  // each thread works on its own page
-  int npage = tid;
-  int npnt = 0;
+  // each thread has its own page allocator
+  MyPage<int> &ipage = list->ipage[tid];
+  ipage.reset();
 
   // loop over owned atoms, storing neighbors
 
   for (i = ifrom; i < ito; i++) {
 
-#if defined(_OPENMP)
-#pragma omp critical
-#endif
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage += nthreads;
-      if (npage >= list->maxpage) list->add_pages(nthreads);
-    }
-
-    neighptr = &(list->pages[npage][npnt]);
     n = 0;
+    neighptr = ipage.vget();
 
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over remaining atoms, owned and ghost
     // only store pair if i < j
 
     for (j = i+1; j < nall; j++) {
       if (includegroup && !(mask[j] & bitmask)) continue;
       jtype = type[j];
       if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
       delx = xtmp - x[j][0];
       dely = ytmp - x[j][1];
       delz = ztmp - x[j][2];
       rsq = delx*delx + dely*dely + delz*delz;
 
       if (rsq <= cutneighsq[itype][jtype]) {
         if (molecular) {
           which = find_special(special[i],nspecial[i],tag[j]);
           if (which == 0) neighptr[n++] = j;
           else if (domain->minimum_image_check(delx,dely,delz))
             neighptr[n++] = j;
           else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
         } else neighptr[n++] = j;
       }
     }
 
     ilist[i] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage.vgot(n);
+    if (ipage.status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
   NEIGH_OMP_CLOSE;
   list->inum = nlocal;
 }
 
 /* ----------------------------------------------------------------------
    N^2 / 2 search for neighbor pairs with partial Newton's 3rd law
    include neighbors of ghost atoms, but no "special neighbors" for ghosts
    pair stored once if i,j are both owned and i < j
    pair stored by me if i owned and j ghost (also stored by proc owning j)
    pair stored once if i,j are both ghost and i < j
 ------------------------------------------------------------------------- */
 
 void Neighbor::half_nsq_no_newton_ghost_omp(NeighList *list)
 {
   const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal;
   const int bitmask = (includegroup) ? group->bitmask[includegroup] : 0;
   const int nall = nlocal + atom->nghost;
 
   NEIGH_OMP_INIT;
 #if defined(_OPENMP)
 #pragma omp parallel default(none) shared(list)
 #endif
   NEIGH_OMP_SETUP(nall);
 
   int i,j,n,itype,jtype,which;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int *neighptr;
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int molecular = atom->molecular;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
 
-  // each thread works on its own page
-  int npage = tid;
-  int npnt = 0;
+  // each thread has its own page allocator
+  MyPage<int> &ipage = list->ipage[tid];
+  ipage.reset();
 
   // loop over owned & ghost atoms, storing neighbors
 
   for (i = ifrom; i < ito; i++) {
 
-#if defined(_OPENMP)
-#pragma omp critical
-#endif
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage += nthreads;
-      if (npage >= list->maxpage) list->add_pages(nthreads);
-    }
-
-    neighptr = &(list->pages[npage][npnt]);
     n = 0;
+    neighptr = ipage.vget();
 
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over remaining atoms, owned and ghost
     // only store pair if i < j
     // stores own/own pairs only once
     // stores own/ghost pairs with owned atom only, on both procs
     // stores ghost/ghost pairs only once
     // no molecular test when i = ghost atom
 
     if (i < nlocal) {
       for (j = i+1; j < nall; j++) {
         if (includegroup && !(mask[j] & bitmask)) continue;
         jtype = type[j];
         if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
         delx = xtmp - x[j][0];
         dely = ytmp - x[j][1];
         delz = ztmp - x[j][2];
         rsq = delx*delx + dely*dely + delz*delz;
 
         if (rsq <= cutneighsq[itype][jtype]) {
           if (molecular) {
             which = find_special(special[i],nspecial[i],tag[j]);
             if (which == 0) neighptr[n++] = j;
             else if (domain->minimum_image_check(delx,dely,delz))
               neighptr[n++] = j;
             else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
           } else neighptr[n++] = j;
         }
       }
 
     } else {
       for (j = i+1; j < nall; j++) {
         if (includegroup && !(mask[j] & bitmask)) continue;
         jtype = type[j];
         if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
         delx = xtmp - x[j][0];
         dely = ytmp - x[j][1];
         delz = ztmp - x[j][2];
         rsq = delx*delx + dely*dely + delz*delz;
 
         if (rsq <= cutneighsq[itype][jtype]) neighptr[n++] = j;
       }
     }
 
     ilist[i] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage.vgot(n);
+    if (ipage.status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
   NEIGH_OMP_CLOSE;
   list->inum = atom->nlocal;
   list->gnum = nall - atom->nlocal;
 }
 
 /* ----------------------------------------------------------------------
    N^2 / 2 search for neighbor pairs with full Newton's 3rd law
    every pair stored exactly once by some processor
    decision on ghost atoms based on itag,jtag tests
 ------------------------------------------------------------------------- */
 
 void Neighbor::half_nsq_newton_omp(NeighList *list)
 {
   const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal;
   const int bitmask = (includegroup) ? group->bitmask[includegroup] : 0;
 
   NEIGH_OMP_INIT;
 #if defined(_OPENMP)
 #pragma omp parallel default(none) shared(list)
 #endif
   NEIGH_OMP_SETUP(nlocal);
 
   int i,j,n,itype,jtype,itag,jtag,which;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int *neighptr;
 
   // loop over each atom, storing neighbors
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int nall = atom->nlocal + atom->nghost;
   int molecular = atom->molecular;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
 
-  int npage = tid;
-  int npnt = 0;
+  // each thread has its own page allocator
+  MyPage<int> &ipage = list->ipage[tid];
+  ipage.reset();
 
   for (i = ifrom; i < ito; i++) {
 
-#if defined(_OPENMP)
-#pragma omp critical
-#endif
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage += nthreads;
-      if (npage >= list->maxpage) list->add_pages(nthreads);
-    }
-
-    neighptr = &(list->pages[npage][npnt]);
     n = 0;
+    neighptr = ipage.vget();
 
     itag = tag[i];
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over remaining atoms, owned and ghost
     // itag = jtag is possible for long cutoffs that include images of self
 
     for (j = i+1; j < nall; j++) {
       if (includegroup && !(mask[j] & bitmask)) continue;
 
       if (j >= nlocal) {
         jtag = tag[j];
         if (itag > jtag) {
           if ((itag+jtag) % 2 == 0) continue;
         } else if (itag < jtag) {
           if ((itag+jtag) % 2 == 1) continue;
         } else {
           if (x[j][2] < ztmp) continue;
           if (x[j][2] == ztmp) {
             if (x[j][1] < ytmp) continue;
             if (x[j][1] == ytmp && x[j][0] < xtmp) continue;
           }
         }
       }
 
       jtype = type[j];
       if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
       delx = xtmp - x[j][0];
       dely = ytmp - x[j][1];
       delz = ztmp - x[j][2];
       rsq = delx*delx + dely*dely + delz*delz;
 
       if (rsq <= cutneighsq[itype][jtype]) {
         if (molecular) {
           which = find_special(special[i],nspecial[i],tag[j]);
           if (which == 0) neighptr[n++] = j;
           else if (domain->minimum_image_check(delx,dely,delz))
             neighptr[n++] = j;
           else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
         } else neighptr[n++] = j;
       }
     }
 
     ilist[i] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage.vgot(n);
+    if (ipage.status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
   NEIGH_OMP_CLOSE;
   list->inum = nlocal;
 }
diff --git a/src/USER-OMP/neigh_respa_omp.cpp b/src/USER-OMP/neigh_respa_omp.cpp
index 28afc81f1..11c7fd9ae 100644
--- a/src/USER-OMP/neigh_respa_omp.cpp
+++ b/src/USER-OMP/neigh_respa_omp.cpp
@@ -1,1011 +1,882 @@
 /* ----------------------------------------------------------------------
    LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
    http://lammps.sandia.gov, Sandia National Laboratories
    Steve Plimpton, sjplimp@sandia.gov
 
    Copyright (2003) Sandia Corporation.  Under the terms of Contract
    DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
    certain rights in this software.  This software is distributed under
    the GNU General Public License.
 
    See the README file in the top-level LAMMPS directory.
 ------------------------------------------------------------------------- */
 
 #include "neighbor.h"
 #include "neighbor_omp.h"
 #include "neigh_list.h"
 #include "atom.h"
 #include "comm.h"
 #include "domain.h"
 #include "group.h"
+#include "my_page.h"
 #include "error.h"
 
 using namespace LAMMPS_NS;
 
 /* ----------------------------------------------------------------------
    multiple respa lists
    N^2 / 2 search for neighbor pairs with partial Newton's 3rd law
    pair added to list if atoms i and j are both owned and i < j
    pair added if j is ghost (also stored by proc owning j)
 ------------------------------------------------------------------------- */
 
 void Neighbor::respa_nsq_no_newton_omp(NeighList *list)
 {
   const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal;
   const int bitmask = (includegroup) ? group->bitmask[includegroup] : 0;
 
   NEIGH_OMP_INIT;
 
   NeighList *listinner = list->listinner;
-  if (nthreads > listinner->maxpage)
-    listinner->add_pages(nthreads - listinner->maxpage);
-
-  NeighList *listmiddle;
+  NeighList *listmiddle = list->listmiddle;
   const int respamiddle = list->respamiddle;
-  if (respamiddle) {
-    listmiddle = list->listmiddle;
-    if (nthreads > listmiddle->maxpage)
-      listmiddle->add_pages(nthreads - listmiddle->maxpage);
-  }
 
 #if defined(_OPENMP)
 #pragma omp parallel default(none) shared(list,listinner,listmiddle)
 #endif
   NEIGH_OMP_SETUP(nlocal);
 
   int i,j,n,itype,jtype,n_inner,n_middle;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int *neighptr,*neighptr_inner,*neighptr_middle;
 
   // loop over each atom, storing neighbors
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int nall = atom->nlocal + atom->nghost;
   int molecular = atom->molecular;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
 
   int *ilist_inner = listinner->ilist;
   int *numneigh_inner = listinner->numneigh;
   int **firstneigh_inner = listinner->firstneigh;
 
   int *ilist_middle,*numneigh_middle,**firstneigh_middle;
   if (respamiddle) {
     ilist_middle = listmiddle->ilist;
     numneigh_middle = listmiddle->numneigh;
     firstneigh_middle = listmiddle->firstneigh;
   }
 
-  int npage = tid;
-  int npnt = 0;
-  int npage_inner = tid;
-  int npnt_inner = 0;
-  int npage_middle = tid;
-  int npnt_middle = 0;
+  // each thread has its own page allocator
+  MyPage<int> &ipage = list->ipage[tid];
+  MyPage<int> &ipage_inner = listinner->ipage[tid];
+  ipage.reset();
+  ipage_inner.reset();
+
+  MyPage<int> *ipage_middle;
+  if (respamiddle) {
+    ipage_middle = listmiddle->ipage + tid;
+    ipage_middle->reset();
+  }
 
   int which = 0;
   int minchange = 0;
 
   for (i = ifrom; i < ito; i++) {
 
-#if defined(_OPENMP)
-#pragma omp critical
-#endif
-   {
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage += nthreads;
-      if (npage >= list->maxpage) list->add_pages(nthreads);
-    }
-    neighptr = &(list->pages[npage][npnt]);
-    n = 0;
-
-    if (pgsize - npnt_inner < oneatom) {
-      npnt_inner = 0;
-      npage_inner += nthreads;
-      if (npage_inner >= listinner->maxpage) listinner->add_pages(nthreads);
-    }
-    neighptr_inner = &(listinner->pages[npage_inner][npnt_inner]);
-    n_inner = 0;
-
+    n = n_inner = 0;
+    neighptr = ipage.vget();
+    neighptr_inner = ipage_inner.vget();
     if (respamiddle) {
-      if (pgsize - npnt_middle < oneatom) {
-        npnt_middle = 0;
-        npage_middle += nthreads;
-        if (npage_middle >= listmiddle->maxpage) listmiddle->add_pages(nthreads);
-      }
-      neighptr_middle = &(listmiddle->pages[npage_middle][npnt_middle]);
       n_middle = 0;
+      neighptr_middle = ipage_middle->vget();
     }
-   }
 
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over remaining atoms, owned and ghost
 
     for (j = i+1; j < nall; j++) {
       if (includegroup && !(mask[j] & bitmask)) continue;
       jtype = type[j];
       if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
       delx = xtmp - x[j][0];
       dely = ytmp - x[j][1];
       delz = ztmp - x[j][2];
       rsq = delx*delx + dely*dely + delz*delz;
 
       if (rsq <= cutneighsq[itype][jtype]) {
         if (molecular) {
           which = find_special(special[i],nspecial[i],tag[j]);
           if (which == 0) neighptr[n++] = j;
           else if (minchange = domain->minimum_image_check(delx,dely,delz))
             neighptr[n++] = j;
           else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
         } else neighptr[n++] = j;
 
         if (rsq < cut_inner_sq) {
           if (which == 0) neighptr_inner[n_inner++] = j;
           else if (minchange) neighptr_inner[n_inner++] = j;
           else if (which > 0) neighptr_inner[n_inner++] = j ^ (which << SBBITS);
         }
 
         if (respamiddle && rsq < cut_middle_sq && rsq > cut_middle_inside_sq) {
           if (which == 0) neighptr_middle[n_middle++] = j;
           else if (minchange) neighptr_middle[n_middle++] = j;
           else if (which > 0)
             neighptr_middle[n_middle++] = j ^ (which << SBBITS);
         }
       }
     }
 
     ilist[i] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage.vgot(n);
+    if (ipage.status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
 
     ilist_inner[i] = i;
     firstneigh_inner[i] = neighptr_inner;
     numneigh_inner[i] = n_inner;
-    npnt_inner += n_inner;
-    if (n_inner > oneatom)
+    ipage.vgot(n_inner);
+    if (ipage_inner.status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
 
     if (respamiddle) {
       ilist_middle[i] = i;
       firstneigh_middle[i] = neighptr_middle;
       numneigh_middle[i] = n_middle;
-      npnt_middle += n_middle;
-      if (n_middle > oneatom)
+      ipage_middle->vgot(n_middle);
+      if (ipage_middle->status())
         error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
     }
   }
   NEIGH_OMP_CLOSE;
   list->inum = nlocal;
   listinner->inum = nlocal;
   if (respamiddle) listmiddle->inum = nlocal;
 }
 
 /* ----------------------------------------------------------------------
    multiple respa lists
    N^2 / 2 search for neighbor pairs with full Newton's 3rd law
    pair added to list if atoms i and j are both owned and i < j
    if j is ghost only me or other proc adds pair
    decision based on itag,jtag tests
 ------------------------------------------------------------------------- */
 
 void Neighbor::respa_nsq_newton_omp(NeighList *list)
 {
   const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal;
   const int bitmask = (includegroup) ? group->bitmask[includegroup] : 0;
 
   NEIGH_OMP_INIT;
 
   NeighList *listinner = list->listinner;
-  if (nthreads > listinner->maxpage)
-    listinner->add_pages(nthreads - listinner->maxpage);
-
-  NeighList *listmiddle;
+  NeighList *listmiddle = list->listmiddle;
   const int respamiddle = list->respamiddle;
-  if (respamiddle) {
-    listmiddle = list->listmiddle;
-    if (nthreads > listmiddle->maxpage)
-      listmiddle->add_pages(nthreads - listmiddle->maxpage);
-  }
 
 #if defined(_OPENMP)
 #pragma omp parallel default(none) shared(list,listinner,listmiddle)
 #endif
   NEIGH_OMP_SETUP(nlocal);
 
   int i,j,n,itype,jtype,itag,jtag,n_inner,n_middle;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int *neighptr,*neighptr_inner,*neighptr_middle;
 
   // loop over each atom, storing neighbors
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int nall = atom->nlocal + atom->nghost;
   int molecular = atom->molecular;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
 
   int *ilist_inner = listinner->ilist;
   int *numneigh_inner = listinner->numneigh;
   int **firstneigh_inner = listinner->firstneigh;
 
   int *ilist_middle,*numneigh_middle,**firstneigh_middle;
   if (respamiddle) {
     ilist_middle = listmiddle->ilist;
     numneigh_middle = listmiddle->numneigh;
     firstneigh_middle = listmiddle->firstneigh;
   }
 
-  int npage = tid;
-  int npnt = 0;
-  int npage_inner = tid;
-  int npnt_inner = 0;
-  int npage_middle = tid;
-  int npnt_middle = 0;
+  // each thread has its own page allocator
+  MyPage<int> &ipage = list->ipage[tid];
+  MyPage<int> &ipage_inner = listinner->ipage[tid];
+  ipage.reset();
+  ipage_inner.reset();
+
+  MyPage<int> *ipage_middle;
+  if (respamiddle) {
+    ipage_middle = listmiddle->ipage + tid;
+    ipage_middle->reset();
+  }
 
   int which = 0;
   int minchange = 0;
 
   for (i = ifrom; i < ito; i++) {
 
-#if defined(_OPENMP)
-#pragma omp critical
-#endif
-   {
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage += nthreads;
-      if (npage >= list->maxpage) list->add_pages(nthreads);
-    }
-    neighptr = &(list->pages[npage][npnt]);
-    n = 0;
-
-    if (pgsize - npnt_inner < oneatom) {
-      npnt_inner = 0;
-      npage_inner += nthreads;
-      if (npage_inner >= listinner->maxpage) listinner->add_pages(nthreads);
-    }
-    neighptr_inner = &(listinner->pages[npage_inner][npnt_inner]);
-    n_inner = 0;
-
+    n = n_inner = 0;
+    neighptr = ipage.vget();
+    neighptr_inner = ipage_inner.vget();
     if (respamiddle) {
-      if (pgsize - npnt_middle < oneatom) {
-        npnt_middle = 0;
-        npage_middle += nthreads;
-        if (npage_middle >= listmiddle->maxpage) listmiddle->add_pages(nthreads);
-      }
-      neighptr_middle = &(listmiddle->pages[npage_middle][npnt_middle]);
       n_middle = 0;
+      neighptr_middle = ipage_middle->vget();
     }
-   }
 
     itag = tag[i];
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over remaining atoms, owned and ghost
 
     for (j = i+1; j < nall; j++) {
       if (includegroup && !(mask[j] & bitmask)) continue;
 
       if (j >= nlocal) {
         jtag = tag[j];
         if (itag > jtag) {
           if ((itag+jtag) % 2 == 0) continue;
         } else if (itag < jtag) {
           if ((itag+jtag) % 2 == 1) continue;
         } else {
           if (x[j][2] < ztmp) continue;
           if (x[j][2] == ztmp) {
             if (x[j][1] < ytmp) continue;
             if (x[j][1] == ytmp && x[j][0] < xtmp) continue;
           }
         }
       }
 
       jtype = type[j];
       if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
       delx = xtmp - x[j][0];
       dely = ytmp - x[j][1];
       delz = ztmp - x[j][2];
       rsq = delx*delx + dely*dely + delz*delz;
 
       if (rsq <= cutneighsq[itype][jtype]) {
         if (molecular) {
           which = find_special(special[i],nspecial[i],tag[j]);
           if (which == 0) neighptr[n++] = j;
           else if (minchange = domain->minimum_image_check(delx,dely,delz))
             neighptr[n++] = j;
           else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
         } else neighptr[n++] = j;
 
         if (rsq < cut_inner_sq) {
           if (which == 0) neighptr_inner[n_inner++] = j;
           else if (minchange) neighptr_inner[n_inner++] = j;
           else if (which > 0) neighptr_inner[n_inner++] = j ^ (which << SBBITS);
         }
 
         if (respamiddle &&
             rsq < cut_middle_sq && rsq > cut_middle_inside_sq) {
           if (which == 0) neighptr_middle[n_middle++] = j;
           else if (minchange) neighptr_middle[n_middle++] = j;
           else if (which > 0)
             neighptr_middle[n_middle++] = j ^ (which << SBBITS);
         }
       }
     }
 
     ilist[i] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage.vgot(n);
+    if (ipage.status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
 
     ilist_inner[i] = i;
     firstneigh_inner[i] = neighptr_inner;
     numneigh_inner[i] = n_inner;
-    npnt_inner += n_inner;
-    if (n_inner > oneatom)
+    ipage.vgot(n_inner);
+    if (ipage_inner.status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
 
     if (respamiddle) {
       ilist_middle[i] = i;
       firstneigh_middle[i] = neighptr_middle;
       numneigh_middle[i] = n_middle;
-      npnt_middle += n_middle;
-      if (n_middle > oneatom)
+      ipage_middle->vgot(n_middle);
+      if (ipage_middle->status())
         error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
     }
   }
   NEIGH_OMP_CLOSE;
   list->inum = nlocal;
   listinner->inum = nlocal;
   if (respamiddle) listmiddle->inum = nlocal;
 }
 
 /* ----------------------------------------------------------------------
    multiple respa lists
    binned neighbor list construction with partial Newton's 3rd law
    each owned atom i checks own bin and surrounding bins in non-Newton stencil
    pair stored once if i,j are both owned and i < j
    pair stored by me if j is ghost (also stored by proc owning j)
 ------------------------------------------------------------------------- */
 
 void Neighbor::respa_bin_no_newton_omp(NeighList *list)
 {
   // bin local & ghost atoms
 
   bin_atoms();
 
   const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal;
 
   NEIGH_OMP_INIT;
 
   NeighList *listinner = list->listinner;
-  if (nthreads > listinner->maxpage)
-    listinner->add_pages(nthreads - listinner->maxpage);
-
-  NeighList *listmiddle;
+  NeighList *listmiddle = list->listmiddle;
   const int respamiddle = list->respamiddle;
-  if (respamiddle) {
-    listmiddle = list->listmiddle;
-    if (nthreads > listmiddle->maxpage)
-      listmiddle->add_pages(nthreads - listmiddle->maxpage);
-  }
 
 #if defined(_OPENMP)
 #pragma omp parallel default(none) shared(list,listinner,listmiddle)
 #endif
   NEIGH_OMP_SETUP(nlocal);
 
   int i,j,k,n,itype,jtype,ibin,n_inner,n_middle;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int *neighptr,*neighptr_inner,*neighptr_middle;
 
   // loop over each atom, storing neighbors
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int molecular = atom->molecular;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
   int nstencil = list->nstencil;
   int *stencil = list->stencil;
 
   int *ilist_inner = listinner->ilist;
   int *numneigh_inner = listinner->numneigh;
   int **firstneigh_inner = listinner->firstneigh;
 
   int *ilist_middle,*numneigh_middle,**firstneigh_middle;
   if (respamiddle) {
     ilist_middle = listmiddle->ilist;
     numneigh_middle = listmiddle->numneigh;
     firstneigh_middle = listmiddle->firstneigh;
   }
 
-  int npage = tid;
-  int npnt = 0;
-  int npage_inner = tid;
-  int npnt_inner = 0;
-  int npage_middle = tid;
-  int npnt_middle = 0;
+  // each thread has its own page allocator
+  MyPage<int> &ipage = list->ipage[tid];
+  MyPage<int> &ipage_inner = listinner->ipage[tid];
+  ipage.reset();
+  ipage_inner.reset();
+
+  MyPage<int> *ipage_middle;
+  if (respamiddle) {
+    ipage_middle = listmiddle->ipage + tid;
+    ipage_middle->reset();
+  }
 
   int which = 0;
   int minchange = 0;
 
   for (i = ifrom; i < ito; i++) {
 
-#if defined(_OPENMP)
-#pragma omp critical
-#endif
-   {
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage += nthreads;
-      if (npage >= list->maxpage) list->add_pages(nthreads);
-    }
-    neighptr = &(list->pages[npage][npnt]);
-    n = 0;
-
-    if (pgsize - npnt_inner < oneatom) {
-      npnt_inner = 0;
-      npage_inner += nthreads;
-      if (npage_inner >= listinner->maxpage) listinner->add_pages(nthreads);
-    }
-    neighptr_inner = &(listinner->pages[npage_inner][npnt_inner]);
-    n_inner = 0;
-
+    n = n_inner = 0;
+    neighptr = ipage.vget();
+    neighptr_inner = ipage_inner.vget();
     if (respamiddle) {
-      if (pgsize - npnt_middle < oneatom) {
-        npnt_middle = 0;
-        npage_middle += nthreads;
-        if (npage_middle >= listmiddle->maxpage) listmiddle->add_pages(nthreads);
-      }
-      neighptr_middle = &(listmiddle->pages[npage_middle][npnt_middle]);
       n_middle = 0;
+      neighptr_middle = ipage_middle->vget();
     }
-   }
 
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
     ibin = coord2bin(x[i]);
 
     // loop over all atoms in surrounding bins in stencil including self
     // only store pair if i < j
     // stores own/own pairs only once
     // stores own/ghost pairs on both procs
 
     for (k = 0; k < nstencil; k++) {
       for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
         if (j <= i) continue;
 
         jtype = type[j];
         if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
         delx = xtmp - x[j][0];
         dely = ytmp - x[j][1];
         delz = ztmp - x[j][2];
         rsq = delx*delx + dely*dely + delz*delz;
 
         if (rsq <= cutneighsq[itype][jtype]) {
           if (molecular) {
             which = find_special(special[i],nspecial[i],tag[j]);
             if (which == 0) neighptr[n++] = j;
             else if (minchange = domain->minimum_image_check(delx,dely,delz))
               neighptr[n++] = j;
             else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
           } else neighptr[n++] = j;
 
           if (rsq < cut_inner_sq) {
             if (which == 0) neighptr_inner[n_inner++] = j;
             else if (minchange) neighptr_inner[n_inner++] = j;
             else if (which > 0)
               neighptr_inner[n_inner++] = j ^ (which << SBBITS);
           }
 
           if (respamiddle &&
               rsq < cut_middle_sq && rsq > cut_middle_inside_sq) {
             if (which == 0) neighptr_middle[n_middle++] = j;
             else if (minchange) neighptr_middle[n_middle++] = j;
             else if (which > 0)
               neighptr_middle[n_middle++] = j ^ (which << SBBITS);
           }
         }
       }
     }
 
     ilist[i] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage.vgot(n);
+    if (ipage.status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
 
     ilist_inner[i] = i;
     firstneigh_inner[i] = neighptr_inner;
     numneigh_inner[i] = n_inner;
-    npnt_inner += n_inner;
-    if (n_inner > oneatom)
+    ipage.vgot(n_inner);
+    if (ipage_inner.status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
 
     if (respamiddle) {
       ilist_middle[i] = i;
       firstneigh_middle[i] = neighptr_middle;
       numneigh_middle[i] = n_middle;
-      npnt_middle += n_middle;
-      if (n_middle > oneatom)
+      ipage_middle->vgot(n_middle);
+      if (ipage_middle->status())
         error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
     }
   }
   NEIGH_OMP_CLOSE;
   list->inum = nlocal;
   listinner->inum = nlocal;
   if (respamiddle) listmiddle->inum = nlocal;
 }
 
 /* ----------------------------------------------------------------------
    multiple respa lists
    binned neighbor list construction with full Newton's 3rd law
    each owned atom i checks its own bin and other bins in Newton stencil
    every pair stored exactly once by some processor
 ------------------------------------------------------------------------- */
 
 void Neighbor::respa_bin_newton_omp(NeighList *list)
 {
   // bin local & ghost atoms
 
   bin_atoms();
 
   const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal;
 
   NEIGH_OMP_INIT;
 
   NeighList *listinner = list->listinner;
-  if (nthreads > listinner->maxpage)
-    listinner->add_pages(nthreads - listinner->maxpage);
-
-  NeighList *listmiddle;
+  NeighList *listmiddle = list->listmiddle;
   const int respamiddle = list->respamiddle;
-  if (respamiddle) {
-    listmiddle = list->listmiddle;
-    if (nthreads > listmiddle->maxpage)
-      listmiddle->add_pages(nthreads - listmiddle->maxpage);
-  }
 
 #if defined(_OPENMP)
 #pragma omp parallel default(none) shared(list,listinner,listmiddle)
 #endif
   NEIGH_OMP_SETUP(nlocal);
 
   int i,j,k,n,itype,jtype,ibin,n_inner,n_middle;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int *neighptr,*neighptr_inner,*neighptr_middle;
 
   // loop over each atom, storing neighbors
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int molecular = atom->molecular;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
   int nstencil = list->nstencil;
   int *stencil = list->stencil;
 
   int *ilist_inner = listinner->ilist;
   int *numneigh_inner = listinner->numneigh;
   int **firstneigh_inner = listinner->firstneigh;
 
   int *ilist_middle,*numneigh_middle,**firstneigh_middle;
   if (respamiddle) {
     ilist_middle = listmiddle->ilist;
     numneigh_middle = listmiddle->numneigh;
     firstneigh_middle = listmiddle->firstneigh;
   }
 
-  int npage = tid;
-  int npnt = 0;
-  int npage_inner = tid;
-  int npnt_inner = 0;
-  int npage_middle = tid;
-  int npnt_middle = 0;
+  // each thread has its own page allocator
+  MyPage<int> &ipage = list->ipage[tid];
+  MyPage<int> &ipage_inner = listinner->ipage[tid];
+  ipage.reset();
+  ipage_inner.reset();
+
+  MyPage<int> *ipage_middle;
+  if (respamiddle) {
+    ipage_middle = listmiddle->ipage + tid;
+    ipage_middle->reset();
+  }
 
   int which = 0;
   int minchange = 0;
 
   for (i = ifrom; i < ito; i++) {
 
-#if defined(_OPENMP)
-#pragma omp critical
-#endif
-   {
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage += nthreads;
-      if (npage >= list->maxpage) list->add_pages(nthreads);
-    }
-    neighptr = &(list->pages[npage][npnt]);
-    n = 0;
-
-    if (pgsize - npnt_inner < oneatom) {
-      npnt_inner = 0;
-      npage_inner += nthreads;
-      if (npage_inner >= listinner->maxpage) listinner->add_pages(nthreads);
-    }
-    neighptr_inner = &(listinner->pages[npage_inner][npnt_inner]);
-    n_inner = 0;
-
+    n = n_inner = 0;
+    neighptr = ipage.vget();
+    neighptr_inner = ipage_inner.vget();
     if (respamiddle) {
-      if (pgsize - npnt_middle < oneatom) {
-        npnt_middle = 0;
-        npage_middle += nthreads;
-        if (npage_middle >= listmiddle->maxpage) listmiddle->add_pages(nthreads);
-      }
-      neighptr_middle = &(listmiddle->pages[npage_middle][npnt_middle]);
       n_middle = 0;
+      neighptr_middle = ipage_middle->vget();
     }
-   }
 
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over rest of atoms in i's bin, ghosts are at end of linked list
     // if j is owned atom, store it, since j is beyond i in linked list
     // if j is ghost, only store if j coords are "above and to the right" of i
 
     for (j = bins[i]; j >= 0; j = bins[j]) {
       if (j >= nlocal) {
         if (x[j][2] < ztmp) continue;
         if (x[j][2] == ztmp) {
           if (x[j][1] < ytmp) continue;
           if (x[j][1] == ytmp && x[j][0] < xtmp) continue;
         }
       }
 
       jtype = type[j];
       if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
       delx = xtmp - x[j][0];
       dely = ytmp - x[j][1];
       delz = ztmp - x[j][2];
       rsq = delx*delx + dely*dely + delz*delz;
 
       if (rsq <= cutneighsq[itype][jtype]) {
         if (molecular) {
           which = find_special(special[i],nspecial[i],tag[j]);
           if (which == 0) neighptr[n++] = j;
           else if (minchange = domain->minimum_image_check(delx,dely,delz))
             neighptr[n++] = j;
           else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
         } else neighptr[n++] = j;
 
         if (rsq < cut_inner_sq) {
           if (which == 0) neighptr_inner[n_inner++] = j;
           else if (minchange) neighptr_inner[n_inner++] = j;
           else if (which > 0) neighptr_inner[n_inner++] = j ^ (which << SBBITS);
         }
 
         if (respamiddle &&
             rsq < cut_middle_sq && rsq > cut_middle_inside_sq) {
           if (which == 0) neighptr_middle[n_middle++] = j;
           else if (minchange) neighptr_middle[n_middle++] = j;
           else if (which > 0)
             neighptr_middle[n_middle++] = j ^ (which << SBBITS);
         }
       }
     }
 
     // loop over all atoms in other bins in stencil, store every pair
 
     ibin = coord2bin(x[i]);
     for (k = 0; k < nstencil; k++) {
       for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
         jtype = type[j];
         if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
         delx = xtmp - x[j][0];
         dely = ytmp - x[j][1];
         delz = ztmp - x[j][2];
         rsq = delx*delx + dely*dely + delz*delz;
 
         if (rsq <= cutneighsq[itype][jtype]) {
           if (molecular) {
             which = find_special(special[i],nspecial[i],tag[j]);
             if (which == 0) neighptr[n++] = j;
             else if (minchange = domain->minimum_image_check(delx,dely,delz))
               neighptr[n++] = j;
             else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
           } else neighptr[n++] = j;
 
           if (rsq < cut_inner_sq) {
             if (which == 0) neighptr_inner[n_inner++] = j;
             else if (minchange) neighptr_inner[n_inner++] = j;
             else if (which > 0)
               neighptr_inner[n_inner++] = j ^ (which << SBBITS);
           }
 
           if (respamiddle &&
               rsq < cut_middle_sq && rsq > cut_middle_inside_sq) {
             if (which == 0) neighptr_middle[n_middle++] = j;
             else if (minchange) neighptr_middle[n_middle++] = j;
             else if (which > 0)
               neighptr_middle[n_middle++] = j ^ (which << SBBITS);
           }
         }
       }
     }
 
     ilist[i] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage.vgot(n);
+    if (ipage.status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
 
     ilist_inner[i] = i;
     firstneigh_inner[i] = neighptr_inner;
     numneigh_inner[i] = n_inner;
-    npnt_inner += n_inner;
-    if (n_inner > oneatom)
+    ipage.vgot(n_inner);
+    if (ipage_inner.status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
 
     if (respamiddle) {
       ilist_middle[i] = i;
       firstneigh_middle[i] = neighptr_middle;
       numneigh_middle[i] = n_middle;
-      npnt_middle += n_middle;
-      if (n_middle > oneatom)
+      ipage_middle->vgot(n_middle);
+      if (ipage_middle->status())
         error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
     }
   }
   NEIGH_OMP_CLOSE;
   list->inum = nlocal;
   listinner->inum = nlocal;
   if (respamiddle) listmiddle->inum = nlocal;
 }
 
 /* ----------------------------------------------------------------------
    multiple respa lists
    binned neighbor list construction with Newton's 3rd law for triclinic
    each owned atom i checks its own bin and other bins in triclinic stencil
    every pair stored exactly once by some processor
 ------------------------------------------------------------------------- */
 
 void Neighbor::respa_bin_newton_tri_omp(NeighList *list)
 {
   // bin local & ghost atoms
 
   bin_atoms();
 
   const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal;
 
   NEIGH_OMP_INIT;
 
   NeighList *listinner = list->listinner;
-  if (nthreads > listinner->maxpage)
-    listinner->add_pages(nthreads - listinner->maxpage);
-
-  NeighList *listmiddle;
+  NeighList *listmiddle = list->listmiddle;
   const int respamiddle = list->respamiddle;
-  if (respamiddle) {
-    listmiddle = list->listmiddle;
-    if (nthreads > listmiddle->maxpage)
-      listmiddle->add_pages(nthreads - listmiddle->maxpage);
-  }
 
 #if defined(_OPENMP)
 #pragma omp parallel default(none) shared(list,listinner,listmiddle)
 #endif
   NEIGH_OMP_SETUP(nlocal);
 
   int i,j,k,n,itype,jtype,ibin,n_inner,n_middle;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int *neighptr,*neighptr_inner,*neighptr_middle;
 
   // loop over each atom, storing neighbors
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int molecular = atom->molecular;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
   int nstencil = list->nstencil;
   int *stencil = list->stencil;
 
   int *ilist_inner = listinner->ilist;
   int *numneigh_inner = listinner->numneigh;
   int **firstneigh_inner = listinner->firstneigh;
 
   int *ilist_middle,*numneigh_middle,**firstneigh_middle;
   if (respamiddle) {
     ilist_middle = listmiddle->ilist;
     numneigh_middle = listmiddle->numneigh;
     firstneigh_middle = listmiddle->firstneigh;
   }
 
-  int npage = tid;
-  int npnt = 0;
-  int npage_inner = tid;
-  int npnt_inner = 0;
-  int npage_middle = tid;
-  int npnt_middle = 0;
+  // each thread has its own page allocator
+  MyPage<int> &ipage = list->ipage[tid];
+  MyPage<int> &ipage_inner = listinner->ipage[tid];
+  ipage.reset();
+  ipage_inner.reset();
+
+  MyPage<int> *ipage_middle;
+  if (respamiddle) {
+    ipage_middle = listmiddle->ipage + tid;
+    ipage_middle->reset();
+  }
 
   int which = 0;
   int minchange = 0;
 
   for (i = ifrom; i < ito; i++) {
 
-#if defined(_OPENMP)
-#pragma omp critical
-#endif
-   {
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage += nthreads;
-      if (npage >= list->maxpage) list->add_pages(nthreads);
-    }
-    neighptr = &(list->pages[npage][npnt]);
-    n = 0;
-
-    if (pgsize - npnt_inner < oneatom) {
-      npnt_inner = 0;
-      npage_inner += nthreads;
-      if (npage_inner >= listinner->maxpage) listinner->add_pages(nthreads);
-    }
-    neighptr_inner = &(listinner->pages[npage_inner][npnt_inner]);
-    n_inner = 0;
-
+    n = n_inner = 0;
+    neighptr = ipage.vget();
+    neighptr_inner = ipage_inner.vget();
     if (respamiddle) {
-      if (pgsize - npnt_middle < oneatom) {
-        npnt_middle = 0;
-        npage_middle += nthreads;
-        if (npage_middle >= listmiddle->maxpage) listmiddle->add_pages(nthreads);
-      }
-      neighptr_middle = &(listmiddle->pages[npage_middle][npnt_middle]);
       n_middle = 0;
+      neighptr_middle = ipage_middle->vget();
     }
-   }
 
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over all atoms in bins in stencil
     // pairs for atoms j "below" i are excluded
     // below = lower z or (equal z and lower y) or (equal zy and lower x)
     //         (equal zyx and j <= i)
     // latter excludes self-self interaction but allows superposed atoms
 
     ibin = coord2bin(x[i]);
     for (k = 0; k < nstencil; k++) {
       for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
         if (x[j][2] < ztmp) continue;
         if (x[j][2] == ztmp) {
           if (x[j][1] < ytmp) continue;
           if (x[j][1] == ytmp) {
             if (x[j][0] < xtmp) continue;
             if (x[j][0] == xtmp && j <= i) continue;
           }
         }
 
         jtype = type[j];
         if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
         delx = xtmp - x[j][0];
         dely = ytmp - x[j][1];
         delz = ztmp - x[j][2];
         rsq = delx*delx + dely*dely + delz*delz;
 
         if (rsq <= cutneighsq[itype][jtype]) {
           if (molecular) {
             which = find_special(special[i],nspecial[i],tag[j]);
             if (which == 0) neighptr[n++] = j;
             else if (minchange = domain->minimum_image_check(delx,dely,delz))
               neighptr[n++] = j;
             else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
           } else neighptr[n++] = j;
 
           if (rsq < cut_inner_sq) {
             if (which == 0) neighptr_inner[n_inner++] = j;
             else if (minchange) neighptr_inner[n_inner++] = j;
             else if (which > 0)
               neighptr_inner[n_inner++] = j ^ (which << SBBITS);
           }
 
           if (respamiddle &&
               rsq < cut_middle_sq && rsq > cut_middle_inside_sq) {
             if (which == 0) neighptr_middle[n_middle++] = j;
             else if (minchange) neighptr_middle[n_middle++] = j;
             else if (which > 0)
               neighptr_middle[n_middle++] = j ^ (which << SBBITS);
           }
         }
       }
     }
 
     ilist[i] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage.vgot(n);
+    if (ipage.status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
 
     ilist_inner[i] = i;
     firstneigh_inner[i] = neighptr_inner;
     numneigh_inner[i] = n_inner;
-    npnt_inner += n_inner;
-    if (n_inner > oneatom)
+    ipage.vgot(n_inner);
+    if (ipage_inner.status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
 
     if (respamiddle) {
       ilist_middle[i] = i;
       firstneigh_middle[i] = neighptr_middle;
       numneigh_middle[i] = n_middle;
-      npnt_middle += n_middle;
-      if (n_middle > oneatom)
+      ipage_middle->vgot(n_middle);
+      if (ipage_middle->status())
         error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
     }
   }
   NEIGH_OMP_CLOSE;
   list->inum = nlocal;
   listinner->inum = nlocal;
   if (respamiddle) listmiddle->inum = nlocal;
 }
diff --git a/src/USER-OMP/neighbor_omp.h b/src/USER-OMP/neighbor_omp.h
index 5baf0c2d2..c564f8b66 100644
--- a/src/USER-OMP/neighbor_omp.h
+++ b/src/USER-OMP/neighbor_omp.h
@@ -1,69 +1,67 @@
 /* -*- c++ -*- ----------------------------------------------------------
    LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
    http://lammps.sandia.gov, Sandia National Laboratories
    Steve Plimpton, sjplimp@sandia.gov
 
    Copyright (2003) Sandia Corporation.  Under the terms of Contract
    DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
    certain rights in this software.  This software is distributed under
    the GNU General Public License.
 
    See the README file in the top-level LAMMPS directory.
 ------------------------------------------------------------------------- */
 
 #ifndef LMP_NEIGHBOR_OMP_H
 #define LMP_NEIGHBOR_OMP_H
 
 #if defined(_OPENMP)
 #include <omp.h>
 #endif
 
 #include "modify.h"
 #include "fix_omp.h"
 #include "thr_data.h"
 
 namespace LAMMPS_NS {
 
 // these macros hide some ugly and redundant OpenMP related stuff
 #if defined(_OPENMP)
 
 // make sure we have at least one page for each thread
 #define NEIGH_OMP_INIT                             \
   const int nthreads = comm->nthreads;             \
-  if (nthreads > list->maxpage)                    \
-    list->add_pages(nthreads - list->maxpage);     \
   const int ifix = modify->find_fix("package_omp")
 
 // get thread id and then assign each thread a fixed chunk of atoms
 #define NEIGH_OMP_SETUP(num)                    \
   {                                             \
     const int tid = omp_get_thread_num();       \
     const int idelta = 1 + num/nthreads;        \
     const int ifrom = tid*idelta;               \
     const int ito   = ((ifrom + idelta) > num)  \
       ? num : (ifrom+idelta);                   \
     FixOMP *fix = static_cast<FixOMP *>(modify->fix[ifix]); \
     ThrData *thr = fix->get_thr(tid);           \
     thr->timer(ThrData::TIME_START);
 
 #define NEIGH_OMP_CLOSE                         \
       thr->timer(ThrData::TIME_NEIGH);          \
     }
 
 #else /* !defined(_OPENMP) */
 
 #define NEIGH_OMP_INIT                          \
   const int nthreads = comm->nthreads;
 
 #define NEIGH_OMP_SETUP(num)                    \
   const int tid = 0;                            \
   const int ifrom = 0;                          \
   const int ito = num
 
 #define NEIGH_OMP_CLOSE
 
 #endif
 
 }
 
 #endif
diff --git a/src/USER-OMP/pair_airebo_omp.cpp b/src/USER-OMP/pair_airebo_omp.cpp
index a2fc72cc8..fbad620aa 100644
--- a/src/USER-OMP/pair_airebo_omp.cpp
+++ b/src/USER-OMP/pair_airebo_omp.cpp
@@ -1,2771 +1,2761 @@
 /* ----------------------------------------------------------------------
    LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
    http://lammps.sandia.gov, Sandia National Laboratories
    Steve Plimpton, sjplimp@sandia.gov
 
    This software is distributed under the GNU General Public License.
 
    See the README file in the top-level LAMMPS directory.
 ------------------------------------------------------------------------- */
 
 /* ----------------------------------------------------------------------
    Contributing author: Axel Kohlmeyer (Temple U)
 ------------------------------------------------------------------------- */
 
 #include "math.h"
 #include "pair_airebo_omp.h"
 #include "atom.h"
 #include "comm.h"
 #include "error.h"
 #include "force.h"
 #include "memory.h"
+#include "my_page.h"
 #include "math_special.h"
 #include "neighbor.h"
 #include "neigh_list.h"
 
 #if defined(_OPENMP)
 #include <omp.h>
 #endif
 
 #include "suffix.h"
 using namespace LAMMPS_NS;
 using namespace MathSpecial;
 
 #define TOL 1.0e-9
 
 /* ---------------------------------------------------------------------- */
 
 PairAIREBOOMP::PairAIREBOOMP(LAMMPS *lmp) :
   PairAIREBO(lmp), ThrOMP(lmp, THR_PAIR)
 {
   suffix_flag |= Suffix::OMP;
   respa_enable = 0;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void PairAIREBOOMP::compute(int eflag, int vflag)
 {
   if (eflag || vflag) {
     ev_setup(eflag,vflag);
   } else evflag = vflag_fdotr = vflag_atom = 0;
 
   REBO_neigh_thr();
 
   const int nall = atom->nlocal + atom->nghost;
   const int nthreads = comm->nthreads;
   const int inum = list->inum;
 
 #if defined(_OPENMP)
 #pragma omp parallel default(none) shared(eflag,vflag)
 #endif
   {
     int ifrom, ito, tid;
 
     loop_setup_thr(ifrom, ito, tid, inum, nthreads);
     ThrData *thr = fix->get_thr(tid);
     thr->timer(ThrData::TIME_START);
     ev_setup_thr(eflag, vflag, nall, eatom, vatom, thr);
 
     FREBO_thr(ifrom,ito,evflag,eflag,vflag_atom,thr);
     if (ljflag) FLJ_thr(ifrom,ito,evflag,eflag,vflag_atom,thr);
     if (torflag) TORSION_thr(ifrom,ito,evflag,eflag,thr);
 
     thr->timer(ThrData::TIME_PAIR);
     reduce_thr(this, eflag, vflag, thr);
   } // end of omp parallel region
 }
 
 /* ----------------------------------------------------------------------
    Bij function
 ------------------------------------------------------------------------- */
 
 double PairAIREBOOMP::bondorder_thr(int i, int j, double rij[3], double rijmag,
                                     double VA, int vflag_atom, ThrData * const thr)
 {
   int atomi,atomj,k,n,l,atomk,atoml,atomn,atom1,atom2,atom3,atom4;
   int itype,jtype,ktype,ltype,ntype;
   double rik[3],rjl[3],rkn[3],rji[3],rki[3],rlj[3],rknmag,dNki,dwjl,bij;
   double NijC,NijH,NjiC,NjiH,wik,dwik,dwkn,wjl;
   double rikmag,rjlmag,cosjik,cosijl,g,tmp2,tmp3;
   double Etmp,pij,tmp,wij,dwij,NconjtmpI,NconjtmpJ,Nki,Nlj,dS;
   double lamdajik,lamdaijl,dgdc,dgdN,pji,Nijconj,piRC;
   double dcosjikdri[3],dcosijldri[3],dcosjikdrk[3];
   double dN2[2],dN3[3];
   double dcosjikdrj[3],dcosijldrj[3],dcosijldrl[3];
   double Tij;
   double r32[3],r32mag,cos321,r43[3],r13[3];
   double dNlj;
   double om1234,rln[3];
   double rlnmag,dwln,r23[3],r23mag,r21[3],r21mag;
   double w21,dw21,r34[3],r34mag,cos234,w34,dw34;
   double cross321[3],cross234[3],prefactor,SpN;
   double fcijpc,fcikpc,fcjlpc,fcjkpc,fcilpc;
   double dt2dik[3],dt2djl[3],dt2dij[3],aa,aaa1,aaa2,at2,cw,cwnum,cwnom;
   double sin321,sin234,rr,rijrik,rijrjl,rjk2,rik2,ril2,rjl2;
   double dctik,dctjk,dctjl,dctij,dctji,dctil,rik2i,rjl2i,sink2i,sinl2i;
   double rjk[3],ril[3],dt1dik,dt1djk,dt1djl,dt1dil,dt1dij;
   double F23[3],F12[3],F34[3],F31[3],F24[3],fi[3],fj[3],fk[3],fl[3];
   double f1[3],f2[3],f3[3],f4[4];
   double dcut321,PijS,PjiS;
   double rij2,tspjik,dtsjik,tspijl,dtsijl,costmp;
   int *REBO_neighs,*REBO_neighs_i,*REBO_neighs_j,*REBO_neighs_k,*REBO_neighs_l;
 
   const double * const * const x = atom->x;
   double * const * const f = thr->get_f();
   int *type = atom->type;
 
   atomi = i;
   atomj = j;
   itype = map[type[i]];
   jtype = map[type[j]];
   wij = Sp(rijmag,rcmin[itype][jtype],rcmax[itype][jtype],dwij);
   NijC = nC[i]-(wij*kronecker(jtype,0));
   NijH = nH[i]-(wij*kronecker(jtype,1));
   NjiC = nC[j]-(wij*kronecker(itype,0));
   NjiH = nH[j]-(wij*kronecker(itype,1));
   bij = 0.0;
   tmp = 0.0;
   tmp2 = 0.0;
   tmp3 = 0.0;
   dgdc = 0.0;
   dgdN = 0.0;
   NconjtmpI = 0.0;
   NconjtmpJ = 0.0;
   Etmp = 0.0;
 
   REBO_neighs = REBO_firstneigh[i];
   for (k = 0; k < REBO_numneigh[i]; k++) {
     atomk = REBO_neighs[k];
     if (atomk != atomj) {
       ktype = map[type[atomk]];
       rik[0] = x[atomi][0]-x[atomk][0];
       rik[1] = x[atomi][1]-x[atomk][1];
       rik[2] = x[atomi][2]-x[atomk][2];
       rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2]));
       lamdajik = 4.0*kronecker(itype,1) *
         ((rho[ktype][1]-rikmag)-(rho[jtype][1]-rijmag));
       wik = Sp(rikmag,rcmin[itype][ktype],rcmax[itype][ktype],dS);
       Nki = nC[atomk]-(wik*kronecker(itype,0))+nH[atomk] -
         (wik*kronecker(itype,1));
       cosjik = ((rij[0]*rik[0])+(rij[1]*rik[1])+(rij[2]*rik[2])) /
         (rijmag*rikmag);
       cosjik = MIN(cosjik,1.0);
       cosjik = MAX(cosjik,-1.0);
 
       // evaluate splines g and derivatives dg
 
       g = gSpline(cosjik,(NijC+NijH),itype,&dgdc,&dgdN);
       Etmp = Etmp+(wik*g*exp(lamdajik));
       tmp3 = tmp3+(wik*dgdN*exp(lamdajik));
       NconjtmpI = NconjtmpI+(kronecker(ktype,0)*wik*Sp(Nki,Nmin,Nmax,dS));
     }
   }
 
   PijS = 0.0;
   dN2[0] = 0.0;
   dN2[1] = 0.0;
   PijS = PijSpline(NijC,NijH,itype,jtype,dN2);
   pij = 1.0/sqrt(1.0+Etmp+PijS);
   tmp = -0.5*pij*pij*pij;
 
   const double invrijm = 1.0/rijmag;
   const double invrijm2 = invrijm*invrijm;
 
   // pij forces
 
   REBO_neighs = REBO_firstneigh[i];
   for (k = 0; k < REBO_numneigh[i]; k++) {
     atomk = REBO_neighs[k];
     if (atomk != atomj) {
       ktype = map[type[atomk]];
       rik[0] = x[atomi][0]-x[atomk][0];
       rik[1] = x[atomi][1]-x[atomk][1];
       rik[2] = x[atomi][2]-x[atomk][2];
       rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2]));
       lamdajik = 4.0*kronecker(itype,1) *
         ((rho[ktype][1]-rikmag)-(rho[jtype][1]-rijmag));
       wik = Sp(rikmag,rcmin[itype][ktype],rcmax[itype][ktype],dwik);
 
       const double invrikm = 1.0/rikmag;
       const double invrijkm = invrijm*invrikm;
       const double invrikm2 = invrikm*invrikm;
 
       cosjik = (rij[0]*rik[0] + rij[1]*rik[1] + rij[2]*rik[2]) * invrijkm;
       cosjik = MIN(cosjik,1.0);
       cosjik = MAX(cosjik,-1.0);
 
       dcosjikdri[0] = ((rij[0]+rik[0])*invrijkm) -
         (cosjik*((rij[0]*invrijm2)+(rik[0]*invrikm2)));
       dcosjikdri[1] = ((rij[1]+rik[1])*invrijkm) -
         (cosjik*((rij[1]*invrijm2)+(rik[1]*invrikm2)));
       dcosjikdri[2] = ((rij[2]+rik[2])*invrijkm) -
         (cosjik*((rij[2]*invrijm2)+(rik[2]*invrikm2)));
       dcosjikdrk[0] = (-rij[0]*invrijkm) + (cosjik*(rik[0]*invrikm2));
       dcosjikdrk[1] = (-rij[1]*invrijkm) + (cosjik*(rik[1]*invrikm2));
       dcosjikdrk[2] = (-rij[2]*invrijkm) + (cosjik*(rik[2]*invrikm2));
       dcosjikdrj[0] = (-rik[0]*invrijkm) + (cosjik*(rij[0]*invrijm2));
       dcosjikdrj[1] = (-rik[1]*invrijkm) + (cosjik*(rij[1]*invrijm2));
       dcosjikdrj[2] = (-rik[2]*invrijkm) + (cosjik*(rij[2]*invrijm2));
 
       g = gSpline(cosjik,(NijC+NijH),itype,&dgdc,&dgdN);
       tmp2 = VA*.5*(tmp*wik*dgdc*exp(lamdajik));
       fj[0] = -tmp2*dcosjikdrj[0];
       fj[1] = -tmp2*dcosjikdrj[1];
       fj[2] = -tmp2*dcosjikdrj[2];
       fi[0] = -tmp2*dcosjikdri[0];
       fi[1] = -tmp2*dcosjikdri[1];
       fi[2] = -tmp2*dcosjikdri[2];
       fk[0] = -tmp2*dcosjikdrk[0];
       fk[1] = -tmp2*dcosjikdrk[1];
       fk[2] = -tmp2*dcosjikdrk[2];
 
       tmp2 = VA*.5*(tmp*wik*g*exp(lamdajik)*4.0*kronecker(itype,1));
       fj[0] -= tmp2*(-rij[0]*invrijm);
       fj[1] -= tmp2*(-rij[1]*invrijm);
       fj[2] -= tmp2*(-rij[2]*invrijm);
       fi[0] -= tmp2*((-rik[0]*invrikm)+(rij[0]*invrijm));
       fi[1] -= tmp2*((-rik[1]*invrikm)+(rij[1]*invrijm));
       fi[2] -= tmp2*((-rik[2]*invrikm)+(rij[2]*invrijm));
       fk[0] -= tmp2*(rik[0]*invrikm);
       fk[1] -= tmp2*(rik[1]*invrikm);
       fk[2] -= tmp2*(rik[2]*invrikm);
 
       // coordination forces
 
       // dwik forces
 
       tmp2 = VA*.5*(tmp*dwik*g*exp(lamdajik))*invrikm;
       fi[0] -= tmp2*rik[0];
       fi[1] -= tmp2*rik[1];
       fi[2] -= tmp2*rik[2];
       fk[0] += tmp2*rik[0];
       fk[1] += tmp2*rik[1];
       fk[2] += tmp2*rik[2];
 
       // PIJ forces
 
       tmp2 = VA*.5*(tmp*dN2[ktype]*dwik)*invrikm;
       fi[0] -= tmp2*rik[0];
       fi[1] -= tmp2*rik[1];
       fi[2] -= tmp2*rik[2];
       fk[0] += tmp2*rik[0];
       fk[1] += tmp2*rik[1];
       fk[2] += tmp2*rik[2];
 
       // dgdN forces
 
       tmp2 = VA*.5*(tmp*tmp3*dwik)*invrikm;
       fi[0] -= tmp2*rik[0];
       fi[1] -= tmp2*rik[1];
       fi[2] -= tmp2*rik[2];
       fk[0] += tmp2*rik[0];
       fk[1] += tmp2*rik[1];
       fk[2] += tmp2*rik[2];
 
       f[atomi][0] += fi[0]; f[atomi][1] += fi[1]; f[atomi][2] += fi[2];
       f[atomj][0] += fj[0]; f[atomj][1] += fj[1]; f[atomj][2] += fj[2];
       f[atomk][0] += fk[0]; f[atomk][1] += fk[1]; f[atomk][2] += fk[2];
 
       if (vflag_atom) {
         rji[0] = -rij[0]; rji[1] = -rij[1]; rji[2] = -rij[2];
         rki[0] = -rik[0]; rki[1] = -rik[1]; rki[2] = -rik[2];
         v_tally3_thr(atomi,atomj,atomk,fj,fk,rji,rki,thr);
       }
     }
   }
 
   tmp = 0.0;
   tmp2 = 0.0;
   tmp3 = 0.0;
   Etmp = 0.0;
 
   REBO_neighs = REBO_firstneigh[j];
   for (l = 0; l < REBO_numneigh[j]; l++) {
     atoml = REBO_neighs[l];
     if (atoml != atomi) {
       ltype = map[type[atoml]];
       rjl[0] = x[atomj][0]-x[atoml][0];
       rjl[1] = x[atomj][1]-x[atoml][1];
       rjl[2] = x[atomj][2]-x[atoml][2];
       rjlmag = sqrt((rjl[0]*rjl[0])+(rjl[1]*rjl[1])+(rjl[2]*rjl[2]));
       lamdaijl = 4.0*kronecker(jtype,1) *
         ((rho[ltype][1]-rjlmag)-(rho[itype][1]-rijmag));
       wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmax[jtype][ltype],dS);
       Nlj = nC[atoml]-(wjl*kronecker(jtype,0)) +
         nH[atoml]-(wjl*kronecker(jtype,1));
       cosijl = -1.0*((rij[0]*rjl[0])+(rij[1]*rjl[1])+(rij[2]*rjl[2])) /
         (rijmag*rjlmag);
       cosijl = MIN(cosijl,1.0);
       cosijl = MAX(cosijl,-1.0);
 
       // evaluate splines g and derivatives dg
 
       g = gSpline(cosijl,NjiC+NjiH,jtype,&dgdc,&dgdN);
       Etmp = Etmp+(wjl*g*exp(lamdaijl));
       tmp3 = tmp3+(wjl*dgdN*exp(lamdaijl));
       NconjtmpJ = NconjtmpJ+(kronecker(ltype,0)*wjl*Sp(Nlj,Nmin,Nmax,dS));
     }
   }
 
   PjiS = 0.0;
   dN2[0] = 0.0;
   dN2[1] = 0.0;
   PjiS = PijSpline(NjiC,NjiH,jtype,itype,dN2);
   pji = 1.0/sqrt(1.0+Etmp+PjiS);
   tmp = -0.5*pji*pji*pji;
 
   REBO_neighs = REBO_firstneigh[j];
   for (l = 0; l < REBO_numneigh[j]; l++) {
     atoml = REBO_neighs[l];
     if (atoml != atomi) {
       ltype = map[type[atoml]];
       rjl[0] = x[atomj][0]-x[atoml][0];
       rjl[1] = x[atomj][1]-x[atoml][1];
       rjl[2] = x[atomj][2]-x[atoml][2];
       rjlmag = sqrt((rjl[0]*rjl[0])+(rjl[1]*rjl[1])+(rjl[2]*rjl[2]));
       lamdaijl = 4.0*kronecker(jtype,1) *
         ((rho[ltype][1]-rjlmag)-(rho[itype][1]-rijmag));
       wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmax[jtype][ltype],dwjl);
 
       const double invrjlm = 1.0/rjlmag;
       const double invrijlm = invrijm*invrjlm;
       const double invrjlm2 = invrjlm*invrjlm;
 
       cosijl = (-1.0*((rij[0]*rjl[0])+(rij[1]*rjl[1])+(rij[2]*rjl[2])))
         * invrijlm;
 
       cosijl = MIN(cosijl,1.0);
       cosijl = MAX(cosijl,-1.0);
 
       dcosijldri[0] = (-rjl[0]*invrijlm) - (cosijl*rij[0]*invrijm2);
       dcosijldri[1] = (-rjl[1]*invrijlm) - (cosijl*rij[1]*invrijm2);
       dcosijldri[2] = (-rjl[2]*invrijlm) - (cosijl*rij[2]*invrijm2);
       dcosijldrj[0] = ((-rij[0]+rjl[0])*invrijlm) +
         (cosijl*((rij[0]*invrijm2)-(rjl[0]*invrjlm2)));
       dcosijldrj[1] = ((-rij[1]+rjl[1])*invrijlm) +
         (cosijl*((rij[1]*invrijm2)-(rjl[1]*invrjlm2)));
       dcosijldrj[2] = ((-rij[2]+rjl[2])*invrijlm) +
         (cosijl*((rij[2]*invrijm2)-(rjl[2]*invrjlm2)));
       dcosijldrl[0] = (rij[0]*invrijlm)+(cosijl*rjl[0]*invrjlm2);
       dcosijldrl[1] = (rij[1]*invrijlm)+(cosijl*rjl[1]*invrjlm2);
       dcosijldrl[2] = (rij[2]*invrijlm)+(cosijl*rjl[2]*invrjlm2);
 
       // evaluate splines g and derivatives dg
 
       g = gSpline(cosijl,NjiC+NjiH,jtype,&dgdc,&dgdN);
       tmp2 = VA*.5*(tmp*wjl*dgdc*exp(lamdaijl));
       fi[0] = -tmp2*dcosijldri[0];
       fi[1] = -tmp2*dcosijldri[1];
       fi[2] = -tmp2*dcosijldri[2];
       fj[0] = -tmp2*dcosijldrj[0];
       fj[1] = -tmp2*dcosijldrj[1];
       fj[2] = -tmp2*dcosijldrj[2];
       fl[0] = -tmp2*dcosijldrl[0];
       fl[1] = -tmp2*dcosijldrl[1];
       fl[2] = -tmp2*dcosijldrl[2];
 
       tmp2 = VA*.5*(tmp*wjl*g*exp(lamdaijl)*4.0*kronecker(jtype,1));
       fi[0] -= tmp2*(rij[0]*invrijm);
       fi[1] -= tmp2*(rij[1]*invrijm);
       fi[2] -= tmp2*(rij[2]*invrijm);
       fj[0] -= tmp2*((-rjl[0]*invrjlm)-(rij[0]*invrijm));
       fj[1] -= tmp2*((-rjl[1]*invrjlm)-(rij[1]*invrijm));
       fj[2] -= tmp2*((-rjl[2]*invrjlm)-(rij[2]*invrijm));
       fl[0] -= tmp2*(rjl[0]*invrjlm);
       fl[1] -= tmp2*(rjl[1]*invrjlm);
       fl[2] -= tmp2*(rjl[2]*invrjlm);
 
       // coordination forces
 
       // dwik forces
 
       tmp2 = VA*.5*(tmp*dwjl*g*exp(lamdaijl))*invrjlm;
       fj[0] -= tmp2*rjl[0];
       fj[1] -= tmp2*rjl[1];
       fj[2] -= tmp2*rjl[2];
       fl[0] += tmp2*rjl[0];
       fl[1] += tmp2*rjl[1];
       fl[2] += tmp2*rjl[2];
 
       // PIJ forces
 
       tmp2 = VA*.5*(tmp*dN2[ltype]*dwjl)*invrjlm;
       fj[0] -= tmp2*rjl[0];
       fj[1] -= tmp2*rjl[1];
       fj[2] -= tmp2*rjl[2];
       fl[0] += tmp2*rjl[0];
       fl[1] += tmp2*rjl[1];
       fl[2] += tmp2*rjl[2];
 
       // dgdN forces
 
       tmp2 = VA*.5*(tmp*tmp3*dwjl)*invrjlm;
       fj[0] -= tmp2*rjl[0];
       fj[1] -= tmp2*rjl[1];
       fj[2] -= tmp2*rjl[2];
       fl[0] += tmp2*rjl[0];
       fl[1] += tmp2*rjl[1];
       fl[2] += tmp2*rjl[2];
 
       f[atomi][0] += fi[0]; f[atomi][1] += fi[1]; f[atomi][2] += fi[2];
       f[atomj][0] += fj[0]; f[atomj][1] += fj[1]; f[atomj][2] += fj[2];
       f[atoml][0] += fl[0]; f[atoml][1] += fl[1]; f[atoml][2] += fl[2];
 
       if (vflag_atom) {
         rlj[0] = -rjl[0]; rlj[1] = -rjl[1]; rlj[2] = -rjl[2];
         v_tally3_thr(atomi,atomj,atoml,fi,fl,rij,rlj,thr);
       }
     }
   }
 
   // evaluate Nij conj
 
   Nijconj = 1.0+(NconjtmpI*NconjtmpI)+(NconjtmpJ*NconjtmpJ);
   piRC = piRCSpline(NijC+NijH,NjiC+NjiH,Nijconj,itype,jtype,dN3);
 
   // piRC forces
 
   REBO_neighs_i = REBO_firstneigh[i];
   for (k = 0; k < REBO_numneigh[i]; k++) {
     atomk = REBO_neighs_i[k];
     if (atomk !=atomj) {
       ktype = map[type[atomk]];
       rik[0] = x[atomi][0]-x[atomk][0];
       rik[1] = x[atomi][1]-x[atomk][1];
       rik[2] = x[atomi][2]-x[atomk][2];
       rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2]));
       wik = Sp(rikmag,rcmin[itype][ktype],rcmax[itype][ktype],dwik);
       Nki = nC[atomk]-(wik*kronecker(itype,0))+nH[atomk] -
         (wik*kronecker(itype,1));
       SpN = Sp(Nki,Nmin,Nmax,dNki);
 
       tmp2 = VA*dN3[0]*dwik/rikmag;
       f[atomi][0] -= tmp2*rik[0];
       f[atomi][1] -= tmp2*rik[1];
       f[atomi][2] -= tmp2*rik[2];
       f[atomk][0] += tmp2*rik[0];
       f[atomk][1] += tmp2*rik[1];
       f[atomk][2] += tmp2*rik[2];
 
       if (vflag_atom) v_tally2_thr(atomi,atomk,-tmp2,rik,thr);
 
       tmp2 = VA*dN3[2]*(2.0*NconjtmpI*dwik*SpN)/rikmag;
       f[atomi][0] -= tmp2*rik[0];
       f[atomi][1] -= tmp2*rik[1];
       f[atomi][2] -= tmp2*rik[2];
       f[atomk][0] += tmp2*rik[0];
       f[atomk][1] += tmp2*rik[1];
       f[atomk][2] += tmp2*rik[2];
 
       if (vflag_atom) v_tally2_thr(atomi,atomk,-tmp2,rik,thr);
 
       if (fabs(dNki) > TOL) {
         REBO_neighs_k = REBO_firstneigh[atomk];
         for (n = 0; n < REBO_numneigh[atomk]; n++) {
           atomn = REBO_neighs_k[n];
           if (atomn != atomi) {
             ntype = map[type[atomn]];
             rkn[0] = x[atomk][0]-x[atomn][0];
             rkn[1] = x[atomk][1]-x[atomn][1];
             rkn[2] = x[atomk][2]-x[atomn][2];
             rknmag = sqrt((rkn[0]*rkn[0])+(rkn[1]*rkn[1])+(rkn[2]*rkn[2]));
             Sp(rknmag,rcmin[ktype][ntype],rcmax[ktype][ntype],dwkn);
 
             tmp2 = VA*dN3[2]*(2.0*NconjtmpI*wik*dNki*dwkn)/rknmag;
             f[atomk][0] -= tmp2*rkn[0];
             f[atomk][1] -= tmp2*rkn[1];
             f[atomk][2] -= tmp2*rkn[2];
             f[atomn][0] += tmp2*rkn[0];
             f[atomn][1] += tmp2*rkn[1];
             f[atomn][2] += tmp2*rkn[2];
 
             if (vflag_atom) v_tally2_thr(atomk,atomn,-tmp2,rkn,thr);
           }
         }
       }
     }
   }
 
   // piRC forces
 
   REBO_neighs = REBO_firstneigh[atomj];
   for (l = 0; l < REBO_numneigh[atomj]; l++) {
     atoml = REBO_neighs[l];
     if (atoml !=atomi) {
       ltype = map[type[atoml]];
       rjl[0] = x[atomj][0]-x[atoml][0];
       rjl[1] = x[atomj][1]-x[atoml][1];
       rjl[2] = x[atomj][2]-x[atoml][2];
       rjlmag = sqrt((rjl[0]*rjl[0])+(rjl[1]*rjl[1])+(rjl[2]*rjl[2]));
       wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmax[jtype][ltype],dwjl);
       Nlj = nC[atoml]-(wjl*kronecker(jtype,0))+nH[atoml] -
         (wjl*kronecker(jtype,1));
       SpN = Sp(Nlj,Nmin,Nmax,dNlj);
 
       tmp2 = VA*dN3[1]*dwjl/rjlmag;
       f[atomj][0] -= tmp2*rjl[0];
       f[atomj][1] -= tmp2*rjl[1];
       f[atomj][2] -= tmp2*rjl[2];
       f[atoml][0] += tmp2*rjl[0];
       f[atoml][1] += tmp2*rjl[1];
       f[atoml][2] += tmp2*rjl[2];
 
       if (vflag_atom) v_tally2_thr(atomj,atoml,-tmp2,rjl,thr);
 
       tmp2 = VA*dN3[2]*(2.0*NconjtmpJ*dwjl*SpN)/rjlmag;
       f[atomj][0] -= tmp2*rjl[0];
       f[atomj][1] -= tmp2*rjl[1];
       f[atomj][2] -= tmp2*rjl[2];
       f[atoml][0] += tmp2*rjl[0];
       f[atoml][1] += tmp2*rjl[1];
       f[atoml][2] += tmp2*rjl[2];
 
       if (vflag_atom) v_tally2_thr(atomj,atoml,-tmp2,rjl,thr);
 
       if (fabs(dNlj) > TOL) {
         REBO_neighs_l = REBO_firstneigh[atoml];
         for (n = 0; n < REBO_numneigh[atoml]; n++) {
           atomn = REBO_neighs_l[n];
           if (atomn != atomj) {
             ntype = map[type[atomn]];
             rln[0] = x[atoml][0]-x[atomn][0];
             rln[1] = x[atoml][1]-x[atomn][1];
             rln[2] = x[atoml][2]-x[atomn][2];
             rlnmag = sqrt((rln[0]*rln[0])+(rln[1]*rln[1])+(rln[2]*rln[2]));
             Sp(rlnmag,rcmin[ltype][ntype],rcmax[ltype][ntype],dwln);
 
             tmp2 = VA*dN3[2]*(2.0*NconjtmpJ*wjl*dNlj*dwln)/rlnmag;
             f[atoml][0] -= tmp2*rln[0];
             f[atoml][1] -= tmp2*rln[1];
             f[atoml][2] -= tmp2*rln[2];
             f[atomn][0] += tmp2*rln[0];
             f[atomn][1] += tmp2*rln[1];
             f[atomn][2] += tmp2*rln[2];
 
             if (vflag_atom) v_tally2_thr(atoml,atomn,-tmp2,rln,thr);
           }
         }
       }
     }
   }
 
   Tij = 0.0;
   dN3[0] = 0.0;
   dN3[1] = 0.0;
   dN3[2] = 0.0;
   if (itype == 0 && jtype == 0)
     Tij=TijSpline((NijC+NijH),(NjiC+NjiH),Nijconj,dN3);
   Etmp = 0.0;
 
   if (fabs(Tij) > TOL) {
     atom2 = atomi;
     atom3 = atomj;
     r32[0] = x[atom3][0]-x[atom2][0];
     r32[1] = x[atom3][1]-x[atom2][1];
     r32[2] = x[atom3][2]-x[atom2][2];
     r32mag = sqrt((r32[0]*r32[0])+(r32[1]*r32[1])+(r32[2]*r32[2]));
     r23[0] = -r32[0];
     r23[1] = -r32[1];
     r23[2] = -r32[2];
     r23mag = r32mag;
     REBO_neighs_i = REBO_firstneigh[i];
     for (k = 0; k < REBO_numneigh[i]; k++) {
       atomk = REBO_neighs_i[k];
       atom1 = atomk;
       ktype = map[type[atomk]];
       if (atomk != atomj) {
         r21[0] = x[atom2][0]-x[atom1][0];
         r21[1] = x[atom2][1]-x[atom1][1];
         r21[2] = x[atom2][2]-x[atom1][2];
         r21mag = sqrt(r21[0]*r21[0] + r21[1]*r21[1] + r21[2]*r21[2]);
         cos321 = -1.0*((r21[0]*r32[0])+(r21[1]*r32[1])+(r21[2]*r32[2])) /
           (r21mag*r32mag);
         cos321 = MIN(cos321,1.0);
         cos321 = MAX(cos321,-1.0);
         Sp2(cos321,thmin,thmax,dcut321);
         sin321 = sqrt(1.0 - cos321*cos321);
         sink2i = 1.0/(sin321*sin321);
         rik2i = 1.0/(r21mag*r21mag);
         if (sin321 != 0.0) {
           rr = (r23mag*r23mag)-(r21mag*r21mag);
           rjk[0] = r21[0]-r23[0];
           rjk[1] = r21[1]-r23[1];
           rjk[2] = r21[2]-r23[2];
           rjk2 = (rjk[0]*rjk[0])+(rjk[1]*rjk[1])+(rjk[2]*rjk[2]);
           rijrik = 2.0*r23mag*r21mag;
           rik2 = r21mag*r21mag;
           dctik = (-rr+rjk2)/(rijrik*rik2);
           dctij = (rr+rjk2)/(rijrik*r23mag*r23mag);
           dctjk = -2.0/rijrik;
           w21 = Sp(r21mag,rcmin[itype][ktype],rcmaxp[itype][ktype],dw21);
           rijmag = r32mag;
           rikmag = r21mag;
           rij2 = r32mag*r32mag;
           rik2 = r21mag*r21mag;
           costmp = 0.5*(rij2+rik2-rjk2)/rijmag/rikmag;
           tspjik = Sp2(costmp,thmin,thmax,dtsjik);
           dtsjik = -dtsjik;
 
           REBO_neighs_j = REBO_firstneigh[j];
           for (l = 0; l < REBO_numneigh[j]; l++) {
             atoml = REBO_neighs_j[l];
             atom4 = atoml;
             ltype = map[type[atoml]];
             if (!(atoml == atomi || atoml == atomk)) {
               r34[0] = x[atom3][0]-x[atom4][0];
               r34[1] = x[atom3][1]-x[atom4][1];
               r34[2] = x[atom3][2]-x[atom4][2];
               r34mag = sqrt((r34[0]*r34[0])+(r34[1]*r34[1])+(r34[2]*r34[2]));
               cos234 = (r32[0]*r34[0] + r32[1]*r34[1] + r32[2]*r34[2]) /
                 (r32mag*r34mag);
               cos234 = MIN(cos234,1.0);
               cos234 = MAX(cos234,-1.0);
               sin234 = sqrt(1.0 - cos234*cos234);
               sinl2i = 1.0/(sin234*sin234);
               rjl2i = 1.0/(r34mag*r34mag);
 
               if (sin234 != 0.0) {
                 w34 = Sp(r34mag,rcmin[jtype][ltype],rcmaxp[jtype][ltype],dw34);
                 rr = (r23mag*r23mag)-(r34mag*r34mag);
                 ril[0] = r23[0]+r34[0];
                 ril[1] = r23[1]+r34[1];
                 ril[2] = r23[2]+r34[2];
                 ril2 = (ril[0]*ril[0])+(ril[1]*ril[1])+(ril[2]*ril[2]);
                 rijrjl = 2.0*r23mag*r34mag;
                 rjl2 = r34mag*r34mag;
                 dctjl = (-rr+ril2)/(rijrjl*rjl2);
                 dctji = (rr+ril2)/(rijrjl*r23mag*r23mag);
                 dctil = -2.0/rijrjl;
                 rjlmag = r34mag;
                 rjl2 = r34mag*r34mag;
                 costmp = 0.5*(rij2+rjl2-ril2)/rijmag/rjlmag;
                 tspijl = Sp2(costmp,thmin,thmax,dtsijl);
                 dtsijl = -dtsijl;
                 prefactor = VA*Tij;
 
                 cross321[0] = (r32[1]*r21[2])-(r32[2]*r21[1]);
                 cross321[1] = (r32[2]*r21[0])-(r32[0]*r21[2]);
                 cross321[2] = (r32[0]*r21[1])-(r32[1]*r21[0]);
                 cross234[0] = (r23[1]*r34[2])-(r23[2]*r34[1]);
                 cross234[1] = (r23[2]*r34[0])-(r23[0]*r34[2]);
                 cross234[2] = (r23[0]*r34[1])-(r23[1]*r34[0]);
 
                 cwnum = (cross321[0]*cross234[0]) +
                   (cross321[1]*cross234[1]) + (cross321[2]*cross234[2]);
                 cwnom = r21mag*r34mag*r23mag*r23mag*sin321*sin234;
                 om1234 = cwnum/cwnom;
                 cw = om1234;
                 Etmp += ((1.0-(om1234*om1234))*w21*w34) *
                   (1.0-tspjik)*(1.0-tspijl);
 
                 dt1dik = (rik2i)-(dctik*sink2i*cos321);
                 dt1djk = (-dctjk*sink2i*cos321);
                 dt1djl = (rjl2i)-(dctjl*sinl2i*cos234);
                 dt1dil = (-dctil*sinl2i*cos234);
                 dt1dij = (2.0/(r23mag*r23mag))-(dctij*sink2i*cos321) -
                   (dctji*sinl2i*cos234);
 
                 dt2dik[0] = (-r23[2]*cross234[1])+(r23[1]*cross234[2]);
                 dt2dik[1] = (-r23[0]*cross234[2])+(r23[2]*cross234[0]);
                 dt2dik[2] = (-r23[1]*cross234[0])+(r23[0]*cross234[1]);
 
                 dt2djl[0] = (-r23[1]*cross321[2])+(r23[2]*cross321[1]);
                 dt2djl[1] = (-r23[2]*cross321[0])+(r23[0]*cross321[2]);
                 dt2djl[2] = (-r23[0]*cross321[1])+(r23[1]*cross321[0]);
 
                 dt2dij[0] = (r21[2]*cross234[1])-(r34[2]*cross321[1]) -
                   (r21[1]*cross234[2])+(r34[1]*cross321[2]);
                 dt2dij[1] = (r21[0]*cross234[2])-(r34[0]*cross321[2]) -
                   (r21[2]*cross234[0])+(r34[2]*cross321[0]);
                 dt2dij[2] = (r21[1]*cross234[0])-(r34[1]*cross321[0]) -
                   (r21[0]*cross234[1])+(r34[0]*cross321[1]);
 
                 aa = (prefactor*2.0*cw/cwnom)*w21*w34 *
                   (1.0-tspjik)*(1.0-tspijl);
                 aaa1 = -prefactor*(1.0-(om1234*om1234)) *
                   (1.0-tspjik)*(1.0-tspijl);
                 aaa2 = aaa1*w21*w34;
                 at2 = aa*cwnum;
 
                 fcijpc = (-dt1dij*at2)+(aaa2*dtsjik*dctij*(1.0-tspijl)) +
                   (aaa2*dtsijl*dctji*(1.0-tspjik));
                 fcikpc = (-dt1dik*at2)+(aaa2*dtsjik*dctik*(1.0-tspijl));
                 fcjlpc = (-dt1djl*at2)+(aaa2*dtsijl*dctjl*(1.0-tspjik));
                 fcjkpc = (-dt1djk*at2)+(aaa2*dtsjik*dctjk*(1.0-tspijl));
                 fcilpc = (-dt1dil*at2)+(aaa2*dtsijl*dctil*(1.0-tspjik));
 
                 F23[0] = (fcijpc*r23[0])+(aa*dt2dij[0]);
                 F23[1] = (fcijpc*r23[1])+(aa*dt2dij[1]);
                 F23[2] = (fcijpc*r23[2])+(aa*dt2dij[2]);
 
                 F12[0] = (fcikpc*r21[0])+(aa*dt2dik[0]);
                 F12[1] = (fcikpc*r21[1])+(aa*dt2dik[1]);
                 F12[2] = (fcikpc*r21[2])+(aa*dt2dik[2]);
 
                 F34[0] = (fcjlpc*r34[0])+(aa*dt2djl[0]);
                 F34[1] = (fcjlpc*r34[1])+(aa*dt2djl[1]);
                 F34[2] = (fcjlpc*r34[2])+(aa*dt2djl[2]);
 
                 F31[0] = (fcjkpc*rjk[0]);
                 F31[1] = (fcjkpc*rjk[1]);
                 F31[2] = (fcjkpc*rjk[2]);
 
                 F24[0] = (fcilpc*ril[0]);
                 F24[1] = (fcilpc*ril[1]);
                 F24[2] = (fcilpc*ril[2]);
 
                 f1[0] = -F12[0]-F31[0];
                 f1[1] = -F12[1]-F31[1];
                 f1[2] = -F12[2]-F31[2];
                 f2[0] = F23[0]+F12[0]+F24[0];
                 f2[1] = F23[1]+F12[1]+F24[1];
                 f2[2] = F23[2]+F12[2]+F24[2];
                 f3[0] = -F23[0]+F34[0]+F31[0];
                 f3[1] = -F23[1]+F34[1]+F31[1];
                 f3[2] = -F23[2]+F34[2]+F31[2];
                 f4[0] = -F34[0]-F24[0];
                 f4[1] = -F34[1]-F24[1];
                 f4[2] = -F34[2]-F24[2];
 
                 // coordination forces
 
                 tmp2 = VA*Tij*((1.0-(om1234*om1234))) *
                   (1.0-tspjik)*(1.0-tspijl)*dw21*w34/r21mag;
                 f2[0] -= tmp2*r21[0];
                 f2[1] -= tmp2*r21[1];
                 f2[2] -= tmp2*r21[2];
                 f1[0] += tmp2*r21[0];
                 f1[1] += tmp2*r21[1];
                 f1[2] += tmp2*r21[2];
 
                 tmp2 = VA*Tij*((1.0-(om1234*om1234))) *
                   (1.0-tspjik)*(1.0-tspijl)*w21*dw34/r34mag;
                 f3[0] -= tmp2*r34[0];
                 f3[1] -= tmp2*r34[1];
                 f3[2] -= tmp2*r34[2];
                 f4[0] += tmp2*r34[0];
                 f4[1] += tmp2*r34[1];
                 f4[2] += tmp2*r34[2];
 
                 f[atom1][0] += f1[0]; f[atom1][1] += f1[1];
                 f[atom1][2] += f1[2];
                 f[atom2][0] += f2[0]; f[atom2][1] += f2[1];
                 f[atom2][2] += f2[2];
                 f[atom3][0] += f3[0]; f[atom3][1] += f3[1];
                 f[atom3][2] += f3[2];
                 f[atom4][0] += f4[0]; f[atom4][1] += f4[1];
                 f[atom4][2] += f4[2];
 
                 if (vflag_atom) {
                   r13[0] = -rjk[0]; r13[1] = -rjk[1]; r13[2] = -rjk[2];
                   r43[0] = -r34[0]; r43[1] = -r34[1]; r43[2] = -r34[2];
                   v_tally4_thr(atom1,atom2,atom3,atom4,f1,f2,f4,r13,r23,r43,thr);
                 }
               }
             }
           }
         }
       }
     }
 
     // Tij forces now that we have Etmp
 
     REBO_neighs = REBO_firstneigh[i];
     for (k = 0; k < REBO_numneigh[i]; k++) {
       atomk = REBO_neighs[k];
       if (atomk != atomj) {
         ktype = map[type[atomk]];
         rik[0] = x[atomi][0]-x[atomk][0];
         rik[1] = x[atomi][1]-x[atomk][1];
         rik[2] = x[atomi][2]-x[atomk][2];
         rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2]));
         wik = Sp(rikmag,rcmin[itype][ktype],rcmax[itype][ktype],dwik);
         Nki = nC[atomk]-(wik*kronecker(itype,0))+nH[atomk] -
           (wik*kronecker(itype,1));
         SpN = Sp(Nki,Nmin,Nmax,dNki);
 
         tmp2 = VA*dN3[0]*dwik*Etmp/rikmag;
         f[atomi][0] -= tmp2*rik[0];
         f[atomi][1] -= tmp2*rik[1];
         f[atomi][2] -= tmp2*rik[2];
         f[atomk][0] += tmp2*rik[0];
         f[atomk][1] += tmp2*rik[1];
         f[atomk][2] += tmp2*rik[2];
 
         if (vflag_atom) v_tally2_thr(atomi,atomk,-tmp2,rik,thr);
 
         tmp2 = VA*dN3[2]*(2.0*NconjtmpI*dwik*SpN)*Etmp/rikmag;
         f[atomi][0] -= tmp2*rik[0];
         f[atomi][1] -= tmp2*rik[1];
         f[atomi][2] -= tmp2*rik[2];
         f[atomk][0] += tmp2*rik[0];
         f[atomk][1] += tmp2*rik[1];
         f[atomk][2] += tmp2*rik[2];
 
         if (vflag_atom) v_tally2_thr(atomi,atomk,-tmp2,rik,thr);
 
         if (fabs(dNki) > TOL) {
           REBO_neighs_k = REBO_firstneigh[atomk];
           for (n = 0; n < REBO_numneigh[atomk]; n++) {
             atomn = REBO_neighs_k[n];
             ntype = map[type[atomn]];
             if (atomn != atomi) {
               rkn[0] = x[atomk][0]-x[atomn][0];
               rkn[1] = x[atomk][1]-x[atomn][1];
               rkn[2] = x[atomk][2]-x[atomn][2];
               rknmag = sqrt((rkn[0]*rkn[0])+(rkn[1]*rkn[1])+(rkn[2]*rkn[2]));
               Sp(rknmag,rcmin[ktype][ntype],rcmax[ktype][ntype],dwkn);
 
               tmp2 = VA*dN3[2]*(2.0*NconjtmpI*wik*dNki*dwkn)*Etmp/rknmag;
               f[atomk][0] -= tmp2*rkn[0];
               f[atomk][1] -= tmp2*rkn[1];
               f[atomk][2] -= tmp2*rkn[2];
               f[atomn][0] += tmp2*rkn[0];
               f[atomn][1] += tmp2*rkn[1];
               f[atomn][2] += tmp2*rkn[2];
 
               if (vflag_atom) v_tally2_thr(atomk,atomn,-tmp2,rkn,thr);
             }
           }
         }
       }
     }
 
     // Tij forces
 
     REBO_neighs = REBO_firstneigh[j];
     for (l = 0; l < REBO_numneigh[j]; l++) {
       atoml = REBO_neighs[l];
       if (atoml != atomi) {
         ltype = map[type[atoml]];
         rjl[0] = x[atomj][0]-x[atoml][0];
         rjl[1] = x[atomj][1]-x[atoml][1];
         rjl[2] = x[atomj][2]-x[atoml][2];
         rjlmag = sqrt((rjl[0]*rjl[0])+(rjl[1]*rjl[1])+(rjl[2]*rjl[2]));
         wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmax[jtype][ltype],dwjl);
         Nlj = nC[atoml]-(wjl*kronecker(jtype,0))+nH[atoml] -
           (wjl*kronecker(jtype,1));
         SpN = Sp(Nlj,Nmin,Nmax,dNlj);
 
         tmp2 = VA*dN3[1]*dwjl*Etmp/rjlmag;
         f[atomj][0] -= tmp2*rjl[0];
         f[atomj][1] -= tmp2*rjl[1];
         f[atomj][2] -= tmp2*rjl[2];
         f[atoml][0] += tmp2*rjl[0];
         f[atoml][1] += tmp2*rjl[1];
         f[atoml][2] += tmp2*rjl[2];
 
         if (vflag_atom) v_tally2_thr(atomj,atoml,-tmp2,rjl,thr);
 
         tmp2 = VA*dN3[2]*(2.0*NconjtmpJ*dwjl*SpN)*Etmp/rjlmag;
         f[atomj][0] -= tmp2*rjl[0];
         f[atomj][1] -= tmp2*rjl[1];
         f[atomj][2] -= tmp2*rjl[2];
         f[atoml][0] += tmp2*rjl[0];
         f[atoml][1] += tmp2*rjl[1];
         f[atoml][2] += tmp2*rjl[2];
 
         if (vflag_atom) v_tally2_thr(atomj,atoml,-tmp2,rjl,thr);
 
         if (fabs(dNlj) > TOL) {
           REBO_neighs_l = REBO_firstneigh[atoml];
           for (n = 0; n < REBO_numneigh[atoml]; n++) {
             atomn = REBO_neighs_l[n];
             ntype = map[type[atomn]];
             if (atomn !=atomj) {
               rln[0] = x[atoml][0]-x[atomn][0];
               rln[1] = x[atoml][1]-x[atomn][1];
               rln[2] = x[atoml][2]-x[atomn][2];
               rlnmag = sqrt((rln[0]*rln[0])+(rln[1]*rln[1])+(rln[2]*rln[2]));
               Sp(rlnmag,rcmin[ltype][ntype],rcmax[ltype][ntype],dwln);
 
               tmp2 = VA*dN3[2]*(2.0*NconjtmpJ*wjl*dNlj*dwln)*Etmp/rlnmag;
               f[atoml][0] -= tmp2*rln[0];
               f[atoml][1] -= tmp2*rln[1];
               f[atoml][2] -= tmp2*rln[2];
               f[atomn][0] += tmp2*rln[0];
               f[atomn][1] += tmp2*rln[1];
               f[atomn][2] += tmp2*rln[2];
 
               if (vflag_atom) v_tally2_thr(atoml,atomn,-tmp2,rln,thr);
             }
           }
         }
       }
     }
   }
 
   bij = (0.5*(pij+pji))+piRC+(Tij*Etmp);
   return bij;
 }
 
 /* ----------------------------------------------------------------------
    Bij* function
 ------------------------------------------------------------------------- */
 
 double PairAIREBOOMP::bondorderLJ_thr(int i, int j, double rij[3], double rijmag,
                                       double VA, double rij0[3], double rij0mag,
                                       int vflag_atom, ThrData * const thr)
 {
   int k,n,l,atomk,atoml,atomn,atom1,atom2,atom3,atom4;
   int atomi,atomj,itype,jtype,ktype,ltype,ntype;
   double rik[3], rjl[3], rkn[3],rknmag,dNki;
   double NijC,NijH,NjiC,NjiH,wik,dwik,dwkn,wjl;
   double rikmag,rjlmag,cosjik,cosijl,g,tmp2,tmp3;
   double Etmp,pij,tmp,wij,dwij,NconjtmpI,NconjtmpJ;
   double Nki,Nlj,dS,lamdajik,lamdaijl,dgdc,dgdN,pji,Nijconj,piRC;
   double dcosjikdri[3],dcosijldri[3],dcosjikdrk[3];
   double dN2[2],dN3[3];
   double dcosijldrj[3],dcosijldrl[3],dcosjikdrj[3],dwjl;
   double Tij,crosskij[3],crosskijmag;
   double crossijl[3],crossijlmag,omkijl;
   double tmppij,tmppji,dN2PIJ[2],dN2PJI[2],dN3piRC[3],dN3Tij[3];
   double bij,tmp3pij,tmp3pji,Stb,dStb;
   double r32[3],r32mag,cos321;
   double om1234,rln[3];
   double rlnmag,dwln,r23[3],r23mag,r21[3],r21mag;
   double w21,dw21,r34[3],r34mag,cos234,w34,dw34;
   double cross321[3],cross234[3],prefactor,SpN;
   double fcijpc,fcikpc,fcjlpc,fcjkpc,fcilpc;
   double dt2dik[3],dt2djl[3],dt2dij[3],aa,aaa1,aaa2,at2,cw,cwnum,cwnom;
   double sin321,sin234,rr,rijrik,rijrjl,rjk2,rik2,ril2,rjl2;
   double dctik,dctjk,dctjl,dctij,dctji,dctil,rik2i,rjl2i,sink2i,sinl2i;
   double rjk[3],ril[3],dt1dik,dt1djk,dt1djl,dt1dil,dt1dij;
   double dNlj;
   double PijS,PjiS;
   double rij2,tspjik,dtsjik,tspijl,dtsijl,costmp;
   int *REBO_neighs,*REBO_neighs_i,*REBO_neighs_j,*REBO_neighs_k,*REBO_neighs_l;
   double F12[3],F23[3],F34[3],F31[3],F24[3];
   double fi[3],fj[3],fk[3],fl[3],f1[3],f2[3],f3[3],f4[4];
   double rji[3],rki[3],rlj[3],r13[3],r43[3];
 
   const double * const * const x = atom->x;
   double * const * const f = thr->get_f();
   const int * const type = atom->type;
 
   atomi = i;
   atomj = j;
   itype = map[type[atomi]];
   jtype = map[type[atomj]];
   wij = Sp(rij0mag,rcmin[itype][jtype],rcmax[itype][jtype],dwij);
   NijC = nC[atomi]-(wij*kronecker(jtype,0));
   NijH = nH[atomi]-(wij*kronecker(jtype,1));
   NjiC = nC[atomj]-(wij*kronecker(itype,0));
   NjiH = nH[atomj]-(wij*kronecker(itype,1));
 
   bij = 0.0;
   tmp = 0.0;
   tmp2 = 0.0;
   tmp3 = 0.0;
   dgdc = 0.0;
   dgdN = 0.0;
   NconjtmpI = 0.0;
   NconjtmpJ = 0.0;
   Etmp = 0.0;
 
   REBO_neighs = REBO_firstneigh[i];
   for (k = 0; k < REBO_numneigh[i]; k++) {
     atomk = REBO_neighs[k];
     if (atomk != atomj) {
       ktype = map[type[atomk]];
       rik[0] = x[atomi][0]-x[atomk][0];
       rik[1] = x[atomi][1]-x[atomk][1];
       rik[2] = x[atomi][2]-x[atomk][2];
       rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2]));
       lamdajik = 4.0*kronecker(itype,1) *
         ((rho[ktype][1]-rikmag)-(rho[jtype][1]-rijmag));
       wik = Sp(rikmag,rcmin[itype][ktype],rcmax[itype][ktype],dS);
       Nki = nC[atomk]-(wik*kronecker(itype,0)) +
         nH[atomk]-(wik*kronecker(itype,1));
       cosjik = ((rij[0]*rik[0])+(rij[1]*rik[1])+(rij[2]*rik[2])) /
         (rijmag*rikmag);
       cosjik = MIN(cosjik,1.0);
       cosjik = MAX(cosjik,-1.0);
 
       // evaluate splines g and derivatives dg
 
       g = gSpline(cosjik,(NijC+NijH),itype,&dgdc,&dgdN);
       Etmp += (wik*g*exp(lamdajik));
       tmp3 += (wik*dgdN*exp(lamdajik));
       NconjtmpI = NconjtmpI+(kronecker(ktype,0)*wik*Sp(Nki,Nmin,Nmax,dS));
     }
   }
 
   PijS = 0.0;
   dN2PIJ[0] = 0.0;
   dN2PIJ[1] = 0.0;
   PijS = PijSpline(NijC,NijH,itype,jtype,dN2PIJ);
   pij = 1.0/sqrt(1.0+Etmp+PijS);
   tmppij = -.5*pij*pij*pij;
   tmp3pij = tmp3;
   tmp = 0.0;
   tmp2 = 0.0;
   tmp3 = 0.0;
   Etmp = 0.0;
 
   REBO_neighs = REBO_firstneigh[j];
   for (l = 0; l < REBO_numneigh[j]; l++) {
     atoml = REBO_neighs[l];
     if (atoml != atomi) {
       ltype = map[type[atoml]];
       rjl[0] = x[atomj][0]-x[atoml][0];
       rjl[1] = x[atomj][1]-x[atoml][1];
       rjl[2] = x[atomj][2]-x[atoml][2];
       rjlmag = sqrt((rjl[0]*rjl[0])+(rjl[1]*rjl[1])+(rjl[2]*rjl[2]));
       lamdaijl = 4.0*kronecker(jtype,1) *
         ((rho[ltype][1]-rjlmag)-(rho[itype][1]-rijmag));
       wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmax[jtype][ltype],dS);
       Nlj = nC[atoml]-(wjl*kronecker(jtype,0))+nH[atoml] -
         (wjl*kronecker(jtype,1));
       cosijl = -1.0*((rij[0]*rjl[0])+(rij[1]*rjl[1])+(rij[2]*rjl[2])) /
         (rijmag*rjlmag);
       cosijl = MIN(cosijl,1.0);
       cosijl = MAX(cosijl,-1.0);
 
       // evaluate splines g and derivatives dg
 
       g = gSpline(cosijl,NjiC+NjiH,jtype,&dgdc,&dgdN);
       Etmp = Etmp+(wjl*g*exp(lamdaijl));
       tmp3 = tmp3+(wjl*dgdN*exp(lamdaijl));
       NconjtmpJ = NconjtmpJ+(kronecker(ltype,0)*wjl*Sp(Nlj,Nmin,Nmax,dS));
     }
   }
 
   PjiS = 0.0;
   dN2PJI[0] = 0.0;
   dN2PJI[1] = 0.0;
   PjiS = PijSpline(NjiC,NjiH,jtype,itype,dN2PJI);
   pji = 1.0/sqrt(1.0+Etmp+PjiS);
   tmppji = -.5*pji*pji*pji;
   tmp3pji = tmp3;
 
   // evaluate Nij conj
 
   Nijconj = 1.0+(NconjtmpI*NconjtmpI)+(NconjtmpJ*NconjtmpJ);
   piRC = piRCSpline(NijC+NijH,NjiC+NjiH,Nijconj,itype,jtype,dN3piRC);
   Tij = 0.0;
   dN3Tij[0] = 0.0;
   dN3Tij[1] = 0.0;
   dN3Tij[2] = 0.0;
   if (itype == 0 && jtype == 0)
     Tij=TijSpline((NijC+NijH),(NjiC+NjiH),Nijconj,dN3Tij);
 
   Etmp = 0.0;
   if (fabs(Tij) > TOL) {
     REBO_neighs_i = REBO_firstneigh[i];
     for (k = 0; k < REBO_numneigh[i]; k++) {
       atomk = REBO_neighs_i[k];
       ktype = map[type[atomk]];
       if (atomk != atomj) {
         rik[0] = x[atomi][0]-x[atomk][0];
         rik[1] = x[atomi][1]-x[atomk][1];
         rik[2] = x[atomi][2]-x[atomk][2];
         rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2]));
         cos321 = ((rij[0]*rik[0])+(rij[1]*rik[1])+(rij[2]*rik[2])) /
           (rijmag*rikmag);
         cos321 = MIN(cos321,1.0);
         cos321 = MAX(cos321,-1.0);
 
         rjk[0] = rik[0]-rij[0];
         rjk[1] = rik[1]-rij[1];
         rjk[2] = rik[2]-rij[2];
         rjk2 = (rjk[0]*rjk[0])+(rjk[1]*rjk[1])+(rjk[2]*rjk[2]);
         rij2 = rijmag*rijmag;
         rik2 = rikmag*rikmag;
         costmp = 0.5*(rij2+rik2-rjk2)/rijmag/rikmag;
         tspjik = Sp2(costmp,thmin,thmax,dtsjik);
 
         if (sqrt(1.0 - cos321*cos321) > sqrt(TOL)) {
           wik = Sp(rikmag,rcmin[itype][ktype],rcmaxp[itype][ktype],dwik);
           REBO_neighs_j = REBO_firstneigh[j];
           for (l = 0; l < REBO_numneigh[j]; l++) {
             atoml = REBO_neighs_j[l];
             ltype = map[type[atoml]];
             if (!(atoml == atomi || atoml == atomk)) {
               rjl[0] = x[atomj][0]-x[atoml][0];
               rjl[1] = x[atomj][1]-x[atoml][1];
               rjl[2] = x[atomj][2]-x[atoml][2];
               rjlmag = sqrt(rjl[0]*rjl[0] + rjl[1]*rjl[1] + rjl[2]*rjl[2]);
               cos234 = -((rij[0]*rjl[0])+(rij[1]*rjl[1])+(rij[2]*rjl[2])) /
                 (rijmag*rjlmag);
               cos234 = MIN(cos234,1.0);
               cos234 = MAX(cos234,-1.0);
 
               ril[0] = rij[0]+rjl[0];
               ril[1] = rij[1]+rjl[1];
               ril[2] = rij[2]+rjl[2];
               ril2 = (ril[0]*ril[0])+(ril[1]*ril[1])+(ril[2]*ril[2]);
               rijrjl = 2.0*rijmag*rjlmag;
               rjl2 = rjlmag*rjlmag;
               costmp = 0.5*(rij2+rjl2-ril2)/rijmag/rjlmag;
               tspijl = Sp2(costmp,thmin,thmax,dtsijl);
 
               if (sqrt(1.0 - cos234*cos234) > sqrt(TOL)) {
                 wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmaxp[jtype][ltype],dS);
                 crosskij[0] = (rij[1]*rik[2]-rij[2]*rik[1]);
                 crosskij[1] = (rij[2]*rik[0]-rij[0]*rik[2]);
                 crosskij[2] = (rij[0]*rik[1]-rij[1]*rik[0]);
                 crosskijmag = sqrt(crosskij[0]*crosskij[0] +
                                    crosskij[1]*crosskij[1] +
                                    crosskij[2]*crosskij[2]);
                 crossijl[0] = (rij[1]*rjl[2]-rij[2]*rjl[1]);
                 crossijl[1] = (rij[2]*rjl[0]-rij[0]*rjl[2]);
                 crossijl[2] = (rij[0]*rjl[1]-rij[1]*rjl[0]);
                 crossijlmag = sqrt(crossijl[0]*crossijl[0] +
                                    crossijl[1]*crossijl[1] +
                                    crossijl[2]*crossijl[2]);
                 omkijl = -1.0*(((crosskij[0]*crossijl[0]) +
                                 (crosskij[1]*crossijl[1]) +
                                 (crosskij[2]*crossijl[2])) /
                                (crosskijmag*crossijlmag));
                 Etmp += ((1.0-(omkijl*omkijl))*wik*wjl) *
                   (1.0-tspjik)*(1.0-tspijl);
               }
             }
           }
         }
       }
     }
   }
 
   bij = (.5*(pij+pji))+piRC+(Tij*Etmp);
   Stb = Sp2(bij,bLJmin[itype][jtype],bLJmax[itype][jtype],dStb);
   VA = VA*dStb;
 
   if (dStb != 0.0) {
     tmp = tmppij;
     dN2[0] = dN2PIJ[0];
     dN2[1] = dN2PIJ[1];
     tmp3 = tmp3pij;
 
     const double invrijm = 1.0/rijmag;
     const double invrijm2 = invrijm*invrijm;
 
     // pij forces
 
     REBO_neighs_i = REBO_firstneigh[i];
     for (k = 0; k < REBO_numneigh[i]; k++) {
       atomk = REBO_neighs_i[k];
       if (atomk != atomj) {
         lamdajik = 0.0;
         rik[0] = x[atomi][0]-x[atomk][0];
         rik[1] = x[atomi][1]-x[atomk][1];
         rik[2] = x[atomi][2]-x[atomk][2];
         rikmag = sqrt(rik[0]*rik[0] + rik[1]*rik[1] + rik[2]*rik[2]);
         lamdajik = 4.0*kronecker(itype,1) *
           ((rho[ktype][1]-rikmag)-(rho[jtype][1]-rijmag));
         wik = Sp(rikmag,rcmin[itype][ktype],rcmax[itype][ktype],dwik);
 
         const double invrikm = 1.0/rikmag;
         const double invrijkm = invrijm*invrikm;
         const double invrikm2 = invrikm*invrikm;
 
         cosjik = ((rij[0]*rik[0])+(rij[1]*rik[1])+(rij[2]*rik[2]))
           * invrijkm;
         cosjik = MIN(cosjik,1.0);
         cosjik = MAX(cosjik,-1.0);
 
         dcosjikdri[0] = ((rij[0]+rik[0])*invrijkm) -
           (cosjik*((rij[0]*invrijm2)+(rik[0]*invrikm2)));
         dcosjikdri[1] = ((rij[1]+rik[1])*invrijkm) -
           (cosjik*((rij[1]*invrijm2)+(rik[1]*invrikm2)));
         dcosjikdri[2] = ((rij[2]+rik[2])*invrijkm) -
           (cosjik*((rij[2]*invrijm2)+(rik[2]*invrikm2)));
         dcosjikdrk[0] = (-rij[0]*invrijkm) + (cosjik*(rik[0]*invrikm2));
         dcosjikdrk[1] = (-rij[1]*invrijkm) + (cosjik*(rik[1]*invrikm2));
         dcosjikdrk[2] = (-rij[2]*invrijkm) + (cosjik*(rik[2]*invrikm2));
         dcosjikdrj[0] = (-rik[0]*invrijkm) + (cosjik*(rij[0]*invrijm2));
         dcosjikdrj[1] = (-rik[1]*invrijkm) + (cosjik*(rij[1]*invrijm2));
         dcosjikdrj[2] = (-rik[2]*invrijkm) + (cosjik*(rij[2]*invrijm2));
 
         g = gSpline(cosjik,(NijC+NijH),itype,&dgdc,&dgdN);
 
         tmp2 = VA*.5*(tmp*wik*dgdc*exp(lamdajik));
         fj[0] = -tmp2*dcosjikdrj[0];
         fj[1] = -tmp2*dcosjikdrj[1];
         fj[2] = -tmp2*dcosjikdrj[2];
         fi[0] = -tmp2*dcosjikdri[0];
         fi[1] = -tmp2*dcosjikdri[1];
         fi[2] = -tmp2*dcosjikdri[2];
         fk[0] = -tmp2*dcosjikdrk[0];
         fk[1] = -tmp2*dcosjikdrk[1];
         fk[2] = -tmp2*dcosjikdrk[2];
 
         tmp2 = VA*.5*(tmp*wik*g*exp(lamdajik)*4.0*kronecker(itype,1));
         fj[0] -= tmp2*(-rij[0]*invrijm);
         fj[1] -= tmp2*(-rij[1]*invrijm);
         fj[2] -= tmp2*(-rij[2]*invrijm);
         fi[0] -= tmp2*((-rik[0]/rikmag)+(rij[0]*invrijm));
         fi[1] -= tmp2*((-rik[1]/rikmag)+(rij[1]*invrijm));
         fi[2] -= tmp2*((-rik[2]/rikmag)+(rij[2]*invrijm));
         fk[0] -= tmp2*(rik[0]/rikmag);
         fk[1] -= tmp2*(rik[1]/rikmag);
         fk[2] -= tmp2*(rik[2]/rikmag);
 
         // coordination forces
 
         // dwik forces
 
         tmp2 = VA*.5*(tmp*dwik*g*exp(lamdajik))/rikmag;
         fi[0] -= tmp2*rik[0];
         fi[1] -= tmp2*rik[1];
         fi[2] -= tmp2*rik[2];
         fk[0] += tmp2*rik[0];
         fk[1] += tmp2*rik[1];
         fk[2] += tmp2*rik[2];
 
         // PIJ forces
 
         tmp2 = VA*.5*(tmp*dN2[ktype]*dwik)/rikmag;
         fi[0] -= tmp2*rik[0];
         fi[1] -= tmp2*rik[1];
         fi[2] -= tmp2*rik[2];
         fk[0] += tmp2*rik[0];
         fk[1] += tmp2*rik[1];
         fk[2] += tmp2*rik[2];
 
         // dgdN forces
 
         tmp2 = VA*.5*(tmp*tmp3*dwik)/rikmag;
         fi[0] -= tmp2*rik[0];
         fi[1] -= tmp2*rik[1];
         fi[2] -= tmp2*rik[2];
         fk[0] += tmp2*rik[0];
         fk[1] += tmp2*rik[1];
         fk[2] += tmp2*rik[2];
 
         f[atomi][0] += fi[0]; f[atomi][1] += fi[1]; f[atomi][2] += fi[2];
         f[atomj][0] += fj[0]; f[atomj][1] += fj[1]; f[atomj][2] += fj[2];
         f[atomk][0] += fk[0]; f[atomk][1] += fk[1]; f[atomk][2] += fk[2];
 
         if (vflag_atom) {
           rji[0] = -rij[0]; rji[1] = -rij[1]; rji[2] = -rij[2];
           rki[0] = -rik[0]; rki[1] = -rik[1]; rki[2] = -rik[2];
           v_tally3_thr(atomi,atomj,atomk,fj,fk,rji,rki,thr);
         }
       }
     }
 
     tmp = tmppji;
     tmp3 = tmp3pji;
     dN2[0] = dN2PJI[0];
     dN2[1] = dN2PJI[1];
     REBO_neighs  =  REBO_firstneigh[j];
     for (l = 0; l < REBO_numneigh[j]; l++) {
       atoml = REBO_neighs[l];
       if (atoml !=atomi) {
         ltype = map[type[atoml]];
         rjl[0] = x[atomj][0]-x[atoml][0];
         rjl[1] = x[atomj][1]-x[atoml][1];
         rjl[2] = x[atomj][2]-x[atoml][2];
         rjlmag = sqrt((rjl[0]*rjl[0])+(rjl[1]*rjl[1])+(rjl[2]*rjl[2]));
         lamdaijl = 4.0*kronecker(jtype,1) *
           ((rho[ltype][1]-rjlmag)-(rho[itype][1]-rijmag));
         wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmax[jtype][ltype],dwjl);
 
         const double invrjlm = 1.0/rjlmag;
         const double invrijlm = invrijm*invrjlm;
         const double invrjlm2 = invrjlm*invrjlm;
 
         cosijl = (-1.0*((rij[0]*rjl[0])+(rij[1]*rjl[1])+(rij[2]*rjl[2]))) *
           invrijlm;
         cosijl = MIN(cosijl,1.0);
         cosijl = MAX(cosijl,-1.0);
 
         dcosijldri[0] = (-rjl[0]*invrijlm) - (cosijl*rij[0]*invrijm2);
         dcosijldri[1] = (-rjl[1]*invrijlm) - (cosijl*rij[1]*invrijm2);
         dcosijldri[2] = (-rjl[2]*invrijlm) - (cosijl*rij[2]*invrijm2);
         dcosijldrj[0] = ((-rij[0]+rjl[0])*invrijlm) +
           (cosijl*((rij[0]*invrijm2)-(rjl[0]*invrjlm2)));
         dcosijldrj[1] = ((-rij[1]+rjl[1])*invrijlm) +
           (cosijl*((rij[1]*invrijm2)-(rjl[1]*invrjlm2)));
         dcosijldrj[2] = ((-rij[2]+rjl[2])*invrijlm) +
           (cosijl*((rij[2]*invrijm2)-(rjl[2]*invrjlm2)));
         dcosijldrl[0] = (rij[0]*invrijlm) + (cosijl*rjl[0]*invrjlm2);
         dcosijldrl[1] = (rij[1]*invrijlm) + (cosijl*rjl[1]*invrjlm2);
         dcosijldrl[2] = (rij[2]*invrijlm) + (cosijl*rjl[2]*invrjlm2);
 
         // evaluate splines g and derivatives dg
 
         g = gSpline(cosijl,NjiC+NjiH,jtype,&dgdc,&dgdN);
         tmp2 = VA*.5*(tmp*wjl*dgdc*exp(lamdaijl));
         fi[0] = -tmp2*dcosijldri[0];
         fi[1] = -tmp2*dcosijldri[1];
         fi[2] = -tmp2*dcosijldri[2];
         fj[0] = -tmp2*dcosijldrj[0];
         fj[1] = -tmp2*dcosijldrj[1];
         fj[2] = -tmp2*dcosijldrj[2];
         fl[0] = -tmp2*dcosijldrl[0];
         fl[1] = -tmp2*dcosijldrl[1];
         fl[2] = -tmp2*dcosijldrl[2];
 
         tmp2 = VA*.5*(tmp*wjl*g*exp(lamdaijl)*4.0*kronecker(jtype,1));
         fi[0] -= tmp2*(rij[0]*invrijm);
         fi[1] -= tmp2*(rij[1]*invrijm);
         fi[2] -= tmp2*(rij[2]*invrijm);
         fj[0] -= tmp2*((-rjl[0]*invrjlm)-(rij[0]*invrijm));
         fj[1] -= tmp2*((-rjl[1]*invrjlm)-(rij[1]*invrijm));
         fj[2] -= tmp2*((-rjl[2]*invrjlm)-(rij[2]*invrijm));
         fl[0] -= tmp2*(rjl[0]*invrjlm);
         fl[1] -= tmp2*(rjl[1]*invrjlm);
         fl[2] -= tmp2*(rjl[2]*invrjlm);
 
          // coordination forces
         // dwik forces
 
         tmp2 = VA*.5*(tmp*dwjl*g*exp(lamdaijl))*invrjlm;
         fj[0] -= tmp2*rjl[0];
         fj[1] -= tmp2*rjl[1];
         fj[2] -= tmp2*rjl[2];
         fl[0] += tmp2*rjl[0];
         fl[1] += tmp2*rjl[1];
         fl[2] += tmp2*rjl[2];
 
         // PIJ forces
 
         tmp2 = VA*.5*(tmp*dN2[ltype]*dwjl)*invrjlm;
         fj[0] -= tmp2*rjl[0];
         fj[1] -= tmp2*rjl[1];
         fj[2] -= tmp2*rjl[2];
         fl[0] += tmp2*rjl[0];
         fl[1] += tmp2*rjl[1];
         fl[2] += tmp2*rjl[2];
 
         // dgdN forces
 
         tmp2=VA*.5*(tmp*tmp3*dwjl)*invrjlm;
         fj[0] -= tmp2*rjl[0];
         fj[1] -= tmp2*rjl[1];
         fj[2] -= tmp2*rjl[2];
         fl[0] += tmp2*rjl[0];
         fl[1] += tmp2*rjl[1];
         fl[2] += tmp2*rjl[2];
 
         f[atomi][0] += fi[0]; f[atomi][1] += fi[1]; f[atomi][2] += fi[2];
         f[atomj][0] += fj[0]; f[atomj][1] += fj[1]; f[atomj][2] += fj[2];
         f[atoml][0] += fl[0]; f[atoml][1] += fl[1]; f[atoml][2] += fl[2];
 
         if (vflag_atom) {
           rlj[0] = -rjl[0]; rlj[1] = -rjl[1]; rlj[2] = -rjl[2];
           v_tally3_thr(atomi,atomj,atoml,fi,fl,rij,rlj,thr);
         }
       }
     }
 
     // piRC forces
 
     dN3[0] = dN3piRC[0];
     dN3[1] = dN3piRC[1];
     dN3[2] = dN3piRC[2];
 
     REBO_neighs_i = REBO_firstneigh[i];
     for (k = 0; k < REBO_numneigh[i]; k++) {
       atomk = REBO_neighs_i[k];
       if (atomk != atomj) {
         ktype = map[type[atomk]];
         rik[0] = x[atomi][0]-x[atomk][0];
         rik[1] = x[atomi][1]-x[atomk][1];
         rik[2] = x[atomi][2]-x[atomk][2];
         rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2]));
         wik = Sp(rikmag,rcmin[itype][ktype],rcmax[itype][ktype],dwik);
         Nki = nC[atomk]-(wik*kronecker(itype,0))+nH[atomk] -
           (wik*kronecker(itype,1));
         SpN = Sp(Nki,Nmin,Nmax,dNki);
 
         tmp2 = VA*dN3[0]*dwik/rikmag;
         f[atomi][0] -= tmp2*rik[0];
         f[atomi][1] -= tmp2*rik[1];
         f[atomi][2] -= tmp2*rik[2];
         f[atomk][0] += tmp2*rik[0];
         f[atomk][1] += tmp2*rik[1];
         f[atomk][2] += tmp2*rik[2];
 
         if (vflag_atom) v_tally2_thr(atomi,atomk,-tmp2,rik,thr);
 
         tmp2 = VA*dN3[2]*(2.0*NconjtmpI*dwik*SpN)/rikmag;
         f[atomi][0] -= tmp2*rik[0];
         f[atomi][1] -= tmp2*rik[1];
         f[atomi][2] -= tmp2*rik[2];
         f[atomk][0] += tmp2*rik[0];
         f[atomk][1] += tmp2*rik[1];
         f[atomk][2] += tmp2*rik[2];
 
         if (vflag_atom) v_tally2_thr(atomi,atomk,-tmp2,rik,thr);
 
         if (fabs(dNki) > TOL) {
           REBO_neighs_k = REBO_firstneigh[atomk];
           for (n = 0; n < REBO_numneigh[atomk]; n++) {
             atomn = REBO_neighs_k[n];
             if (atomn != atomi) {
               ntype = map[type[atomn]];
               rkn[0] = x[atomk][0]-x[atomn][0];
               rkn[1] = x[atomk][1]-x[atomn][1];
               rkn[2] = x[atomk][2]-x[atomn][2];
               rknmag = sqrt((rkn[0]*rkn[0])+(rkn[1]*rkn[1])+(rkn[2]*rkn[2]));
               Sp(rknmag,rcmin[ktype][ntype],rcmax[ktype][ntype],dwkn);
 
               tmp2 = VA*dN3[2]*(2.0*NconjtmpI*wik*dNki*dwkn)/rknmag;
               f[atomk][0] -= tmp2*rkn[0];
               f[atomk][1] -= tmp2*rkn[1];
               f[atomk][2] -= tmp2*rkn[2];
               f[atomn][0] += tmp2*rkn[0];
               f[atomn][1] += tmp2*rkn[1];
               f[atomn][2] += tmp2*rkn[2];
 
               if (vflag_atom) v_tally2_thr(atomk,atomn,-tmp2,rkn,thr);
             }
           }
         }
       }
     }
 
     // piRC forces to J side
 
     REBO_neighs = REBO_firstneigh[j];
     for (l = 0; l < REBO_numneigh[j]; l++) {
       atoml = REBO_neighs[l];
       if (atoml != atomi) {
         ltype = map[type[atoml]];
         rjl[0] = x[atomj][0]-x[atoml][0];
         rjl[1] = x[atomj][1]-x[atoml][1];
         rjl[2] = x[atomj][2]-x[atoml][2];
         rjlmag = sqrt((rjl[0]*rjl[0])+(rjl[1]*rjl[1])+(rjl[2]*rjl[2]));
         wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmax[jtype][ltype],dwjl);
         Nlj = nC[atoml]-(wjl*kronecker(jtype,0))+nH[atoml] -
           (wjl*kronecker(jtype,1));
         SpN = Sp(Nlj,Nmin,Nmax,dNlj);
 
         tmp2 = VA*dN3[1]*dwjl/rjlmag;
         f[atomj][0] -= tmp2*rjl[0];
         f[atomj][1] -= tmp2*rjl[1];
         f[atomj][2] -= tmp2*rjl[2];
         f[atoml][0] += tmp2*rjl[0];
         f[atoml][1] += tmp2*rjl[1];
         f[atoml][2] += tmp2*rjl[2];
 
         if (vflag_atom) v_tally2_thr(atomj,atoml,-tmp2,rjl,thr);
 
         tmp2 = VA*dN3[2]*(2.0*NconjtmpJ*dwjl*SpN)/rjlmag;
         f[atomj][0] -= tmp2*rjl[0];
         f[atomj][1] -= tmp2*rjl[1];
         f[atomj][2] -= tmp2*rjl[2];
         f[atoml][0] += tmp2*rjl[0];
         f[atoml][1] += tmp2*rjl[1];
         f[atoml][2] += tmp2*rjl[2];
 
         if (vflag_atom) v_tally2_thr(atomj,atoml,-tmp2,rjl,thr);
 
         if (fabs(dNlj) > TOL) {
           REBO_neighs_l = REBO_firstneigh[atoml];
           for (n = 0; n < REBO_numneigh[atoml]; n++) {
             atomn = REBO_neighs_l[n];
             if (atomn != atomj) {
               ntype = map[type[atomn]];
               rln[0] = x[atoml][0]-x[atomn][0];
               rln[1] = x[atoml][1]-x[atomn][1];
               rln[2] = x[atoml][2]-x[atomn][2];
               rlnmag = sqrt((rln[0]*rln[0])+(rln[1]*rln[1])+(rln[2]*rln[2]));
               Sp(rlnmag,rcmin[ltype][ntype],rcmax[ltype][ntype],dwln);
 
               tmp2 = VA*dN3[2]*(2.0*NconjtmpJ*wjl*dNlj*dwln)/rlnmag;
               f[atoml][0] -= tmp2*rln[0];
               f[atoml][1] -= tmp2*rln[1];
               f[atoml][2] -= tmp2*rln[2];
               f[atomn][0] += tmp2*rln[0];
               f[atomn][1] += tmp2*rln[1];
               f[atomn][2] += tmp2*rln[2];
 
               if (vflag_atom) v_tally2_thr(atoml,atomn,-tmp2,rln,thr);
             }
           }
         }
       }
     }
 
     if (fabs(Tij) > TOL) {
       dN3[0] = dN3Tij[0];
       dN3[1] = dN3Tij[1];
       dN3[2] = dN3Tij[2];
       atom2 = atomi;
       atom3 = atomj;
       r32[0] = x[atom3][0]-x[atom2][0];
       r32[1] = x[atom3][1]-x[atom2][1];
       r32[2] = x[atom3][2]-x[atom2][2];
       r32mag = sqrt((r32[0]*r32[0])+(r32[1]*r32[1])+(r32[2]*r32[2]));
       r23[0] = -r32[0];
       r23[1] = -r32[1];
       r23[2] = -r32[2];
       r23mag = r32mag;
 
       REBO_neighs_i = REBO_firstneigh[i];
       for (k = 0; k < REBO_numneigh[i]; k++) {
         atomk = REBO_neighs_i[k];
         atom1 = atomk;
         ktype = map[type[atomk]];
         if (atomk != atomj) {
           r21[0] = x[atom2][0]-x[atom1][0];
           r21[1] = x[atom2][1]-x[atom1][1];
           r21[2] = x[atom2][2]-x[atom1][2];
           r21mag = sqrt(r21[0]*r21[0] + r21[1]*r21[1] + r21[2]*r21[2]);
           cos321 = ((r21[0]*rij[0])+(r21[1]*rij[1])+(r21[2]*rij[2])) /
             (r21mag*rijmag);
           cos321 = MIN(cos321,1.0);
           cos321 = MAX(cos321,-1.0);
           sin321 = sqrt(1.0 - cos321*cos321);
           sink2i = 1.0/(sin321*sin321);
           rik2i = 1.0/(r21mag*r21mag);
 
           if (sin321 != 0.0) {
             rr = (rijmag*rijmag)-(r21mag*r21mag);
             rjk[0] = r21[0]-rij[0];
             rjk[1] = r21[1]-rij[1];
             rjk[2] = r21[2]-rij[2];
             rjk2 = (rjk[0]*rjk[0])+(rjk[1]*rjk[1])+(rjk[2]*rjk[2]);
             rijrik = 2.0*rijmag*r21mag;
             rik2 = r21mag*r21mag;
             dctik = (-rr+rjk2)/(rijrik*rik2);
             dctij = (rr+rjk2)/(rijrik*rijmag*rijmag);
             dctjk = -2.0/rijrik;
             w21 = Sp(r21mag,rcmin[itype][ktype],rcmaxp[itype][ktype],dw21);
             rikmag = r21mag;
             rij2 = r32mag*r32mag;
             rik2 = r21mag*r21mag;
             costmp = 0.5*(rij2+rik2-rjk2)/rijmag/rikmag;
             tspjik = Sp2(costmp,thmin,thmax,dtsjik);
             dtsjik = -dtsjik;
 
             REBO_neighs_j = REBO_firstneigh[j];
             for (l = 0; l < REBO_numneigh[j]; l++) {
               atoml = REBO_neighs_j[l];
               atom4 = atoml;
               ltype = map[type[atoml]];
               if (!(atoml == atomi || atoml == atomk)) {
                 r34[0] = x[atom3][0]-x[atom4][0];
                 r34[1] = x[atom3][1]-x[atom4][1];
                 r34[2] = x[atom3][2]-x[atom4][2];
                 r34mag = sqrt(r34[0]*r34[0] + r34[1]*r34[1] + r34[2]*r34[2]);
                 cos234 = -1.0*((rij[0]*r34[0])+(rij[1]*r34[1]) +
                                (rij[2]*r34[2]))/(rijmag*r34mag);
                 cos234 = MIN(cos234,1.0);
                 cos234 = MAX(cos234,-1.0);
                 sin234 = sqrt(1.0 - cos234*cos234);
                 sinl2i = 1.0/(sin234*sin234);
                 rjl2i = 1.0/(r34mag*r34mag);
 
                 if (sin234 != 0.0) {
                   w34 = Sp(r34mag,rcmin[jtype][ltype],
                            rcmaxp[jtype][ltype],dw34);
                   rr = (r23mag*r23mag)-(r34mag*r34mag);
                   ril[0] = r23[0]+r34[0];
                   ril[1] = r23[1]+r34[1];
                   ril[2] = r23[2]+r34[2];
                   ril2 = (ril[0]*ril[0])+(ril[1]*ril[1])+(ril[2]*ril[2]);
                   rijrjl = 2.0*r23mag*r34mag;
                   rjl2 = r34mag*r34mag;
                   dctjl = (-rr+ril2)/(rijrjl*rjl2);
                   dctji = (rr+ril2)/(rijrjl*r23mag*r23mag);
                   dctil = -2.0/rijrjl;
                   rjlmag = r34mag;
                   rjl2 = r34mag*r34mag;
                   costmp = 0.5*(rij2+rjl2-ril2)/rijmag/rjlmag;
                   tspijl = Sp2(costmp,thmin,thmax,dtsijl);
                   dtsijl = -dtsijl; //need minus sign
                   prefactor = VA*Tij;
 
                   cross321[0] = (r32[1]*r21[2])-(r32[2]*r21[1]);
                   cross321[1] = (r32[2]*r21[0])-(r32[0]*r21[2]);
                   cross321[2] = (r32[0]*r21[1])-(r32[1]*r21[0]);
                   cross234[0] = (r23[1]*r34[2])-(r23[2]*r34[1]);
                   cross234[1] = (r23[2]*r34[0])-(r23[0]*r34[2]);
                   cross234[2] = (r23[0]*r34[1])-(r23[1]*r34[0]);
 
                   cwnum = (cross321[0]*cross234[0]) +
                     (cross321[1]*cross234[1])+(cross321[2]*cross234[2]);
                   cwnom = r21mag*r34mag*r23mag*r23mag*sin321*sin234;
                   om1234 = cwnum/cwnom;
                   cw = om1234;
                   Etmp += ((1.0-(om1234*om1234))*w21*w34) *
                     (1.0-tspjik)*(1.0-tspijl);
 
                   dt1dik = (rik2i)-(dctik*sink2i*cos321);
                   dt1djk = (-dctjk*sink2i*cos321);
                   dt1djl = (rjl2i)-(dctjl*sinl2i*cos234);
                   dt1dil = (-dctil*sinl2i*cos234);
                   dt1dij = (2.0/(r23mag*r23mag)) -
                     (dctij*sink2i*cos321)-(dctji*sinl2i*cos234);
 
                   dt2dik[0] = (-r23[2]*cross234[1])+(r23[1]*cross234[2]);
                   dt2dik[1] = (-r23[0]*cross234[2])+(r23[2]*cross234[0]);
                   dt2dik[2] = (-r23[1]*cross234[0])+(r23[0]*cross234[1]);
 
                   dt2djl[0] = (-r23[1]*cross321[2])+(r23[2]*cross321[1]);
                   dt2djl[1] = (-r23[2]*cross321[0])+(r23[0]*cross321[2]);
                   dt2djl[2] = (-r23[0]*cross321[1])+(r23[1]*cross321[0]);
 
                   dt2dij[0] = (r21[2]*cross234[1]) -
                     (r34[2]*cross321[1])-(r21[1]*cross234[2]) +
                     (r34[1]*cross321[2]);
                   dt2dij[1] = (r21[0]*cross234[2]) -
                     (r34[0]*cross321[2])-(r21[2]*cross234[0]) +
                     (r34[2]*cross321[0]);
                   dt2dij[2] = (r21[1]*cross234[0]) -
                     (r34[1]*cross321[0])-(r21[0]*cross234[1]) +
                     (r34[0]*cross321[1]);
 
                   aa = (prefactor*2.0*cw/cwnom)*w21*w34 *
                     (1.0-tspjik)*(1.0-tspijl);
                   aaa1 = -prefactor*(1.0-(om1234*om1234)) *
                     (1.0-tspjik)*(1.0-tspijl);
                   aaa2 = aaa1*w21*w34;
                   at2 = aa*cwnum;
 
                   fcijpc = (-dt1dij*at2)+(aaa2*dtsjik*dctij*(1.0-tspijl)) +
                     (aaa2*dtsijl*dctji*(1.0-tspjik));
                   fcikpc = (-dt1dik*at2)+(aaa2*dtsjik*dctik*(1.0-tspijl));
                   fcjlpc = (-dt1djl*at2)+(aaa2*dtsijl*dctjl*(1.0-tspjik));
                   fcjkpc = (-dt1djk*at2)+(aaa2*dtsjik*dctjk*(1.0-tspijl));
                   fcilpc = (-dt1dil*at2)+(aaa2*dtsijl*dctil*(1.0-tspjik));
 
                   F23[0] = (fcijpc*r23[0])+(aa*dt2dij[0]);
                   F23[1] = (fcijpc*r23[1])+(aa*dt2dij[1]);
                   F23[2] = (fcijpc*r23[2])+(aa*dt2dij[2]);
 
                   F12[0] = (fcikpc*r21[0])+(aa*dt2dik[0]);
                   F12[1] = (fcikpc*r21[1])+(aa*dt2dik[1]);
                   F12[2] = (fcikpc*r21[2])+(aa*dt2dik[2]);
 
                   F34[0] = (fcjlpc*r34[0])+(aa*dt2djl[0]);
                   F34[1] = (fcjlpc*r34[1])+(aa*dt2djl[1]);
                   F34[2] = (fcjlpc*r34[2])+(aa*dt2djl[2]);
 
                   F31[0] = (fcjkpc*rjk[0]);
                   F31[1] = (fcjkpc*rjk[1]);
                   F31[2] = (fcjkpc*rjk[2]);
 
                   F24[0] = (fcilpc*ril[0]);
                   F24[1] = (fcilpc*ril[1]);
                   F24[2] = (fcilpc*ril[2]);
 
                   f1[0] = -F12[0]-F31[0];
                   f1[1] = -F12[1]-F31[1];
                   f1[2] = -F12[2]-F31[2];
                   f2[0] = F23[0]+F12[0]+F24[0];
                   f2[1] = F23[1]+F12[1]+F24[1];
                   f2[2] = F23[2]+F12[2]+F24[2];
                   f3[0] = -F23[0]+F34[0]+F31[0];
                   f3[1] = -F23[1]+F34[1]+F31[1];
                   f3[2] = -F23[2]+F34[2]+F31[2];
                   f4[0] = -F34[0]-F24[0];
                   f4[1] = -F34[1]-F24[1];
                   f4[2] = -F34[2]-F24[2];
 
                   // coordination forces
 
                   tmp2 = VA*Tij*((1.0-(om1234*om1234))) *
                     (1.0-tspjik)*(1.0-tspijl)*dw21*w34/r21mag;
                   f2[0] -= tmp2*r21[0];
                   f2[1] -= tmp2*r21[1];
                   f2[2] -= tmp2*r21[2];
                   f1[0] += tmp2*r21[0];
                   f1[1] += tmp2*r21[1];
                   f1[2] += tmp2*r21[2];
 
                   tmp2 = VA*Tij*((1.0-(om1234*om1234))) *
                     (1.0-tspjik)*(1.0-tspijl)*w21*dw34/r34mag;
                   f3[0] -= tmp2*r34[0];
                   f3[1] -= tmp2*r34[1];
                   f3[2] -= tmp2*r34[2];
                   f4[0] += tmp2*r34[0];
                   f4[1] += tmp2*r34[1];
                   f4[2] += tmp2*r34[2];
 
                   f[atom1][0] += f1[0]; f[atom1][1] += f1[1];
                   f[atom1][2] += f1[2];
                   f[atom2][0] += f2[0]; f[atom2][1] += f2[1];
                   f[atom2][2] += f2[2];
                   f[atom3][0] += f3[0]; f[atom3][1] += f3[1];
                   f[atom3][2] += f3[2];
                   f[atom4][0] += f4[0]; f[atom4][1] += f4[1];
                   f[atom4][2] += f4[2];
 
                   if (vflag_atom) {
                     r13[0] = -rjk[0]; r13[1] = -rjk[1]; r13[2] = -rjk[2];
                     r43[0] = -r34[0]; r43[1] = -r34[1]; r43[2] = -r34[2];
                     v_tally4_thr(atom1,atom2,atom3,atom4,f1,f2,f4,r13,r23,r43,thr);
                   }
                 }
               }
             }
           }
         }
       }
 
       REBO_neighs = REBO_firstneigh[i];
       for (k = 0; k < REBO_numneigh[i]; k++) {
         atomk = REBO_neighs[k];
         if (atomk != atomj) {
           ktype = map[type[atomk]];
           rik[0] = x[atomi][0]-x[atomk][0];
           rik[1] = x[atomi][1]-x[atomk][1];
           rik[2] = x[atomi][2]-x[atomk][2];
           rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2]));
           wik = Sp(rikmag,rcmin[itype][ktype],rcmax[itype][ktype],dwik);
           Nki = nC[atomk]-(wik*kronecker(itype,0))+nH[atomk] -
             (wik*kronecker(itype,1));
           SpN = Sp(Nki,Nmin,Nmax,dNki);
 
           tmp2 = VA*dN3[0]*dwik*Etmp/rikmag;
           f[atomi][0] -= tmp2*rik[0];
           f[atomi][1] -= tmp2*rik[1];
           f[atomi][2] -= tmp2*rik[2];
           f[atomk][0] += tmp2*rik[0];
           f[atomk][1] += tmp2*rik[1];
           f[atomk][2] += tmp2*rik[2];
 
           if (vflag_atom) v_tally2_thr(atomi,atomk,-tmp2,rik,thr);
 
           tmp2 = VA*dN3[2]*(2.0*NconjtmpI*dwik*SpN)*Etmp/rikmag;
           f[atomi][0] -= tmp2*rik[0];
           f[atomi][1] -= tmp2*rik[1];
           f[atomi][2] -= tmp2*rik[2];
           f[atomk][0] += tmp2*rik[0];
           f[atomk][1] += tmp2*rik[1];
           f[atomk][2] += tmp2*rik[2];
 
           if (vflag_atom) v_tally2_thr(atomi,atomk,-tmp2,rik,thr);
 
           if (fabs(dNki)  >TOL) {
             REBO_neighs_k = REBO_firstneigh[atomk];
             for (n = 0; n < REBO_numneigh[atomk]; n++) {
               atomn = REBO_neighs_k[n];
               ntype = map[type[atomn]];
               if (atomn !=atomi) {
                 rkn[0] = x[atomk][0]-x[atomn][0];
                 rkn[1] = x[atomk][1]-x[atomn][1];
                 rkn[2] = x[atomk][2]-x[atomn][2];
                 rknmag = sqrt((rkn[0]*rkn[0])+(rkn[1]*rkn[1])+(rkn[2]*rkn[2]));
                 Sp(rknmag,rcmin[ktype][ntype],rcmax[ktype][ntype],dwkn);
 
                 tmp2 = VA*dN3[2]*(2.0*NconjtmpI*wik*dNki*dwkn)*Etmp/rknmag;
                 f[atomk][0] -= tmp2*rkn[0];
                 f[atomk][1] -= tmp2*rkn[1];
                 f[atomk][2] -= tmp2*rkn[2];
                 f[atomn][0] += tmp2*rkn[0];
                 f[atomn][1] += tmp2*rkn[1];
                 f[atomn][2] += tmp2*rkn[2];
 
                 if (vflag_atom) v_tally2_thr(atomk,atomn,-tmp2,rkn,thr);
               }
             }
           }
         }
       }
 
       // Tij forces
 
       REBO_neighs = REBO_firstneigh[j];
       for (l = 0; l < REBO_numneigh[j]; l++) {
         atoml = REBO_neighs[l];
         if (atoml != atomi) {
           ltype = map[type[atoml]];
           rjl[0] = x[atomj][0]-x[atoml][0];
           rjl[1] = x[atomj][1]-x[atoml][1];
           rjl[2] = x[atomj][2]-x[atoml][2];
           rjlmag = sqrt((rjl[0]*rjl[0])+(rjl[1]*rjl[1])+(rjl[2]*rjl[2]));
           wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmax[jtype][ltype],dwjl);
           Nlj = nC[atoml]-(wjl*kronecker(jtype,0))+nH[atoml] -
             (wjl*kronecker(jtype,1));
           SpN = Sp(Nlj,Nmin,Nmax,dNlj);
 
           tmp2 = VA*dN3[1]*dwjl*Etmp/rjlmag;
           f[atomj][0] -= tmp2*rjl[0];
           f[atomj][1] -= tmp2*rjl[1];
           f[atomj][2] -= tmp2*rjl[2];
           f[atoml][0] += tmp2*rjl[0];
           f[atoml][1] += tmp2*rjl[1];
           f[atoml][2] += tmp2*rjl[2];
 
           if (vflag_atom) v_tally2_thr(atomj,atoml,-tmp2,rjl,thr);
 
           tmp2 = VA*dN3[2]*(2.0*NconjtmpJ*dwjl*SpN)*Etmp/rjlmag;
           f[atomj][0] -= tmp2*rjl[0];
           f[atomj][1] -= tmp2*rjl[1];
           f[atomj][2] -= tmp2*rjl[2];
           f[atoml][0] += tmp2*rjl[0];
           f[atoml][1] += tmp2*rjl[1];
           f[atoml][2] += tmp2*rjl[2];
 
           if (vflag_atom) v_tally2_thr(atomj,atoml,-tmp2,rjl,thr);
 
           if (fabs(dNlj) > TOL) {
             REBO_neighs_l = REBO_firstneigh[atoml];
             for (n = 0; n < REBO_numneigh[atoml]; n++) {
               atomn = REBO_neighs_l[n];
               ntype = map[type[atomn]];
               if (atomn != atomj) {
                 rln[0] = x[atoml][0]-x[atomn][0];
                 rln[1] = x[atoml][1]-x[atomn][1];
                 rln[2] = x[atoml][2]-x[atomn][2];
                 rlnmag = sqrt((rln[0]*rln[0])+(rln[1]*rln[1])+(rln[2]*rln[2]));
                 Sp(rlnmag,rcmin[ltype][ntype],rcmax[ltype][ntype],dwln);
 
                 tmp2 = VA*dN3[2]*(2.0*NconjtmpJ*wjl*dNlj*dwln)*Etmp/rlnmag;
                 f[atoml][0] -= tmp2*rln[0];
                 f[atoml][1] -= tmp2*rln[1];
                 f[atoml][2] -= tmp2*rln[2];
                 f[atomn][0] += tmp2*rln[0];
                 f[atomn][1] += tmp2*rln[1];
                 f[atomn][2] += tmp2*rln[2];
 
                 if (vflag_atom) v_tally2_thr(atoml,atomn,-tmp2,rln,thr);
               }
             }
           }
         }
       }
     }
   }
 
   return Stb;
 }
 
 /* ----------------------------------------------------------------------
    REBO forces and energy
 ------------------------------------------------------------------------- */
 
 void PairAIREBOOMP::FREBO_thr(int ifrom, int ito, int evflag, int eflag,
                               int vflag_atom, ThrData * const thr)
 {
   int i,j,k,m,ii,itype,jtype,itag,jtag;
   double delx,dely,delz,evdwl,fpair,xtmp,ytmp,ztmp;
   double rsq,rij,wij;
   double Qij,Aij,alphaij,VR,pre,dVRdi,VA,term,bij,dVAdi,dVA;
   double dwij,del[3];
   int *ilist,*REBO_neighs;
 
   evdwl = 0.0;
 
   const double * const * const x = atom->x;
   double * const * const f = thr->get_f();
   int *type = atom->type;
   int *tag = atom->tag;
   int nlocal = atom->nlocal;
 
   ilist = list->ilist;
 
   // two-body interactions from REBO neighbor list, skip half of them
 
   for (ii = ifrom; ii < ito; ii++) {
     i = ilist[ii];
     itag = tag[i];
     itype = map[type[i]];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
     REBO_neighs = REBO_firstneigh[i];
 
     for (k = 0; k < REBO_numneigh[i]; k++) {
       j = REBO_neighs[k];
       jtag = tag[j];
 
       if (itag > jtag) {
         if ((itag+jtag) % 2 == 0) continue;
       } else if (itag < jtag) {
         if ((itag+jtag) % 2 == 1) continue;
       } else {
         if (x[j][2] < ztmp) continue;
         if (x[j][2] == ztmp && x[j][1] < ytmp) continue;
         if (x[j][2] == ztmp && x[j][1] == ytmp && x[j][0] < xtmp) continue;
       }
 
       jtype = map[type[j]];
 
       delx = x[i][0] - x[j][0];
       dely = x[i][1] - x[j][1];
       delz = x[i][2] - x[j][2];
       rsq = delx*delx + dely*dely + delz*delz;
       rij = sqrt(rsq);
       wij = Sp(rij,rcmin[itype][jtype],rcmax[itype][jtype],dwij);
       if (wij <= TOL) continue;
 
       Qij = Q[itype][jtype];
       Aij = A[itype][jtype];
       alphaij = alpha[itype][jtype];
 
       VR = wij*(1.0+(Qij/rij)) * Aij*exp(-alphaij*rij);
       pre = wij*Aij * exp(-alphaij*rij);
       dVRdi = pre * ((-alphaij)-(Qij/rsq)-(Qij*alphaij/rij));
       dVRdi += VR/wij * dwij;
 
       VA = dVA = 0.0;
       for (m = 0; m < 3; m++) {
         term = -wij * BIJc[itype][jtype][m] * exp(-Beta[itype][jtype][m]*rij);
         VA += term;
         dVA += -Beta[itype][jtype][m] * term;
       }
       dVA += VA/wij * dwij;
       del[0] = delx;
       del[1] = dely;
       del[2] = delz;
       bij = bondorder_thr(i,j,del,rij,VA,vflag_atom,thr);
       dVAdi = bij*dVA;
 
       fpair = -(dVRdi+dVAdi) / rij;
       f[i][0] += delx*fpair;
       f[i][1] += dely*fpair;
       f[i][2] += delz*fpair;
       f[j][0] -= delx*fpair;
       f[j][1] -= dely*fpair;
       f[j][2] -= delz*fpair;
 
       if (eflag) evdwl = VR + bij*VA;
       if (evflag) ev_tally_thr(this,i,j,nlocal,/* newton_pair */ 1,
                                evdwl,0.0,fpair,delx,dely,delz,thr);
     }
   }
 }
 
 /* ----------------------------------------------------------------------
    compute LJ forces and energy
    find 3- and 4-step paths between atoms I,J via REBO neighbor lists
 ------------------------------------------------------------------------- */
 
 void PairAIREBOOMP::FLJ_thr(int ifrom, int ito, int evflag, int eflag,
                             int vflag_atom, ThrData * const thr)
 {
   int i,j,k,m,ii,jj,kk,mm,jnum,itype,jtype,ktype,mtype,itag,jtag;
   int atomi,atomj,atomk,atomm;
   int testpath,npath,done;
   double evdwl,fpair,xtmp,ytmp,ztmp;
   double rsq,best,wik,wkm,cij,rij,dwij,dwik,dwkj,dwkm,dwmj;
   double delij[3],rijsq,delik[3],rik,deljk[3];
   double rkj,wkj,dC,VLJ,dVLJ,VA,Str,dStr,Stb;
   double vdw,slw,dvdw,dslw,drij,swidth,tee,tee2;
   double rljmin,rljmax,sigcut,sigmin,sigwid;
   double delkm[3],rkm,deljm[3],rmj,wmj,r2inv,r6inv,scale,delscale[3];
   int *ilist,*jlist,*numneigh,**firstneigh;
   int *REBO_neighs_i,*REBO_neighs_k;
   double delikS[3],deljkS[3],delkmS[3],deljmS[3],delimS[3];
   double rikS,rkjS,rkmS,rmjS,wikS,dwikS;
   double wkjS,dwkjS,wkmS,dwkmS,wmjS,dwmjS;
   double fpair1,fpair2,fpair3;
   double fi[3],fj[3],fk[3],fm[3];
 
   // I-J interaction from full neighbor list
   // skip 1/2 of interactions since only consider each pair once
 
   evdwl = 0.0;
   rljmin = 0.0;
   rljmax = 0.0;
   sigcut = 0.0;
   sigmin = 0.0;
   sigwid = 0.0;
 
   const double * const * const x = atom->x;
   double * const * const f = thr->get_f();
   int *tag = atom->tag;
   int *type = atom->type;
   int nlocal = atom->nlocal;
 
   ilist = list->ilist;
   numneigh = list->numneigh;
   firstneigh = list->firstneigh;
 
   // loop over neighbors of my atoms
 
   for (ii = ifrom; ii < ito; ii++) {
     i = ilist[ii];
     itag = tag[i];
     itype = map[type[i]];
     atomi = i;
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
     jlist = firstneigh[i];
     jnum = numneigh[i];
 
     for (jj = 0; jj < jnum; jj++) {
       j = jlist[jj];
       j &= NEIGHMASK;
       jtag = tag[j];
 
       if (itag > jtag) {
         if ((itag+jtag) % 2 == 0) continue;
       } else if (itag < jtag) {
         if ((itag+jtag) % 2 == 1) continue;
       } else {
         if (x[j][2] < ztmp) continue;
         if (x[j][2] == ztmp && x[j][1] < ytmp) continue;
         if (x[j][2] == ztmp && x[j][1] == ytmp && x[j][0] < xtmp) continue;
       }
 
       jtype = map[type[j]];
       atomj = j;
 
       delij[0] = xtmp - x[j][0];
       delij[1] = ytmp - x[j][1];
       delij[2] = ztmp - x[j][2];
       rijsq = delij[0]*delij[0] + delij[1]*delij[1] + delij[2]*delij[2];
 
       // if outside of LJ cutoff, skip
       // if outside of 4-path cutoff, best = 0.0, no need to test paths
       // if outside of 2-path cutoff but inside 4-path cutoff,
       //   best = 0.0, test 3-,4-paths
       // if inside 2-path cutoff, best = wij, only test 3-,4-paths if best < 1
 
       if (rijsq >= cutljsq[itype][jtype]) continue;
       rij = sqrt(rijsq);
       if (rij >= cut3rebo) {
         best = 0.0;
         testpath = 0;
       } else if (rij >= rcmax[itype][jtype]) {
         best = 0.0;
         testpath = 1;
       } else {
         best = Sp(rij,rcmin[itype][jtype],rcmax[itype][jtype],dwij);
         npath = 2;
         if (best < 1.0) testpath = 1;
         else testpath = 0;
       }
 
       done = 0;
       if (testpath) {
 
         // test all 3-body paths = I-K-J
         // I-K interactions come from atom I's REBO neighbors
         // if wik > current best, compute wkj
         // if best = 1.0, done
 
         REBO_neighs_i = REBO_firstneigh[i];
         for (kk = 0; kk < REBO_numneigh[i] && done==0; kk++) {
           k = REBO_neighs_i[kk];
           if (k == j) continue;
           ktype = map[type[k]];
 
           delik[0] = x[i][0] - x[k][0];
           delik[1] = x[i][1] - x[k][1];
           delik[2] = x[i][2] - x[k][2];
           rsq = delik[0]*delik[0] + delik[1]*delik[1] + delik[2]*delik[2];
           if (rsq < rcmaxsq[itype][ktype]) {
             rik = sqrt(rsq);
             wik = Sp(rik,rcmin[itype][ktype],rcmax[itype][ktype],dwik);
           } else wik = 0.0;
 
           if (wik > best) {
             deljk[0] = x[j][0] - x[k][0];
             deljk[1] = x[j][1] - x[k][1];
             deljk[2] = x[j][2] - x[k][2];
             rsq = deljk[0]*deljk[0] + deljk[1]*deljk[1] + deljk[2]*deljk[2];
             if (rsq < rcmaxsq[ktype][jtype]) {
               rkj = sqrt(rsq);
               wkj = Sp(rkj,rcmin[ktype][jtype],rcmax[ktype][jtype],dwkj);
               if (wik*wkj > best) {
                 best = wik*wkj;
                 npath = 3;
                  atomk = k;
                     delikS[0] = delik[0];
                     delikS[1] = delik[1];
                     delikS[2] = delik[2];
                     rikS = rik;
                     wikS = wik;
                     dwikS = dwik;
                     deljkS[0] = deljk[0];
                     deljkS[1] = deljk[1];
                     deljkS[2] = deljk[2];
                     rkjS = rkj;
                     wkjS = wkj;
                     dwkjS = dwkj;
                 if (best == 1.0) {
                   done = 1;
                   break;
                 }
               }
             }
 
             // test all 4-body paths = I-K-M-J
             // K-M interactions come from atom K's REBO neighbors
             // if wik*wkm > current best, compute wmj
             // if best = 1.0, done
 
             REBO_neighs_k = REBO_firstneigh[k];
             for (mm = 0; mm < REBO_numneigh[k] && done==0; mm++) {
               m = REBO_neighs_k[mm];
               if (m == i || m == j) continue;
               mtype = map[type[m]];
               delkm[0] = x[k][0] - x[m][0];
               delkm[1] = x[k][1] - x[m][1];
               delkm[2] = x[k][2] - x[m][2];
               rsq = delkm[0]*delkm[0] + delkm[1]*delkm[1] + delkm[2]*delkm[2];
               if (rsq < rcmaxsq[ktype][mtype]) {
                 rkm = sqrt(rsq);
                 wkm = Sp(rkm,rcmin[ktype][mtype],rcmax[ktype][mtype],dwkm);
               } else wkm = 0.0;
 
               if (wik*wkm > best) {
                 deljm[0] = x[j][0] - x[m][0];
                 deljm[1] = x[j][1] - x[m][1];
                 deljm[2] = x[j][2] - x[m][2];
                 rsq = deljm[0]*deljm[0] + deljm[1]*deljm[1] +
                   deljm[2]*deljm[2];
                 if (rsq < rcmaxsq[mtype][jtype]) {
                   rmj = sqrt(rsq);
                   wmj = Sp(rmj,rcmin[mtype][jtype],rcmax[mtype][jtype],dwmj);
                   if (wik*wkm*wmj > best) {
                     best = wik*wkm*wmj;
                     npath = 4;
                     atomk = k;
                     delikS[0] = delik[0];
                     delikS[1] = delik[1];
                     delikS[2] = delik[2];
                     rikS = rik;
                     wikS = wik;
                     dwikS = dwik;
                     atomm = m;
                     delkmS[0] = delkm[0];
                     delkmS[1] = delkm[1];
                         delkmS[2] = delkm[2];
                     rkmS = rkm;
                     wkmS = wkm;
                     dwkmS = dwkm;
                     deljmS[0] = deljm[0];
                     deljmS[1] = deljm[1];
                        deljmS[2] = deljm[2];
                     rmjS = rmj;
                     wmjS = wmj;
                     dwmjS = dwmj;
                     if (best == 1.0) {
                       done = 1;
                       break;
                     }
                   }
                 }
               }
             }
           }
         }
       }
 
       cij = 1.0 - best;
       if (cij == 0.0) continue;
 
       // compute LJ forces and energy
 
       sigwid = 0.84;
       sigcut = 3.0;
       sigmin = sigcut - sigwid;
 
       rljmin = sigma[itype][jtype];
       rljmax = sigcut * rljmin;
       rljmin = sigmin * rljmin;
 
       if (rij > rljmax) {
         slw = 0.0;
         dslw = 0.0;
       } else if (rij > rljmin) {
         drij = rij - rljmin;
         swidth = rljmax - rljmin;
         tee = drij / swidth;
         tee2 = tee*tee;
         slw = 1.0 - tee2 * (3.0 - 2.0 * tee);
         dslw = 6.0 * tee * (1.0 - tee) / rij / swidth;
       } else {
         slw = 1.0;
         dslw = 0.0;
       }
 
       r2inv = 1.0/rijsq;
       r6inv = r2inv*r2inv*r2inv;
 
       vdw = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]);
       dvdw = -r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]) / rij;
 
       // VLJ now becomes vdw * slw, derivaties, etc.
 
       VLJ = vdw * slw;
       dVLJ = dvdw * slw + vdw * dslw;
 
       Str = Sp2(rij,rcLJmin[itype][jtype],rcLJmax[itype][jtype],dStr);
       VA = Str*cij*VLJ;
       if (Str > 0.0) {
         scale = rcmin[itype][jtype] / rij;
         delscale[0] = scale * delij[0];
         delscale[1] = scale * delij[1];
         delscale[2] = scale * delij[2];
         Stb = bondorderLJ_thr(i,j,delscale,rcmin[itype][jtype],VA,
                               delij,rij,vflag_atom,thr);
       } else Stb = 0.0;
 
       fpair = -(dStr * (Stb*cij*VLJ - cij*VLJ) +
                 dVLJ * (Str*Stb*cij + cij - Str*cij)) / rij;
 
       f[i][0] += delij[0]*fpair;
       f[i][1] += delij[1]*fpair;
       f[i][2] += delij[2]*fpair;
       f[j][0] -= delij[0]*fpair;
       f[j][1] -= delij[1]*fpair;
       f[j][2] -= delij[2]*fpair;
 
       if (eflag) evdwl = VA*Stb + (1.0-Str)*cij*VLJ;
       if (evflag) ev_tally_thr(this,i,j,nlocal,/* newton_pair */ 1,
                                evdwl,0.0,fpair,delij[0],delij[1],delij[2],thr);
 
       if (cij < 1.0) {
         dC = Str*Stb*VLJ + (1.0-Str)*VLJ;
         if (npath == 2) {
           fpair = dC*dwij / rij;
           f[atomi][0] += delij[0]*fpair;
           f[atomi][1] += delij[1]*fpair;
           f[atomi][2] += delij[2]*fpair;
           f[atomj][0] -= delij[0]*fpair;
           f[atomj][1] -= delij[1]*fpair;
           f[atomj][2] -= delij[2]*fpair;
 
           if (vflag_atom) v_tally2_thr(atomi,atomj,fpair,delij,thr);
 
         } else if (npath == 3) {
           fpair1 = dC*dwikS*wkjS / rikS;
           fi[0] = delikS[0]*fpair1;
           fi[1] = delikS[1]*fpair1;
           fi[2] = delikS[2]*fpair1;
           fpair2 = dC*wikS*dwkjS / rkjS;
           fj[0] = deljkS[0]*fpair2;
           fj[1] = deljkS[1]*fpair2;
           fj[2] = deljkS[2]*fpair2;
 
           f[atomi][0] += fi[0];
           f[atomi][1] += fi[1];
           f[atomi][2] += fi[2];
           f[atomj][0] += fj[0];
           f[atomj][1] += fj[1];
           f[atomj][2] += fj[2];
           f[atomk][0] -= fi[0] + fj[0];
           f[atomk][1] -= fi[1] + fj[1];
           f[atomk][2] -= fi[2] + fj[2];
 
           if (vflag_atom)
             v_tally3_thr(atomi,atomj,atomk,fi,fj,delikS,deljkS,thr);
 
         } else {
           fpair1 = dC*dwikS*wkmS*wmjS / rikS;
           fi[0] = delikS[0]*fpair1;
           fi[1] = delikS[1]*fpair1;
           fi[2] = delikS[2]*fpair1;
 
           fpair2 = dC*wikS*dwkmS*wmjS / rkmS;
           fk[0] = delkmS[0]*fpair2 - fi[0];
           fk[1] = delkmS[1]*fpair2 - fi[1];
           fk[2] = delkmS[2]*fpair2 - fi[2];
 
           fpair3 = dC*wikS*wkmS*dwmjS / rmjS;
           fj[0] = deljmS[0]*fpair3;
           fj[1] = deljmS[1]*fpair3;
           fj[2] = deljmS[2]*fpair3;
 
           fm[0] = -delkmS[0]*fpair2 - fj[0];
           fm[1] = -delkmS[1]*fpair2 - fj[1];
           fm[2] = -delkmS[2]*fpair2 - fj[2];
 
           f[atomi][0] += fi[0];
           f[atomi][1] += fi[1];
           f[atomi][2] += fi[2];
           f[atomj][0] += fj[0];
           f[atomj][1] += fj[1];
           f[atomj][2] += fj[2];
           f[atomk][0] += fk[0];
           f[atomk][1] += fk[1];
           f[atomk][2] += fk[2];
           f[atomm][0] += fm[0];
           f[atomm][1] += fm[1];
           f[atomm][2] += fm[2];
 
           if (vflag_atom) {
             delimS[0] = delikS[0] + delkmS[0];
             delimS[1] = delikS[1] + delkmS[1];
             delimS[2] = delikS[2] + delkmS[2];
             v_tally4_thr(atomi,atomj,atomk,atomm,fi,fj,fk,delimS,deljmS,delkmS,thr);
           }
         }
       }
     }
   }
 }
 
 /* ----------------------------------------------------------------------
    torsional forces and energy
 ------------------------------------------------------------------------- */
 
 void PairAIREBOOMP::TORSION_thr(int ifrom, int ito,
                                 int evflag, int eflag, ThrData * const thr)
 {
   int i,j,k,l,ii,itag,jtag;
   double evdwl,fpair,xtmp,ytmp,ztmp;
   double cos321;
   double w21,dw21,cos234,w34,dw34;
   double cross321[3],cross321mag,cross234[3],cross234mag;
   double w23,dw23,cw2,ekijl,Ec;
   double cw,cwnum,cwnom;
   double rij,rij2,rik,rjl,tspjik,dtsjik,tspijl,dtsijl,costmp,fcpc;
   double sin321,sin234,rjk2,rik2,ril2,rjl2;
   double rjk,ril;
   double Vtors;
   double dndij[3],tmpvec[3],dndik[3],dndjl[3];
   double dcidij,dcidik,dcidjk,dcjdji,dcjdjl,dcjdil;
   double dsidij,dsidik,dsidjk,dsjdji,dsjdjl,dsjdil;
   double dxidij,dxidik,dxidjk,dxjdji,dxjdjl,dxjdil;
   double ddndij,ddndik,ddndjk,ddndjl,ddndil,dcwddn,dcwdn,dvpdcw,Ftmp[3];
   double del32[3],rsq,r32,del23[3],del21[3],r21;
   double deljk[3],del34[3],delil[3],delkl[3],r23,r34;
   double fi[3],fj[3],fk[3],fl[3];
   int itype,jtype,ktype,ltype,kk,ll,jj;
   int *ilist,*REBO_neighs_i,*REBO_neighs_j;
 
   const double * const * const x = atom->x;
   double * const * const f = thr->get_f();
   int *type = atom->type;
   int *tag = atom->tag;
 
   ilist = list->ilist;
 
   for (ii = ifrom; ii < ito; ii++) {
     i = ilist[ii];
     itag = tag[i];
     itype = map[type[i]];
     if (itype != 0) continue;
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
     REBO_neighs_i = REBO_firstneigh[i];
 
     for (jj = 0; jj < REBO_numneigh[i]; jj++) {
       j = REBO_neighs_i[jj];
       jtag = tag[j];
 
       if (itag > jtag) {
         if ((itag+jtag) % 2 == 0) continue;
       } else if (itag < jtag) {
         if ((itag+jtag) % 2 == 1) continue;
       } else {
         if (x[j][2] < ztmp) continue;
         if (x[j][2] == ztmp && x[j][1] < ytmp) continue;
         if (x[j][2] == ztmp && x[j][1] == ytmp && x[j][0] < xtmp) continue;
       }
 
       jtype = map[type[j]];
       if (jtype != 0) continue;
 
       del32[0] = x[j][0]-x[i][0];
       del32[1] = x[j][1]-x[i][1];
       del32[2] = x[j][2]-x[i][2];
       rsq = del32[0]*del32[0] + del32[1]*del32[1] + del32[2]*del32[2];
       r32 = sqrt(rsq);
       del23[0] = -del32[0];
       del23[1] = -del32[1];
       del23[2] = -del32[2];
       r23 = r32;
       w23 = Sp(r23,rcmin[itype][jtype],rcmax[itype][jtype],dw23);
 
       for (kk = 0; kk < REBO_numneigh[i]; kk++) {
         k = REBO_neighs_i[kk];
         ktype = map[type[k]];
         if (k == j) continue;
         del21[0] = x[i][0]-x[k][0];
         del21[1] = x[i][1]-x[k][1];
         del21[2] = x[i][2]-x[k][2];
         rsq = del21[0]*del21[0] + del21[1]*del21[1] + del21[2]*del21[2];
         r21 = sqrt(rsq);
         cos321 = - ((del21[0]*del32[0]) + (del21[1]*del32[1]) +
                     (del21[2]*del32[2])) / (r21*r32);
         cos321 = MIN(cos321,1.0);
         cos321 = MAX(cos321,-1.0);
         sin321 = sqrt(1.0 - cos321*cos321);
         if (sin321 < TOL) continue;
 
         deljk[0] = del21[0]-del23[0];
         deljk[1] = del21[1]-del23[1];
         deljk[2] = del21[2]-del23[2];
         rjk2 = deljk[0]*deljk[0] + deljk[1]*deljk[1] + deljk[2]*deljk[2];
         rjk=sqrt(rjk2);
         rik2 = r21*r21;
         w21 = Sp(r21,rcmin[itype][ktype],rcmax[itype][ktype],dw21);
 
         rij = r32;
         rik = r21;
         rij2 = r32*r32;
         rik2 = r21*r21;
         costmp = 0.5*(rij2+rik2-rjk2)/rij/rik;
         tspjik = Sp2(costmp,thmin,thmax,dtsjik);
         dtsjik = -dtsjik;
 
         REBO_neighs_j = REBO_firstneigh[j];
         for (ll = 0; ll < REBO_numneigh[j]; ll++) {
           l = REBO_neighs_j[ll];
           ltype = map[type[l]];
           if (l == i || l == k) continue;
           del34[0] = x[j][0]-x[l][0];
           del34[1] = x[j][1]-x[l][1];
           del34[2] = x[j][2]-x[l][2];
           rsq = del34[0]*del34[0] + del34[1]*del34[1] + del34[2]*del34[2];
           r34 = sqrt(rsq);
           cos234 = (del32[0]*del34[0] + del32[1]*del34[1] +
                     del32[2]*del34[2]) / (r32*r34);
           cos234 = MIN(cos234,1.0);
           cos234 = MAX(cos234,-1.0);
           sin234 = sqrt(1.0 - cos234*cos234);
           if (sin234 < TOL) continue;
           w34 = Sp(r34,rcmin[jtype][ltype],rcmax[jtype][ltype],dw34);
           delil[0] = del23[0] + del34[0];
           delil[1] = del23[1] + del34[1];
           delil[2] = del23[2] + del34[2];
           ril2 = delil[0]*delil[0] + delil[1]*delil[1] + delil[2]*delil[2];
           ril=sqrt(ril2);
           rjl2 = r34*r34;
 
           rjl = r34;
           rjl2 = r34*r34;
           costmp = 0.5*(rij2+rjl2-ril2)/rij/rjl;
           tspijl = Sp2(costmp,thmin,thmax,dtsijl);
           dtsijl = -dtsijl; //need minus sign
           cross321[0] = (del32[1]*del21[2])-(del32[2]*del21[1]);
           cross321[1] = (del32[2]*del21[0])-(del32[0]*del21[2]);
           cross321[2] = (del32[0]*del21[1])-(del32[1]*del21[0]);
           cross321mag = sqrt(cross321[0]*cross321[0]+
                              cross321[1]*cross321[1]+
                              cross321[2]*cross321[2]);
           cross234[0] = (del23[1]*del34[2])-(del23[2]*del34[1]);
           cross234[1] = (del23[2]*del34[0])-(del23[0]*del34[2]);
           cross234[2] = (del23[0]*del34[1])-(del23[1]*del34[0]);
           cross234mag = sqrt(cross234[0]*cross234[0]+
                              cross234[1]*cross234[1]+
                              cross234[2]*cross234[2]);
           cwnum = (cross321[0]*cross234[0]) +
             (cross321[1]*cross234[1])+(cross321[2]*cross234[2]);
           cwnom = r21*r34*r32*r32*sin321*sin234;
           cw = cwnum/cwnom;
 
           cw2 = (.5*(1.0-cw));
           ekijl = epsilonT[ktype][ltype];
           Ec = 256.0*ekijl/405.0;
           Vtors = (Ec*(powint(cw2,5)))-(ekijl/10.0);
 
           if (eflag) evdwl = Vtors*w21*w23*w34*(1.0-tspjik)*(1.0-tspijl);
 
           dndij[0] = (cross234[1]*del21[2])-(cross234[2]*del21[1]);
           dndij[1] = (cross234[2]*del21[0])-(cross234[0]*del21[2]);
           dndij[2] = (cross234[0]*del21[1])-(cross234[1]*del21[0]);
 
           tmpvec[0] = (del34[1]*cross321[2])-(del34[2]*cross321[1]);
           tmpvec[1] = (del34[2]*cross321[0])-(del34[0]*cross321[2]);
           tmpvec[2] = (del34[0]*cross321[1])-(del34[1]*cross321[0]);
 
           dndij[0] = dndij[0]+tmpvec[0];
           dndij[1] = dndij[1]+tmpvec[1];
           dndij[2] = dndij[2]+tmpvec[2];
 
           dndik[0] = (del23[1]*cross234[2])-(del23[2]*cross234[1]);
           dndik[1] = (del23[2]*cross234[0])-(del23[0]*cross234[2]);
           dndik[2] = (del23[0]*cross234[1])-(del23[1]*cross234[0]);
 
           dndjl[0] = (cross321[1]*del23[2])-(cross321[2]*del23[1]);
           dndjl[1] = (cross321[2]*del23[0])-(cross321[0]*del23[2]);
           dndjl[2] = (cross321[0]*del23[1])-(cross321[1]*del23[0]);
 
           dcidij = ((r23*r23)-(r21*r21)+(rjk*rjk))/(2.0*r23*r23*r21);
           dcidik = ((r21*r21)-(r23*r23)+(rjk*rjk))/(2.0*r23*r21*r21);
           dcidjk = (-rjk)/(r23*r21);
           dcjdji = ((r23*r23)-(r34*r34)+(ril*ril))/(2.0*r23*r23*r34);
           dcjdjl = ((r34*r34)-(r23*r23)+(ril*ril))/(2.0*r23*r34*r34);
           dcjdil = (-ril)/(r23*r34);
 
           dsidij = (-cos321/sin321)*dcidij;
           dsidik = (-cos321/sin321)*dcidik;
           dsidjk = (-cos321/sin321)*dcidjk;
 
           dsjdji = (-cos234/sin234)*dcjdji;
           dsjdjl = (-cos234/sin234)*dcjdjl;
           dsjdil = (-cos234/sin234)*dcjdil;
 
           dxidij = (r21*sin321)+(r23*r21*dsidij);
           dxidik = (r23*sin321)+(r23*r21*dsidik);
           dxidjk = (r23*r21*dsidjk);
 
           dxjdji = (r34*sin234)+(r23*r34*dsjdji);
           dxjdjl = (r23*sin234)+(r23*r34*dsjdjl);
           dxjdil = (r23*r34*dsjdil);
 
           ddndij = (dxidij*cross234mag)+(cross321mag*dxjdji);
           ddndik = dxidik*cross234mag;
           ddndjk = dxidjk*cross234mag;
           ddndjl = cross321mag*dxjdjl;
           ddndil = cross321mag*dxjdil;
           dcwddn = -cwnum/(cwnom*cwnom);
           dcwdn = 1.0/cwnom;
           dvpdcw = (-1.0)*Ec*(-.5)*5.0*powint(cw2,4) *
             w23*w21*w34*(1.0-tspjik)*(1.0-tspijl);
 
           Ftmp[0] = dvpdcw*((dcwdn*dndij[0])+(dcwddn*ddndij*del23[0]/r23));
           Ftmp[1] = dvpdcw*((dcwdn*dndij[1])+(dcwddn*ddndij*del23[1]/r23));
           Ftmp[2] = dvpdcw*((dcwdn*dndij[2])+(dcwddn*ddndij*del23[2]/r23));
           fi[0] = Ftmp[0];
           fi[1] = Ftmp[1];
           fi[2] = Ftmp[2];
           fj[0] = -Ftmp[0];
           fj[1] = -Ftmp[1];
           fj[2] = -Ftmp[2];
 
           Ftmp[0] = dvpdcw*((dcwdn*dndik[0])+(dcwddn*ddndik*del21[0]/r21));
           Ftmp[1] = dvpdcw*((dcwdn*dndik[1])+(dcwddn*ddndik*del21[1]/r21));
           Ftmp[2] = dvpdcw*((dcwdn*dndik[2])+(dcwddn*ddndik*del21[2]/r21));
           fi[0] += Ftmp[0];
           fi[1] += Ftmp[1];
           fi[2] += Ftmp[2];
           fk[0] = -Ftmp[0];
           fk[1] = -Ftmp[1];
           fk[2] = -Ftmp[2];
 
           Ftmp[0] = (dvpdcw*dcwddn*ddndjk*deljk[0])/rjk;
           Ftmp[1] = (dvpdcw*dcwddn*ddndjk*deljk[1])/rjk;
           Ftmp[2] = (dvpdcw*dcwddn*ddndjk*deljk[2])/rjk;
           fj[0] += Ftmp[0];
           fj[1] += Ftmp[1];
           fj[2] += Ftmp[2];
           fk[0] -= Ftmp[0];
           fk[1] -= Ftmp[1];
           fk[2] -= Ftmp[2];
 
           Ftmp[0] = dvpdcw*((dcwdn*dndjl[0])+(dcwddn*ddndjl*del34[0]/r34));
           Ftmp[1] = dvpdcw*((dcwdn*dndjl[1])+(dcwddn*ddndjl*del34[1]/r34));
           Ftmp[2] = dvpdcw*((dcwdn*dndjl[2])+(dcwddn*ddndjl*del34[2]/r34));
           fj[0] += Ftmp[0];
           fj[1] += Ftmp[1];
           fj[2] += Ftmp[2];
           fl[0] = -Ftmp[0];
           fl[1] = -Ftmp[1];
           fl[2] = -Ftmp[2];
 
           Ftmp[0] = (dvpdcw*dcwddn*ddndil*delil[0])/ril;
           Ftmp[1] = (dvpdcw*dcwddn*ddndil*delil[1])/ril;
           Ftmp[2] = (dvpdcw*dcwddn*ddndil*delil[2])/ril;
           fi[0] += Ftmp[0];
           fi[1] += Ftmp[1];
           fi[2] += Ftmp[2];
           fl[0] -= Ftmp[0];
           fl[1] -= Ftmp[1];
           fl[2] -= Ftmp[2];
 
           // coordination forces
 
           fpair = Vtors*dw21*w23*w34*(1.0-tspjik)*(1.0-tspijl) / r21;
           fi[0] -= del21[0]*fpair;
           fi[1] -= del21[1]*fpair;
           fi[2] -= del21[2]*fpair;
           fk[0] += del21[0]*fpair;
           fk[1] += del21[1]*fpair;
           fk[2] += del21[2]*fpair;
 
           fpair = Vtors*w21*dw23*w34*(1.0-tspjik)*(1.0-tspijl) / r23;
           fi[0] -= del23[0]*fpair;
           fi[1] -= del23[1]*fpair;
           fi[2] -= del23[2]*fpair;
           fj[0] += del23[0]*fpair;
           fj[1] += del23[1]*fpair;
           fj[2] += del23[2]*fpair;
 
           fpair = Vtors*w21*w23*dw34*(1.0-tspjik)*(1.0-tspijl) / r34;
           fj[0] -= del34[0]*fpair;
           fj[1] -= del34[1]*fpair;
           fj[2] -= del34[2]*fpair;
           fl[0] += del34[0]*fpair;
           fl[1] += del34[1]*fpair;
           fl[2] += del34[2]*fpair;
 
           // additional cut off function forces
 
           fcpc = -Vtors*w21*w23*w34*dtsjik*(1.0-tspijl);
           fpair = fcpc*dcidij/rij;
           fi[0] += fpair*del23[0];
           fi[1] += fpair*del23[1];
           fi[2] += fpair*del23[2];
           fj[0] -= fpair*del23[0];
           fj[1] -= fpair*del23[1];
           fj[2] -= fpair*del23[2];
 
           fpair = fcpc*dcidik/rik;
           fi[0] += fpair*del21[0];
           fi[1] += fpair*del21[1];
           fi[2] += fpair*del21[2];
           fk[0] -= fpair*del21[0];
           fk[1] -= fpair*del21[1];
           fk[2] -= fpair*del21[2];
 
           fpair = fcpc*dcidjk/rjk;
           fj[0] += fpair*deljk[0];
           fj[1] += fpair*deljk[1];
           fj[2] += fpair*deljk[2];
           fk[0] -= fpair*deljk[0];
           fk[1] -= fpair*deljk[1];
           fk[2] -= fpair*deljk[2];
 
           fcpc = -Vtors*w21*w23*w34*(1.0-tspjik)*dtsijl;
           fpair = fcpc*dcjdji/rij;
           fi[0] += fpair*del23[0];
           fi[1] += fpair*del23[1];
           fi[2] += fpair*del23[2];
           fj[0] -= fpair*del23[0];
           fj[1] -= fpair*del23[1];
           fj[2] -= fpair*del23[2];
 
           fpair = fcpc*dcjdjl/rjl;
           fj[0] += fpair*del34[0];
           fj[1] += fpair*del34[1];
           fj[2] += fpair*del34[2];
           fl[0] -= fpair*del34[0];
           fl[1] -= fpair*del34[1];
           fl[2] -= fpair*del34[2];
 
           fpair = fcpc*dcjdil/ril;
           fi[0] += fpair*delil[0];
           fi[1] += fpair*delil[1];
           fi[2] += fpair*delil[2];
           fl[0] -= fpair*delil[0];
           fl[1] -= fpair*delil[1];
           fl[2] -= fpair*delil[2];
 
           // sum per-atom forces into atom force array
 
           f[i][0] += fi[0]; f[i][1] += fi[1]; f[i][2] += fi[2];
           f[j][0] += fj[0]; f[j][1] += fj[1]; f[j][2] += fj[2];
           f[k][0] += fk[0]; f[k][1] += fk[1]; f[k][2] += fk[2];
           f[l][0] += fl[0]; f[l][1] += fl[1]; f[l][2] += fl[2];
 
           if (evflag) {
             delkl[0] = delil[0] - del21[0];
             delkl[1] = delil[1] - del21[1];
             delkl[2] = delil[2] - del21[2];
             ev_tally4_thr(this,i,j,k,l,evdwl,fi,fj,fk,delil,del34,delkl,thr);
           }
         }
       }
     }
   }
 }
 
 /* ----------------------------------------------------------------------
    create REBO neighbor list from main neighbor list
    REBO neighbor list stores neighbors of ghost atoms
 ------------------------------------------------------------------------- */
 
 void PairAIREBOOMP::REBO_neigh_thr()
 {
   const int nlocal = atom->nlocal;
   const int nthreads = comm->nthreads;
 
   if (atom->nmax > maxlocal) {
     maxlocal = atom->nmax;
     memory->destroy(REBO_numneigh);
     memory->sfree(REBO_firstneigh);
     memory->destroy(nC);
     memory->destroy(nH);
     memory->create(REBO_numneigh,maxlocal,"AIREBO:numneigh");
     REBO_firstneigh = (int **) memory->smalloc(maxlocal*sizeof(int *),
                                                "AIREBO:firstneigh");
     memory->create(nC,maxlocal,"AIREBO:nC");
     memory->create(nH,maxlocal,"AIREBO:nH");
   }
 
-  if (nthreads > maxpage)
-    add_pages(nthreads - maxpage);
-
 #if defined(_OPENMP)
 #pragma omp parallel default(none)
 #endif
   {
     int i,j,ii,jj,n,jnum,itype,jtype;
     double xtmp,ytmp,ztmp,delx,dely,delz,rsq,dS;
     int *ilist,*jlist,*numneigh,**firstneigh;
     int *neighptr;
 
     double **x = atom->x;
     int *type = atom->type;
 
     const int allnum = list->inum + list->gnum;
     ilist = list->ilist;
     numneigh = list->numneigh;
     firstneigh = list->firstneigh;
 
 #if defined(_OPENMP)
     const int tid = omp_get_thread_num();
 #else
     const int tid = 0;
 #endif
 
     const int iidelta = 1 + allnum/nthreads;
     const int iifrom = tid*iidelta;
     const int iito = ((iifrom+iidelta)>allnum) ? allnum : (iifrom+iidelta);
 
     // store all REBO neighs of owned and ghost atoms
     // scan full neighbor list of I
 
-    int npage = tid;
-    int npnt = 0;
+    // each thread has its own page allocator
+    MyPage<int> &ipg = ipage[tid];
+    ipg.reset();
 
     for (ii = iifrom; ii < iito; ii++) {
       i = ilist[ii];
 
-#if defined(_OPENMP)
-#pragma omp critical
-#endif
-      if (pgsize - npnt < oneatom) {
-        npnt = 0;
-        npage += nthreads;
-        if (npage >= maxpage) add_pages(nthreads);
-      }
-      neighptr = &(pages[npage][npnt]);
       n = 0;
+      neighptr = ipg.vget();
 
       xtmp = x[i][0];
       ytmp = x[i][1];
       ztmp = x[i][2];
       itype = map[type[i]];
       nC[i] = nH[i] = 0.0;
       jlist = firstneigh[i];
       jnum = numneigh[i];
 
       for (jj = 0; jj < jnum; jj++) {
         j = jlist[jj];
         j &= NEIGHMASK;
         jtype = map[type[j]];
         delx = xtmp - x[j][0];
         dely = ytmp - x[j][1];
         delz = ztmp - x[j][2];
         rsq = delx*delx + dely*dely + delz*delz;
 
         if (rsq < rcmaxsq[itype][jtype]) {
           neighptr[n++] = j;
           if (jtype == 0)
             nC[i] += Sp(sqrt(rsq),rcmin[itype][jtype],rcmax[itype][jtype],dS);
           else
             nH[i] += Sp(sqrt(rsq),rcmin[itype][jtype],rcmax[itype][jtype],dS);
         }
       }
 
       REBO_firstneigh[i] = neighptr;
       REBO_numneigh[i] = n;
-      npnt += n;
-
-      if (npnt >= pgsize)
-        error->one(FLERR,"REBO list overflow, boost neigh_modify one or page");
+      ipg.vgot(n);
+      if (ipg.status())
+        error->one(FLERR,"REBO list overflow, boost neigh_modify one");
     }
   }
 }
 
 
 /* ---------------------------------------------------------------------- */
 
 double PairAIREBOOMP::memory_usage()
 {
   double bytes = memory_usage_thr();
   bytes += PairAIREBO::memory_usage();
 
   return bytes;
 }
diff --git a/src/USER-OMP/pair_comb_omp.cpp b/src/USER-OMP/pair_comb_omp.cpp
index b658c0e23..3ce953b18 100644
--- a/src/USER-OMP/pair_comb_omp.cpp
+++ b/src/USER-OMP/pair_comb_omp.cpp
@@ -1,640 +1,632 @@
 /* ----------------------------------------------------------------------
    LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
    http://lammps.sandia.gov, Sandia National Laboratories
    Steve Plimpton, sjplimp@sandia.gov
 
    This software is distributed under the GNU General Public License.
 
    See the README file in the top-level LAMMPS directory.
 ------------------------------------------------------------------------- */
 
 /* ----------------------------------------------------------------------
    Contributing author: Axel Kohlmeyer (Temple U)
 ------------------------------------------------------------------------- */
 
 #include "math.h"
 #include "pair_comb_omp.h"
 #include "atom.h"
 #include "comm.h"
 #include "group.h"
 #include "force.h"
 #include "memory.h"
+#include "my_page.h"
 #include "neighbor.h"
 #include "neigh_list.h"
 
 #include "suffix.h"
 using namespace LAMMPS_NS;
 
 #define MAXNEIGH 24
 
 /* ---------------------------------------------------------------------- */
 
 PairCombOMP::PairCombOMP(LAMMPS *lmp) :
   PairComb(lmp), ThrOMP(lmp, THR_PAIR)
 {
   suffix_flag |= Suffix::OMP;
   respa_enable = 0;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void PairCombOMP::compute(int eflag, int vflag)
 {
   if (eflag || vflag) {
     ev_setup(eflag,vflag);
   } else evflag = vflag_fdotr = vflag_atom = 0;
 
   const int nall = atom->nlocal + atom->nghost;
   const int nthreads = comm->nthreads;
   const int inum = list->inum;
 
   // Build short range neighbor list
 
   Short_neigh_thr();
 
 #if defined(_OPENMP)
 #pragma omp parallel default(none) shared(eflag,vflag)
 #endif
   {
     int ifrom, ito, tid;
 
     loop_setup_thr(ifrom, ito, tid, inum, nthreads);
     ThrData *thr = fix->get_thr(tid);
     thr->timer(ThrData::TIME_START);
     ev_setup_thr(eflag, vflag, nall, eatom, vatom, thr);
 
     if (evflag) {
       if (eflag) {
         if (vflag_atom) eval<1,1,1>(ifrom, ito, thr);
         else eval<1,1,0>(ifrom, ito, thr);
       } else {
         if (vflag_atom) eval<1,0,1>(ifrom, ito, thr);
         else eval<1,0,0>(ifrom, ito, thr);
       }
     } else eval<0,0,0>(ifrom, ito, thr);
 
     thr->timer(ThrData::TIME_PAIR);
     reduce_thr(this, eflag, vflag, thr);
   } // end of omp parallel region
 }
 
 template <int EVFLAG, int EFLAG, int VFLAG_ATOM>
 void PairCombOMP::eval(int iifrom, int iito, ThrData * const thr)
 {
   int i,j,k,ii,jj,kk,jnum,iparam_i;
   int itag,jtag,itype,jtype,ktype,iparam_ij,iparam_ijk;
   double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair;
   double rsq,rsq1,rsq2;
   double delr1[3],delr2[3],fi[3],fj[3],fk[3];
   double zeta_ij,prefactor;
   int *ilist,*jlist,*numneigh,**firstneigh;
   int mr1,mr2,mr3;
   int rsc,inty;
   double elp_ij,filp[3],fjlp[3],fklp[3];
   double iq,jq;
   double yaself;
   double potal,fac11,fac11e;
   double vionij,fvionij,sr1,sr2,sr3,Eov,Fov;
   int sht_jnum, *sht_jlist, nj;
 
   evdwl = ecoul = 0.0;
 
   const double * const * const x = atom->x;
   double * const * const f = thr->get_f();
   const double * const q = atom->q;
   const int * const tag = atom->tag;
   const int * const type = atom->type;
   const int nlocal = atom->nlocal;
 
   ilist = list->ilist;
   numneigh = list->numneigh;
   firstneigh = list->firstneigh;
 
   yaself = vionij = fvionij = Eov = Fov = 0.0;
 
   double fxtmp,fytmp,fztmp;
   double fjxtmp,fjytmp,fjztmp;
 
   // self energy correction term: potal
 
   potal_calc(potal,fac11,fac11e);
 
   // loop over full neighbor list of my atoms
 
   for (ii = iifrom; ii < iito; ++ii) {
 
     i = ilist[ii];
     itag = tag[i];
     itype = map[type[i]];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
     fxtmp = fytmp = fztmp = 0.0;
 
     iq = q[i];
     NCo[i] = 0;
     nj = 0;
     iparam_i = elem2param[itype][itype][itype];
 
     // self energy, only on i atom
 
     yaself = self(&params[iparam_i],iq,potal);
 
     if (EVFLAG) ev_tally_thr(this,i,i,nlocal,0,yaself,
                              0.0,0.0,0.0,0.0,0.0,thr);
 
     // two-body interactions (long and short repulsive)
 
     jlist = firstneigh[i];
     jnum = numneigh[i];
     sht_jlist = sht_first[i];
     sht_jnum = sht_num[i];
 
     for (jj = 0; jj < jnum; jj++) {
       j = jlist[jj];
       j &= NEIGHMASK;
       jtag = tag[j];
 
       if (itag > jtag) {
         if ((itag+jtag) % 2 == 0) continue;
       } else if (itag < jtag) {
         if ((itag+jtag) % 2 == 1) continue;
       } else {
         if (x[j][2] < ztmp) continue;
         if (x[j][2] == ztmp && x[j][1] < ytmp) continue;
         if (x[j][2] == ztmp && x[j][1] == ytmp && x[j][0] < xtmp) continue;
       }
 
       // Qj calculates 2-body Coulombic
 
       jtype = map[type[j]];
       jq = q[j];
 
       delx = xtmp - x[j][0];
       dely = ytmp - x[j][1];
       delz = ztmp - x[j][2];
       rsq = delx*delx + dely*dely + delz*delz;
 
       iparam_ij = elem2param[itype][jtype][jtype];
 
       // long range q-dependent
 
       if (rsq > params[iparam_ij].lcutsq) continue;
 
       inty = intype[itype][jtype];
 
       // polynomial three-point interpolation
 
       tri_point(rsq, mr1, mr2, mr3, sr1, sr2, sr3, itype);
 
       // 1/r energy and forces
 
       direct(inty,mr1,mr2,mr3,rsq,sr1,sr2,sr3,iq,jq,
              potal,fac11,fac11e,vionij,fvionij);
 
       // field correction to self energy
 
       field(&params[iparam_ij],rsq,iq,jq,vionij,fvionij);
 
       // polarization field
       // sums up long range forces
 
       fxtmp += delx*fvionij;
       fytmp += dely*fvionij;
       fztmp += delz*fvionij;
       f[j][0] -= delx*fvionij;
       f[j][1] -= dely*fvionij;
       f[j][2] -= delz*fvionij;
 
       if (EVFLAG)
         ev_tally_thr(this,i,j,nlocal,/* newton_pair */ 1,
                      0.0,vionij,fvionij,delx,dely,delz,thr);
 
       // short range q-independent
 
       if (rsq > params[iparam_ij].cutsq) continue;
 
       repulsive(&params[iparam_ij],rsq,fpair,EFLAG,evdwl,iq,jq);
 
       // repulsion is pure two-body, sums up pair repulsive forces
 
       fxtmp += delx*fpair;
       fytmp += dely*fpair;
       fztmp += delz*fpair;
       f[j][0] -= delx*fpair;
       f[j][1] -= dely*fpair;
       f[j][2] -= delz*fpair;
 
       if (EVFLAG)
         ev_tally_thr(this,i,j,nlocal,/* newton_pair */ 1,
                      evdwl,0.0,fpair,delx,dely,delz,thr);
     }
 
     // accumulate coordination number information
 
     if (cor_flag) {
       int numcoor = 0;
       for (jj = 0; jj < sht_jnum; jj++) {
         j = sht_jlist[jj];
         jtype = map[type[j]];
         iparam_ij = elem2param[itype][jtype][jtype];
 
         if(params[iparam_ij].hfocor > 0.0 ) {
           delr1[0] = x[j][0] - xtmp;
           delr1[1] = x[j][1] - ytmp;
           delr1[2] = x[j][2] - ztmp;
           rsq1 = vec3_dot(delr1,delr1);
 
           if (rsq1 > params[iparam_ij].cutsq) continue;
           ++numcoor;
         }
       }
       NCo[i] = numcoor;
     }
 
     // three-body interactions
     // half i-j loop
 
     for (jj = 0; jj < sht_jnum; jj++) {
       j = sht_jlist[jj];
 
       jtype = map[type[j]];
       iparam_ij = elem2param[itype][jtype][jtype];
 
       // this Qj for q-dependent BSi
 
       jq = q[j];
 
       delr1[0] = x[j][0] - xtmp;
       delr1[1] = x[j][1] - ytmp;
       delr1[2] = x[j][2] - ztmp;
       rsq1 = vec3_dot(delr1,delr1);
 
       if (rsq1 > params[iparam_ij].cutsq) continue;
       nj ++;
 
       // accumulate bondorder zeta for each i-j interaction via loop over k
 
       fjxtmp = fjytmp = fjztmp = 0.0;
       zeta_ij = 0.0;
       cuo_flag1 = 0; cuo_flag2 = 0;
 
       for (kk = 0; kk < sht_jnum; kk++) {
         k = sht_jlist[kk];
         if (j == k) continue;
         ktype = map[type[k]];
         iparam_ijk = elem2param[itype][jtype][ktype];
 
         delr2[0] = x[k][0] - xtmp;
         delr2[1] = x[k][1] - ytmp;
         delr2[2] = x[k][2] - ztmp;
         rsq2 = vec3_dot(delr2,delr2);
 
         if (rsq2 > params[iparam_ijk].cutsq) continue;
 
         zeta_ij += zeta(&params[iparam_ijk],rsq1,rsq2,delr1,delr2);
 
         if (params[iparam_ijk].hfocor == -2.0) cuo_flag1 = 1;
         if (params[iparam_ijk].hfocor == -1.0) cuo_flag2 = 1;
       }
 
       if (cuo_flag1 && cuo_flag2) cuo_flag = 1;
       else cuo_flag = 0;
 
       force_zeta(&params[iparam_ij],EFLAG,i,nj,rsq1,zeta_ij,
                  iq,jq,fpair,prefactor,evdwl);
 
       // over-coordination correction for HfO2
 
       if (cor_flag && NCo[i] != 0)
         Over_cor(&params[iparam_ij],rsq1,NCo[i],Eov, Fov);
       evdwl +=  Eov;
       fpair +=  Fov;
 
       fxtmp += delr1[0]*fpair;
       fytmp += delr1[1]*fpair;
       fztmp += delr1[2]*fpair;
       fjxtmp -= delr1[0]*fpair;
       fjytmp -= delr1[1]*fpair;
       fjztmp -= delr1[2]*fpair;
 
       if (EVFLAG) ev_tally_thr(this,i,j,nlocal,/* newton_pair */ 1,evdwl,0.0,
                                -fpair,-delr1[0],-delr1[1],-delr1[2],thr);
 
       // attractive term via loop over k (3-body forces)
 
       for (kk = 0; kk < sht_jnum; kk++) {
         k = sht_jlist[kk];
         if (j == k) continue;
         ktype = map[type[k]];
         iparam_ijk = elem2param[itype][jtype][ktype];
 
         delr2[0] = x[k][0] - xtmp;
         delr2[1] = x[k][1] - ytmp;
         delr2[2] = x[k][2] - ztmp;
         rsq2 = vec3_dot(delr2,delr2);
         if (rsq2 > params[iparam_ijk].cutsq) continue;
 
         for (rsc = 0; rsc < 3; rsc++)
           fi[rsc] = fj[rsc] = fk[rsc] = 0.0;
 
         attractive(&params[iparam_ijk],prefactor,
                    rsq1,rsq2,delr1,delr2,fi,fj,fk);
 
         // 3-body LP and BB correction and forces
 
         elp_ij = elp(&params[iparam_ijk],rsq1,rsq2,delr1,delr2);
         flp(&params[iparam_ijk],rsq1,rsq2,delr1,delr2,filp,fjlp,fklp);
 
         fxtmp += fi[0] + filp[0];
         fytmp += fi[1] + filp[1];
         fztmp += fi[2] + filp[2];
         fjxtmp += fj[0] + fjlp[0];
         fjytmp += fj[1] + fjlp[1];
         fjztmp += fj[2] + fjlp[2];
         f[k][0] += fk[0] + fklp[0];
         f[k][1] += fk[1] + fklp[1];
         f[k][2] += fk[2] + fklp[2];
 
         if (EVFLAG)
           ev_tally_thr(this,i,j,nlocal,/* newton_pair */ 1,
                        elp_ij,0.0,0.0,0.0,0.0,0.0, thr);
         if (VFLAG_ATOM) v_tally3_thr(i,j,k,fj,fk,delr1,delr2,thr);
       }
       f[j][0] += fjxtmp;
       f[j][1] += fjytmp;
       f[j][2] += fjztmp;
     }
     f[i][0] += fxtmp;
     f[i][1] += fytmp;
     f[i][2] += fztmp;
 
     if (cuo_flag) params[iparam_i].cutsq *= 0.65;
   }
   cuo_flag = 0;
 }
 
 /* ---------------------------------------------------------------------- */
 
 double PairCombOMP::yasu_char(double *qf_fix, int &igroup)
 {
   int ii;
   double potal,fac11,fac11e;
 
   const double * const * const x = atom->x;
   const double * const q = atom->q;
   const int * const type = atom->type;
   const int * const tag = atom->tag;
 
   const int inum = list->inum;
   const int * const ilist = list->ilist;
   const int * const numneigh = list->numneigh;
   const int * const * const firstneigh = list->firstneigh;
 
   const int * const mask = atom->mask;
   const int groupbit = group->bitmask[igroup];
 
   qf = qf_fix;
   for (ii = 0; ii < inum; ii++) {
     const int i = ilist[ii];
     if (mask[i] & groupbit)
       qf[i] = 0.0;
   }
 
   // communicating charge force to all nodes, first forward then reverse
 
   comm->forward_comm_pair(this);
 
   // self energy correction term: potal
 
   potal_calc(potal,fac11,fac11e);
 
   // loop over full neighbor list of my atoms
 #if defined(_OPENMP)
 #pragma omp parallel for private(ii) default(none) shared(potal,fac11e)
 #endif
   for (ii = 0; ii < inum; ii ++) {
     double fqi,fqj,fqij,fqji,fqjj,delr1[3];
     double sr1,sr2,sr3;
     int mr1,mr2,mr3;
 
     const int i = ilist[ii];
     const int itag = tag[i];
     int nj = 0;
 
     if (mask[i] & groupbit) {
       fqi = fqj = fqij = fqji = fqjj = 0.0; // should not be needed.
       int itype = map[type[i]];
       const double xtmp = x[i][0];
       const double ytmp = x[i][1];
       const double ztmp = x[i][2];
       const double iq = q[i];
       const int iparam_i = elem2param[itype][itype][itype];
 
       // charge force from self energy
 
       fqi = qfo_self(&params[iparam_i],iq,potal);
 
       // two-body interactions
 
       const int * const jlist = firstneigh[i];
       const int jnum = numneigh[i];
 
       for (int jj = 0; jj < jnum; jj++) {
         const int j = jlist[jj] & NEIGHMASK;
         const int jtag = tag[j];
 
         if (itag > jtag) {
           if ((itag+jtag) % 2 == 0) continue;
         } else if (itag < jtag) {
           if ((itag+jtag) % 2 == 1) continue;
         } else {
           if (x[j][2] < ytmp) continue;
           if (x[j][2] == ztmp && x[j][1] < ytmp) continue;
           if (x[j][2] == ztmp && x[j][1] == ytmp && x[j][0] < xtmp) continue;
         }
 
         const int jtype = map[type[j]];
         double jq = q[j];
 
         delr1[0] = x[j][0] - xtmp;
         delr1[1] = x[j][1] - ytmp;
         delr1[2] = x[j][2] - ztmp;
         double rsq1 = vec3_dot(delr1,delr1);
 
         const int iparam_ij = elem2param[itype][jtype][jtype];
 
         // long range q-dependent
 
         if (rsq1 > params[iparam_ij].lcutsq) continue;
 
         const int inty = intype[itype][jtype];
 
         // polynomial three-point interpolation
 
         tri_point(rsq1,mr1,mr2,mr3,sr1,sr2,sr3,itype);
 
         // 1/r charge forces
 
         qfo_direct(inty,mr1,mr2,mr3,rsq1,sr1,sr2,sr3,fac11e,fqij);
 
         // field correction to self energy and charge force
 
         qfo_field(&params[iparam_ij],rsq1,iq,jq,fqji,fqjj);
         fqi   += jq * fqij + fqji;
 #if defined(_OPENMP)
 #pragma omp atomic
 #endif
         qf[j] += (iq * fqij + fqjj);
       }
 
         // three-body interactions
 
       for (int jj = 0; jj < jnum; jj++) {
         const int j = jlist[jj] & NEIGHMASK;
         const int jtype = map[type[j]];
         const double jq = q[j];
 
         delr1[0] = x[j][0] - xtmp;
         delr1[1] = x[j][1] - ytmp;
         delr1[2] = x[j][2] - ztmp;
         double rsq1 = vec3_dot(delr1,delr1);
 
         const int iparam_ij = elem2param[itype][jtype][jtype];
 
         if (rsq1 > params[iparam_ij].cutsq) continue;
         nj ++;
 
         // charge force in Aij and Bij
 
         qfo_short(&params[iparam_ij],i,nj,rsq1,iq,jq,fqij,fqjj);
         fqi += fqij;
 #if defined(_OPENMP)
 #pragma omp atomic
 #endif
         qf[j] += fqjj;
       }
 
 #if defined(_OPENMP)
 #pragma omp atomic
 #endif
       qf[i] += fqi;
     }
   }
 
   comm->reverse_comm_pair(this);
 
   // sum charge force on each node and return it
 
   double eneg = 0.0;
   for (ii = 0; ii < inum; ii++) {
     const int i = ilist[ii];
     if (mask[i] & groupbit)
       eneg += qf[i];
   }
   double enegtot;
   MPI_Allreduce(&eneg,&enegtot,1,MPI_DOUBLE,MPI_SUM,world);
   return enegtot;
 }
 
 /* ---------------------------------------------------------------------- */
 
 double PairCombOMP::memory_usage()
 {
   double bytes = memory_usage_thr();
   bytes += PairComb::memory_usage();
 
   return bytes;
 }
 /* ---------------------------------------------------------------------- */
 
 void PairCombOMP::Short_neigh_thr()
 {
 
   if (atom->nmax > nmax) {
     nmax = atom->nmax;
     memory->sfree(sht_first);
     sht_first = (int **) memory->smalloc(nmax*sizeof(int *),
-            "pair:sht_first");
+                                         "pair:sht_first");
     memory->grow(sht_num,nmax,"pair:sht_num");
     memory->grow(NCo,nmax,"pair:NCo");
-    memory->grow(bbij,nmax,nmax,"pair:bbij");
+    memory->grow(bbij,nmax,MAXNEIGH,"pair:bbij");
   }
 
   const int nthreads = comm->nthreads;
-  if (nthreads > maxpage)
-    add_pages(nthreads - maxpage);
 
 #if defined(_OPENMP)
 #pragma omp parallel default(none)
 #endif
   {
     int nj,npntj,*neighptrj;
     int iparam_ij,*ilist,*jlist,*numneigh,**firstneigh;
     int jnum,i,j,ii,jj;
     double xtmp,ytmp,ztmp,rsq,delrj[3];
     double **x = atom->x;
     int *type  = atom->type;
 
     const int inum = list->inum;
     ilist = list->ilist;
     numneigh = list->numneigh;
     firstneigh = list->firstneigh;
 
 
 #if defined(_OPENMP)
     const int tid = omp_get_thread_num();
 #else
     const int tid = 0;
 #endif
 
     const int iidelta = 1 + inum/nthreads;
     const int iifrom = tid*iidelta;
-    int iito   = iifrom + iidelta;
-    if (iito > inum) iito = inum;
+    const int iito   = ((iifrom + iidelta) > inum) ? inum : (iifrom+iidelta);
 
-    int npage = tid;
-    npntj = 0;
+    // each thread has its own page allocator
+    MyPage<int> &ipg = ipage[tid];
+    ipg.reset();
 
-    if (iifrom < inum) {
-      for (ii = iifrom; ii < iito; ii++) {
-        i = ilist[ii];
+    // create Comb neighbor list
 
-#if defined(_OPENMP)
-#pragma omp critical
-#endif
-        if(pgsize - npntj < oneatom) {
-          npntj = 0;
-          npage += nthreads;
-          if (npage >= maxpage) add_pages(nthreads);
-        }
+    for (ii = iifrom; ii < iito; ii++) {
+      i = ilist[ii];
 
-        neighptrj = &pages[npage][npntj];
-        nj = 0;
+      nj = 0;
+      neighptrj = ipg.vget();
 
-        xtmp = x[i][0];
-        ytmp = x[i][1];
-        ztmp = x[i][2];
+      xtmp = x[i][0];
+      ytmp = x[i][1];
+      ztmp = x[i][2];
 
-        jlist = firstneigh[i];
-        jnum = numneigh[i];
+      jlist = firstneigh[i];
+      jnum = numneigh[i];
 
-        for (jj = 0; jj < jnum; jj++) {
-          j = jlist[jj];
-          j &= NEIGHMASK;
+      for (jj = 0; jj < jnum; jj++) {
+        j = jlist[jj];
+        j &= NEIGHMASK;
 
-          delrj[0] = xtmp - x[j][0];
-          delrj[1] = ytmp - x[j][1];
-          delrj[2] = ztmp - x[j][2];
-          rsq = vec3_dot(delrj,delrj);
+        delrj[0] = xtmp - x[j][0];
+        delrj[1] = ytmp - x[j][1];
+        delrj[2] = ztmp - x[j][2];
+        rsq = vec3_dot(delrj,delrj);
 
-          if (rsq > cutmin) continue;
-          neighptrj[nj++] = j;
-        }
-        sht_first[i] = neighptrj;
-        sht_num[i] = nj;
-        npntj += nj;
+        if (rsq > cutmin) continue;
+        neighptrj[nj++] = j;
       }
+      sht_first[i] = neighptrj;
+      sht_num[i] = nj;
+      ipg.vgot(nj);
+      if (ipg.status())
+        error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
     }
   }
 }
diff --git a/src/fix_shear_history.cpp b/src/fix_shear_history.cpp
index f9e321a23..e022b4839 100644
--- a/src/fix_shear_history.cpp
+++ b/src/fix_shear_history.cpp
@@ -1,342 +1,431 @@
 /* ----------------------------------------------------------------------
    LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
    http://lammps.sandia.gov, Sandia National Laboratories
    Steve Plimpton, sjplimp@sandia.gov
 
    Copyright (2003) Sandia Corporation.  Under the terms of Contract
    DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
    certain rights in this software.  This software is distributed under
    the GNU General Public License.
 
    See the README file in the top-level LAMMPS directory.
 ------------------------------------------------------------------------- */
 
+#include "mpi.h"
 #include "string.h"
 #include "stdio.h"
 #include "fix_shear_history.h"
 #include "atom.h"
+#include "comm.h"
 #include "neighbor.h"
 #include "neigh_list.h"
 #include "force.h"
 #include "pair.h"
 #include "update.h"
 #include "modify.h"
 #include "memory.h"
 #include "error.h"
 
 using namespace LAMMPS_NS;
 using namespace FixConst;
 
-#define MAXTOUCH 15
-
 /* ---------------------------------------------------------------------- */
 
 FixShearHistory::FixShearHistory(LAMMPS *lmp, int narg, char **arg) :
   Fix(lmp, narg, arg)
 {
   restart_peratom = 1;
   create_attribute = 1;
 
   // perform initial allocation of atom-based arrays
   // register with atom class
 
   npartner = NULL;
   partner = NULL;
   shearpartner = NULL;
   grow_arrays(atom->nmax);
   atom->add_callback(0);
   atom->add_callback(1);
 
+  ipage = NULL;
+  dpage = NULL;
+  pgsize = oneatom = 0;
+
   // initialize npartner to 0 so neighbor list creation is OK the 1st time
 
   int nlocal = atom->nlocal;
   for (int i = 0; i < nlocal; i++) npartner[i] = 0;
+  maxtouch = 0;
 }
 
 /* ---------------------------------------------------------------------- */
 
 FixShearHistory::~FixShearHistory()
 {
   // unregister this fix so atom class doesn't invoke it any more
 
   atom->delete_callback(id,0);
   atom->delete_callback(id,1);
 
   // delete locally stored arrays
 
   memory->destroy(npartner);
-  memory->destroy(partner);
-  memory->destroy(shearpartner);
+  memory->sfree(partner);
+  memory->sfree(shearpartner);
+  delete[] ipage;
+  delete[] dpage;
 }
 
 /* ---------------------------------------------------------------------- */
 
 int FixShearHistory::setmask()
 {
   int mask = 0;
   mask |= PRE_EXCHANGE;
   mask |= MIN_PRE_EXCHANGE;
   return mask;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void FixShearHistory::init()
 {
   if (atom->tag_enable == 0)
     error->all(FLERR,
                "Pair style granular with history requires atoms have IDs");
 
   int dim;
   computeflag = (int *) pair->extract("computeflag",dim);
+
+  // create pages if first time or if neighbor pgsize/oneatom has changed
+  // note that latter could cause shear history info to be discarded
+
+  int create = 0;
+  if (ipage == NULL) create = 1;
+  if (pgsize != neighbor->pgsize) create = 1;
+  if (oneatom != neighbor->oneatom) create = 1;
+
+  if (create) {
+    delete[] ipage;
+    delete[] dpage;
+
+    pgsize = neighbor->pgsize;
+    oneatom = neighbor->oneatom;
+    int nmypage = comm->nthreads;
+    ipage = new MyPage<int>[nmypage];
+    dpage = new MyPage<double[3]>[nmypage];
+    for (int i=0; i < nmypage; ++i) {
+      ipage[i].init(oneatom,pgsize);
+      dpage[i].init(oneatom,pgsize);
+    }
+  }
 }
 
 /* ----------------------------------------------------------------------
    called by setup of run or minimize
    called by write_restart as input script command
    only invoke pre_exchange() if neigh list stores more current history info
      than npartner/partner arrays in this fix
    that will only be case if pair->compute() has been invoked since
      update of npartner/npartner
    this logic avoids 2 problems:
      run 100; write_restart; run 100
        setup_pre_exchange is called twice (by write_restart and 2nd run setup)
        w/out a neighbor list being created in between
      read_restart; run 100
        setup_pre_exchange called by run setup whacks restart shear history info
 ------------------------------------------------------------------------- */
 
 void FixShearHistory::setup_pre_exchange()
 {
   if (*computeflag) pre_exchange();
   *computeflag = 0;
 }
 
 /* ----------------------------------------------------------------------
    copy shear partner info from neighbor lists to atom arrays
    so can be migrated or stored with atoms
 ------------------------------------------------------------------------- */
 
 void FixShearHistory::pre_exchange()
 {
-  int i,j,ii,jj,m,inum,jnum;
+  int i,j,ii,jj,m,n,inum,jnum;
   int *ilist,*jlist,*numneigh,**firstneigh;
   int *touch,**firsttouch;
   double *shear,*allshear,**firstshear;
 
   // zero npartner for all current atoms
+  // clear 2 page data structures
 
   int nlocal = atom->nlocal;
   for (i = 0; i < nlocal; i++) npartner[i] = 0;
 
-  // copy shear info from neighbor list atoms to atom arrays
+  ipage->reset();
+  dpage->reset();
+
+  // 1st loop over neighbor list
+  // calculate npartner for each owned atom
 
   int *tag = atom->tag;
   NeighList *list = pair->list;
   inum = list->inum;
   ilist = list->ilist;
   numneigh = list->numneigh;
   firstneigh = list->firstneigh;
   firsttouch = list->listgranhistory->firstneigh;
   firstshear = list->listgranhistory->firstdouble;
 
+  for (ii = 0; ii < inum; ii++) {
+    i = ilist[ii];
+    jlist = firstneigh[i];
+    jnum = numneigh[i];
+    touch = firsttouch[i];
+
+    for (jj = 0; jj < jnum; jj++) {
+      if (touch[jj]) {
+        npartner[i]++;
+        j = jlist[jj];
+        j &= NEIGHMASK;
+        if (j < nlocal) npartner[j]++;
+      }
+    }
+  }
+
+  // get page chunks to store atom IDs and shear history for my atoms
+
+  for (ii = 0; ii < inum; ii++) {
+    i = ilist[ii];
+    n = npartner[i];
+    partner[i] = ipage->get(n);
+    shearpartner[i] = dpage->get(n);
+    if (partner[i] == NULL || shearpartner[i] == NULL)
+      error->one(FLERR,"Shear history overflow, boost neigh_modify one");
+  }
+
+  // 2nd loop over neighbor list
+  // store atom IDs and shear history for my atoms
+  // re-zero npartner to use as counter for all my atoms
+
+  for (i = 0; i < nlocal; i++) npartner[i] = 0;
+
   for (ii = 0; ii < inum; ii++) {
     i = ilist[ii];
     jlist = firstneigh[i];
     allshear = firstshear[i];
     jnum = numneigh[i];
     touch = firsttouch[i];
 
     for (jj = 0; jj < jnum; jj++) {
       if (touch[jj]) {
         shear = &allshear[3*jj];
         j = jlist[jj];
         j &= NEIGHMASK;
-        if (npartner[i] < MAXTOUCH) {
-          m = npartner[i];
-          partner[i][m] = tag[j];
-          shearpartner[i][m][0] = shear[0];
-          shearpartner[i][m][1] = shear[1];
-          shearpartner[i][m][2] = shear[2];
-        }
+        m = npartner[i];
+        partner[i][m] = tag[j];
+        shearpartner[i][m][0] = shear[0];
+        shearpartner[i][m][1] = shear[1];
+        shearpartner[i][m][2] = shear[2];
         npartner[i]++;
         if (j < nlocal) {
-          if (npartner[j] < MAXTOUCH) {
-            m = npartner[j];
-            partner[j][m] = tag[i];
-            shearpartner[j][m][0] = -shear[0];
-            shearpartner[j][m][1] = -shear[1];
-            shearpartner[j][m][2] = -shear[2];
-          }
+          m = npartner[j];
+          partner[j][m] = tag[i];
+          shearpartner[j][m][0] = -shear[0];
+          shearpartner[j][m][1] = -shear[1];
+          shearpartner[j][m][2] = -shear[2];
           npartner[j]++;
         }
       }
     }
   }
 
-  // test for too many touching neighbors
+  // set maxtouch = max # of partners of any owned atom
 
-  int flag = 0;
-  for (i = 0; i < nlocal; i++)
-    if (npartner[i] >= MAXTOUCH) flag = 1;
-  int flag_all;
-  MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_SUM,world);
-  if (flag_all)
-    error->all(FLERR,"Too many touching neighbors - boost MAXTOUCH");
+  maxtouch = 0;
+  for (i = 0; i < nlocal; i++) maxtouch = MAX(maxtouch,npartner[i]);
 }
 
 /* ---------------------------------------------------------------------- */
 
 void FixShearHistory::min_setup_pre_exchange()
 {
   if (*computeflag) pre_exchange();
   *computeflag = 0;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void FixShearHistory::min_pre_exchange()
 {
   pre_exchange();
 }
 
 /* ----------------------------------------------------------------------
    memory usage of local atom-based arrays
 ------------------------------------------------------------------------- */
 
 double FixShearHistory::memory_usage()
 {
   int nmax = atom->nmax;
   double bytes = nmax * sizeof(int);
-  bytes += nmax*MAXTOUCH * sizeof(int);
-  bytes += nmax*MAXTOUCH*3 * sizeof(double);
+  bytes = nmax * sizeof(int *);
+  bytes = nmax * sizeof(double *);
+
+  int nmypage = comm->nthreads;
+  for (int i=0; i < nmypage; ++i) {
+    bytes += ipage[i].size();
+    bytes += dpage[i].size();
+  }
+
   return bytes;
 }
 
 /* ----------------------------------------------------------------------
    allocate local atom-based arrays
 ------------------------------------------------------------------------- */
 
 void FixShearHistory::grow_arrays(int nmax)
 {
   memory->grow(npartner,nmax,"shear_history:npartner");
-  memory->grow(partner,nmax,MAXTOUCH,"shear_history:partner");
-  memory->grow(shearpartner,nmax,MAXTOUCH,3,"shear_history:shearpartner");
+  partner = (int **) memory->srealloc(partner,nmax*sizeof(int *),
+                                      "shear_history:partner");
+  typedef double (*sptype)[3];
+  shearpartner = (sptype *) 
+    memory->srealloc(shearpartner,nmax*sizeof(sptype),
+                     "shear_history:shearpartner");
 }
 
 /* ----------------------------------------------------------------------
    copy values within local atom-based arrays
 ------------------------------------------------------------------------- */
 
 void FixShearHistory::copy_arrays(int i, int j, int delflag)
 {
+  // just copy pointers for partner and shearpartner
+  // b/c can't overwrite chunk allocation inside ipage,dpage
+  // incoming atoms in unpack_exchange just grab new chunks
+  // so are orphaning chunks for migrating atoms
+  // OK, b/c will reset ipage,dpage on next reneighboring
+
   npartner[j] = npartner[i];
-  for (int m = 0; m < npartner[j]; m++) {
-    partner[j][m] = partner[i][m];
-    shearpartner[j][m][0] = shearpartner[i][m][0];
-    shearpartner[j][m][1] = shearpartner[i][m][1];
-    shearpartner[j][m][2] = shearpartner[i][m][2];
-  }
+  partner[j] = partner[i];
+  shearpartner[j] = shearpartner[i];
 }
 
 /* ----------------------------------------------------------------------
    initialize one atom's array values, called when atom is created
 ------------------------------------------------------------------------- */
 
 void FixShearHistory::set_arrays(int i)
 {
   npartner[i] = 0;
 }
 
 /* ----------------------------------------------------------------------
    pack values in local atom-based arrays for exchange with another proc
 ------------------------------------------------------------------------- */
 
 int FixShearHistory::pack_exchange(int i, double *buf)
 {
+  // NOTE: how do I know comm buf is big enough if extreme # of touching neighs
+  // Comm::BUFEXTRA may need to be increased
+
   int m = 0;
   buf[m++] = npartner[i];
   for (int n = 0; n < npartner[i]; n++) {
     buf[m++] = partner[i][n];
     buf[m++] = shearpartner[i][n][0];
     buf[m++] = shearpartner[i][n][1];
     buf[m++] = shearpartner[i][n][2];
   }
   return m;
 }
 
 /* ----------------------------------------------------------------------
    unpack values in local atom-based arrays from exchange with another proc
 ------------------------------------------------------------------------- */
 
 int FixShearHistory::unpack_exchange(int nlocal, double *buf)
 {
+  // allocate new chunks from ipage,dpage for incoming values
+
   int m = 0;
   npartner[nlocal] = static_cast<int> (buf[m++]);
+  maxtouch = MAX(maxtouch,npartner[nlocal]);
+  partner[nlocal] = ipage->get(npartner[nlocal]);
+  shearpartner[nlocal] = dpage->get(npartner[nlocal]);
   for (int n = 0; n < npartner[nlocal]; n++) {
     partner[nlocal][n] = static_cast<int> (buf[m++]);
     shearpartner[nlocal][n][0] = buf[m++];
     shearpartner[nlocal][n][1] = buf[m++];
     shearpartner[nlocal][n][2] = buf[m++];
   }
   return m;
 }
 
 /* ----------------------------------------------------------------------
    pack values in local atom-based arrays for restart file
 ------------------------------------------------------------------------- */
 
 int FixShearHistory::pack_restart(int i, double *buf)
 {
   int m = 0;
   buf[m++] = 4*npartner[i] + 2;
   buf[m++] = npartner[i];
   for (int n = 0; n < npartner[i]; n++) {
     buf[m++] = partner[i][n];
     buf[m++] = shearpartner[i][n][0];
     buf[m++] = shearpartner[i][n][1];
     buf[m++] = shearpartner[i][n][2];
   }
   return m;
 }
 
 /* ----------------------------------------------------------------------
    unpack values from atom->extra array to restart the fix
 ------------------------------------------------------------------------- */
 
 void FixShearHistory::unpack_restart(int nlocal, int nth)
 {
   double **extra = atom->extra;
 
   // skip to Nth set of extra values
 
   int m = 0;
   for (int i = 0; i < nth; i++) m += static_cast<int> (extra[nlocal][m]);
   m++;
 
+  // allocate new chunks from ipage,dpage for incoming values
+
   npartner[nlocal] = static_cast<int> (extra[nlocal][m++]);
+  maxtouch = MAX(maxtouch,npartner[nlocal]);
+  partner[nlocal] = ipage->get(npartner[nlocal]);
+  shearpartner[nlocal] = dpage->get(npartner[nlocal]);
   for (int n = 0; n < npartner[nlocal]; n++) {
     partner[nlocal][n] = static_cast<int> (extra[nlocal][m++]);
     shearpartner[nlocal][n][0] = extra[nlocal][m++];
     shearpartner[nlocal][n][1] = extra[nlocal][m++];
     shearpartner[nlocal][n][2] = extra[nlocal][m++];
   }
 }
 
 /* ----------------------------------------------------------------------
    maxsize of any atom's restart data
 ------------------------------------------------------------------------- */
 
 int FixShearHistory::maxsize_restart()
 {
-  return 4*MAXTOUCH + 2;
+  // maxtouch_all = max touching partners across all procs
+
+  int maxtouch_all;
+  MPI_Allreduce(&maxtouch,&maxtouch_all,1,MPI_INT,MPI_MAX,world);
+  return 4*maxtouch_all + 2;
 }
 
 /* ----------------------------------------------------------------------
    size of atom nlocal's restart data
 ------------------------------------------------------------------------- */
 
 int FixShearHistory::size_restart(int nlocal)
 {
   return 4*npartner[nlocal] + 2;
 }
diff --git a/src/fix_shear_history.h b/src/fix_shear_history.h
index 974d3968e..79103ecb3 100644
--- a/src/fix_shear_history.h
+++ b/src/fix_shear_history.h
@@ -1,80 +1,85 @@
 /* -*- c++ -*- ----------------------------------------------------------
    LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
    http://lammps.sandia.gov, Sandia National Laboratories
    Steve Plimpton, sjplimp@sandia.gov
 
    Copyright (2003) Sandia Corporation.  Under the terms of Contract
    DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
    certain rights in this software.  This software is distributed under
    the GNU General Public License.
 
    See the README file in the top-level LAMMPS directory.
 ------------------------------------------------------------------------- */
 
 #ifdef FIX_CLASS
 
 FixStyle(SHEAR_HISTORY,FixShearHistory)
 
 #else
 
 #ifndef LMP_FIX_SHEAR_HISTORY_H
 #define LMP_FIX_SHEAR_HISTORY_H
 
 #include "fix.h"
+#include "my_page.h"
 
 namespace LAMMPS_NS {
 
 class FixShearHistory : public Fix {
   friend class Neighbor;
   friend class PairGranHookeHistory;
-  friend class FixPour;
 
  public:
   FixShearHistory(class LAMMPS *, int, char **);
   ~FixShearHistory();
   int setmask();
   void init();
   void setup_pre_exchange();
   virtual void pre_exchange();
   void min_setup_pre_exchange();
   void min_pre_exchange();
 
   double memory_usage();
   void grow_arrays(int);
   void copy_arrays(int, int, int);
   void set_arrays(int);
   int pack_exchange(int, double *);
   int unpack_exchange(int, double *);
   int pack_restart(int, double *);
   void unpack_restart(int, int);
   int size_restart(int);
   int maxsize_restart();
 
  protected:
   int *npartner;                // # of touching partners of each atom
   int **partner;                // tags for the partners
-  double ***shearpartner;       // 3 shear values with the partner
+  double (**shearpartner)[3];   // 3 shear values with the partner
+  int maxtouch;                 // max # of touching partners for my atoms
 
   class Pair *pair;
   int *computeflag;             // computeflag in PairGranHookeHistory
+
+  int pgsize,oneatom;           // copy of settings in Neighbor
+  MyPage<int> *ipage;           // pages of partner atom IDs
+  MyPage<double[3]> *dpage;     // pages of shear history with partners
 };
 
 }
 
 #endif
 #endif
 
 /* ERROR/WARNING messages:
 
 E: Pair style granular with history requires atoms have IDs
 
 Atoms in the simulation do not have IDs, so history effects
 cannot be tracked by the granular pair potential.
 
 E: Too many touching neighbors - boost MAXTOUCH
 
 A granular simulation has too many neighbors touching one atom.  The
 MAXTOUCH parameter in fix_shear_history.cpp must be set larger and
 LAMMPS must be re-built.
 
 */
diff --git a/src/my_page.h b/src/my_page.h
new file mode 100644
index 000000000..f4297abdf
--- /dev/null
+++ b/src/my_page.h
@@ -0,0 +1,225 @@
+/* -*- c++ -*- ----------------------------------------------------------
+   LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
+   http://lammps.sandia.gov, Sandia National Laboratories
+   Steve Plimpton, sjplimp@sandia.gov
+
+   Copyright (2003) Sandia Corporation.  Under the terms of Contract
+   DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
+   certain rights in this software.  This software is distributed under
+   the GNU General Public License.
+
+   See the README file in the top-level LAMMPS directory.
+------------------------------------------------------------------------- */
+
+/* ----------------------------------------------------------------------
+MyPage = templated class for storing chunks of datums in pages
+  chunks are not returnable, can only reset and start over
+  replaces many small mallocs with a few large mallocs
+  pages are never freed, so can reuse w/out reallocs
+usage:
+  request one datum at a time, repeat, clear
+  request chunks of datums in each get() or vget(), repeat, clear
+  chunk size can vary from request to request
+  chunk size can be known in advance or registered after usage via vgot()
+inputs:
+   template T = one datum, e.g. int, double, struct, int[3]
+     for int[3], access datum as ivec[i][2]
+methods:
+   T *get() = return ptr to one datum
+   T *get(N) = return ptr to N datums, N < maxchunk required
+   T *vget() = return ptr to maxchunk datums, use as needed, then call vgot()
+     all gets return NULL if error encountered
+   vgot(N) = used N datums of previous vget(), N < maxchunk required
+   void init(maxchunk, pagesize, pagedelta) (re-)initializes allocator. call right after "new".
+     maxchunk = max # of datums in one chunk, default = 1
+     pagesize = # of datums in one page, default = 1024
+               should be insure big enough to store multiple chunks
+     pagedelta = # of pages to allocate at a time, default = 1
+   void reset() = clear pages w/out freeing
+   int size() = return total size of allocated pages in bytes
+   int status() = return error status (0 = ok, 1 = invalid input,
+                   2 = allocation error, 3 = chunksize > maxchunk)
+------------------------------------------------------------------------- */
+
+#ifndef LAMMPS_MY_PAGE_H
+#define LAMMPS_MY_PAGE_H
+
+#include "stdlib.h"
+namespace LAMMPS_NS {
+
+template<class T>
+class MyPage {
+ public:
+  MyPage() {
+    ndatum = nchunk = 0;
+    pages = NULL;
+    npage = 0;
+    errorflag = 0;
+  }
+
+  void init(int user_maxchunk = 1, int user_pagesize = 1024, 
+            int user_pagedelta = 1) {
+    maxchunk = user_maxchunk;
+    pagesize = user_pagesize;
+    pagedelta = user_pagedelta;
+
+    errorflag = 0;
+    if (maxchunk <= 0 || pagesize <= 0 || pagedelta <= 0) errorflag = 1;
+    if (maxchunk > pagesize) errorflag = 1;
+    if (errorflag) return;
+
+    for (int i = 0; i < npage; i++) free(pages[i]);
+    free(pages);
+
+    // initial page allocation
+
+    ndatum = nchunk = 0;
+    pages = NULL;
+    npage = 0;
+    allocate();
+    if (errorflag) return;
+    ipage = index = 0;
+    page = pages[ipage];
+  }
+
+  // free all pages of allocated memory
+
+  ~MyPage() {
+    for (int i = 0; i < npage; i++) free(pages[i]);
+    free(pages);
+  }
+
+  // get ptr to one datum
+  // return NULL if run out of memory
+
+  T *get() {
+    ndatum++;
+    nchunk++;
+    if (index < pagesize) return &page[index++];
+    ipage++;
+    if (ipage == npage) {
+      allocate();
+      if (errorflag) return NULL;
+    }
+    page = pages[ipage];
+    index = 0;
+    return &page[index++];
+  }
+
+  // get ptr to location that can store N datums
+  // error if N > maxchunk
+  // return NULL if run out of memory
+
+  T *get(int n) {
+    if (n > maxchunk) {
+      errorflag = 3;
+      return NULL;
+    }
+    ndatum += n;
+    nchunk++;
+    if (index+n <= pagesize) {
+      int start = index;
+      index += n;
+      return &page[start];
+    }
+    ipage++;
+    if (ipage == npage) {
+      allocate();
+      if (errorflag) return NULL;
+    }
+    page = pages[ipage];
+    index = n;
+    return &page[0];
+  }
+
+  // get ptr to location that can store maxchunk datums
+  // will return same ptr as previous call if vgot() not called
+  // return NULL if run out of memory
+  
+  T *vget() {
+    if (index+maxchunk <= pagesize) return &page[index];
+    ipage++;
+    if (ipage == npage) {
+      allocate();
+      if (errorflag) return NULL;
+    }
+    page = pages[ipage];
+    index = 0;
+    return &page[index];
+  }
+
+  // increment by N = # of values stored in loc returned by vget()
+  // OK to not call if vget() ptr was not used
+  // error if N > maxchunk
+
+  void vgot(int n) {
+    if (n > maxchunk) errorflag = 3;
+    ndatum += n;
+    nchunk++;
+    index += n;
+  }
+
+  // reset index to beginning of first page
+  // effectively clears all pages, without freeing any memory
+
+  void reset() {
+    ndatum = nchunk = 0;
+    index = ipage = 0;
+    page = pages[ipage];
+  }
+
+  // return total size of all allocated pages
+
+  int size() const {
+    return npage*pagesize*sizeof(T);
+  }
+
+  // return error status
+
+  int status() const {
+    return errorflag;
+  }
+
+ private:
+  T **pages;      // list of allocated pages
+  T *page;        // ptr to current page
+  int npage;      // # of allocated pages
+  int ipage;      // index of current page
+  int index;      // current index on current page
+  
+  int ndatum;      // total # of stored datums
+  int nchunk;      // total # of stored chunks
+  int errorflag;   // flag > 1 if error has occurred
+                   // 1 = invalid inputs
+                   // 2 = memory allocation error
+                   // 3 = chunk size exceeded maxchunk
+
+  int maxchunk;   // max # of datums in one requested chunk
+  int pagesize;   // # of datums in one page, default = 1024
+  int pagedelta;  // # of pages to allocate at once, default = 1
+
+  void allocate() {
+    npage += pagedelta;
+    pages = (T **) realloc(pages,npage*sizeof(T *));
+    if (!pages) {
+      errorflag = 2;
+      return;
+    }
+
+    void *ptr;
+    for (int i = npage-pagedelta; i < npage; i++) {
+#if defined(LAMMPS_MEMALIGN)
+      if (posix_memalign(&ptr, LAMMPS_MEMALIGN, pagesize*sizeof(T)))
+        errorflag = 2;
+      pages[i] = (T *) ptr;
+#else
+      pages[i] = (T *) malloc(pagesize*sizeof(T));
+      if (!pages[i]) errorflag = 2;
+#endif
+    }
+  }
+};
+
+}
+
+#endif
diff --git a/src/neigh_derive.cpp b/src/neigh_derive.cpp
index 4bda3d71d..343dc1dc6 100644
--- a/src/neigh_derive.cpp
+++ b/src/neigh_derive.cpp
@@ -1,504 +1,459 @@
 /* ----------------------------------------------------------------------
    LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
    http://lammps.sandia.gov, Sandia National Laboratories
    Steve Plimpton, sjplimp@sandia.gov
 
    Copyright (2003) Sandia Corporation.  Under the terms of Contract
    DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
    certain rights in this software.  This software is distributed under
    the GNU General Public License.
 
    See the README file in the top-level LAMMPS directory.
 ------------------------------------------------------------------------- */
 
 #include "neighbor.h"
 #include "neigh_list.h"
 #include "atom.h"
+#include "my_page.h"
 #include "error.h"
 
 using namespace LAMMPS_NS;
 
 /* ----------------------------------------------------------------------
    build half list from full list
    pair stored once if i,j are both owned and i < j
    pair stored by me if j is ghost (also stored by proc owning j)
    works if full list is a skip list
 ------------------------------------------------------------------------- */
 
 void Neighbor::half_from_full_no_newton(NeighList *list)
 {
   int i,j,ii,jj,n,jnum,joriginal;
   int *neighptr,*jlist;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
-  int **pages = list->pages;
+  MyPage<int> *ipage = list->ipage;
+
   int *ilist_full = list->listfull->ilist;
   int *numneigh_full = list->listfull->numneigh;
   int **firstneigh_full = list->listfull->firstneigh;
   int inum_full = list->listfull->inum;
 
   int inum = 0;
-  int npage = 0;
-  int npnt = 0;
+  ipage->reset();
 
   // loop over atoms in full list
 
   for (ii = 0; ii < inum_full; ii++) {
-
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage++;
-      if (npage == list->maxpage) pages = list->add_pages();
-    }
-
-    neighptr = &pages[npage][npnt];
     n = 0;
+    neighptr = ipage->vget();
 
     // loop over parent full list
 
     i = ilist_full[ii];
     jlist = firstneigh_full[i];
     jnum = numneigh_full[i];
 
     for (jj = 0; jj < jnum; jj++) {
       joriginal = jlist[jj];
       j = joriginal & NEIGHMASK;
       if (j > i) neighptr[n++] = joriginal;
     }
 
     ilist[inum++] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage->vgot(n);
+    if (ipage->status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
 
   list->inum = inum;
 }
 
 /* ----------------------------------------------------------------------
    build half list from full list
    pair stored once if i,j are both owned and i < j
    if j is ghost, only store if j coords are "above and to the right" of i
    works if full list is a skip list
 ------------------------------------------------------------------------- */
 
 void Neighbor::half_from_full_newton(NeighList *list)
 {
   int i,j,ii,jj,n,jnum,joriginal;
   int *neighptr,*jlist;
   double xtmp,ytmp,ztmp;
 
   double **x = atom->x;
   int nlocal = atom->nlocal;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
-  int **pages = list->pages;
+  MyPage<int> *ipage = list->ipage;
+
   int *ilist_full = list->listfull->ilist;
   int *numneigh_full = list->listfull->numneigh;
   int **firstneigh_full = list->listfull->firstneigh;
   int inum_full = list->listfull->inum;
 
   int inum = 0;
-  int npage = 0;
-  int npnt = 0;
+  ipage->reset();
 
   // loop over parent full list
 
   for (ii = 0; ii < inum_full; ii++) {
-
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage++;
-      if (npage == list->maxpage) pages = list->add_pages();
-    }
-
-    neighptr = &pages[npage][npnt];
     n = 0;
+    neighptr = ipage->vget();
 
     i = ilist_full[ii];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over full neighbor list
 
     jlist = firstneigh_full[i];
     jnum = numneigh_full[i];
 
     for (jj = 0; jj < jnum; jj++) {
       joriginal = jlist[jj];
       j = joriginal & NEIGHMASK;
       if (j < nlocal) {
         if (i > j) continue;
       } else {
         if (x[j][2] < ztmp) continue;
         if (x[j][2] == ztmp) {
           if (x[j][1] < ytmp) continue;
           if (x[j][1] == ytmp && x[j][0] < xtmp) continue;
         }
       }
       neighptr[n++] = joriginal;
     }
 
     ilist[inum++] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage->vgot(n);
+    if (ipage->status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
 
   list->inum = inum;
 }
 
 /* ----------------------------------------------------------------------
    build skip list for subset of types from parent list
    iskip and ijskip flag which atom types and type pairs to skip
    this is for half and full lists
    if ghostflag, also store neighbors of ghost atoms & set inum,gnum correctly
 ------------------------------------------------------------------------- */
 
 void Neighbor::skip_from(NeighList *list)
 {
   int i,j,ii,jj,n,itype,jnum,joriginal;
   int *neighptr,*jlist;
 
   int *type = atom->type;
   int nlocal = atom->nlocal;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
-  int **pages = list->pages;
+  MyPage<int> *ipage = list->ipage;
+
   int *ilist_skip = list->listskip->ilist;
   int *numneigh_skip = list->listskip->numneigh;
   int **firstneigh_skip = list->listskip->firstneigh;
   int num_skip = list->listskip->inum;
   if (list->ghostflag) num_skip += list->listskip->gnum;
 
   int *iskip = list->iskip;
   int **ijskip = list->ijskip;
 
   int inum = 0;
-  int npage = 0;
-  int npnt = 0;
+  ipage->reset();
 
   // loop over atoms in other list
   // skip I atom entirely if iskip is set for type[I]
   // skip I,J pair if ijskip is set for type[I],type[J]
 
   for (ii = 0; ii < num_skip; ii++) {
     i = ilist_skip[ii];
     itype = type[i];
     if (iskip[itype]) continue;
 
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage++;
-      if (npage == list->maxpage) pages = list->add_pages();
-    }
-
-    neighptr = &pages[npage][npnt];
     n = 0;
+    neighptr = ipage->vget();
 
     // loop over parent non-skip list
 
     jlist = firstneigh_skip[i];
     jnum = numneigh_skip[i];
 
     for (jj = 0; jj < jnum; jj++) {
       joriginal = jlist[jj];
       j = joriginal & NEIGHMASK;
       if (ijskip[itype][type[j]]) continue;
       neighptr[n++] = joriginal;
     }
 
     ilist[inum++] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage->vgot(n);
+    if (ipage->status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
 
   list->inum = inum;
   if (list->ghostflag) {
     int num = 0;
     for (i = 0; i < inum; i++)
       if (ilist[i] < nlocal) num++;
       else break;
     list->inum = num;
     list->gnum = inum - num;
   }
 }
 
 /* ----------------------------------------------------------------------
    build skip list for subset of types from parent list
    iskip and ijskip flag which atom types and type pairs to skip
    this is for granular lists with history, copy the history values from parent
 ------------------------------------------------------------------------- */
 
 void Neighbor::skip_from_granular(NeighList *list)
 {
   int i,j,ii,jj,n,nn,itype,jnum,joriginal;
   int *neighptr,*jlist,*touchptr,*touchptr_skip;
   double *shearptr,*shearptr_skip;
 
   int *type = atom->type;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
-  int **pages = list->pages;
+  MyPage<int> *ipage = list->ipage;
+
   int *ilist_skip = list->listskip->ilist;
   int *numneigh_skip = list->listskip->numneigh;
   int **firstneigh_skip = list->listskip->firstneigh;
   int **firsttouch_skip = list->listskip->listgranhistory->firstneigh;
   double **firstshear_skip = list->listskip->listgranhistory->firstdouble;
   int inum_skip = list->listskip->inum;
 
   int *iskip = list->iskip;
   int **ijskip = list->ijskip;
 
   NeighList *listgranhistory = list->listgranhistory;
   int **firsttouch = listgranhistory->firstneigh;
   double **firstshear = listgranhistory->firstdouble;
-  int **pages_touch = listgranhistory->pages;
-  double **pages_shear = listgranhistory->dpages;
+  MyPage<int> *ipage_touch = listgranhistory->ipage;
+  MyPage<double> *dpage_shear = listgranhistory->dpage;
 
   int inum = 0;
-  int npage = 0;
-  int npnt = 0;
+  ipage->reset();
+  ipage_touch->reset();
+  dpage_shear->reset();
 
   // loop over atoms in other list
   // skip I atom entirely if iskip is set for type[I]
   // skip I,J pair if ijskip is set for type[I],type[J]
 
   for (ii = 0; ii < inum_skip; ii++) {
     i = ilist_skip[ii];
     itype = type[i];
     if (iskip[itype]) continue;
 
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage++;
-      if (npage == list->maxpage) {
-        pages = list->add_pages();
-        pages_touch = listgranhistory->add_pages();
-        pages_shear = listgranhistory->dpages;
-      }
-    }
-
-    n = 0;
-    neighptr = &pages[npage][npnt];
-    nn = 0;
-    touchptr = &pages_touch[npage][npnt];
-    shearptr = &pages_shear[npage][3*npnt];
+    n = nn = 0;
+    neighptr = ipage->vget();
+    touchptr = ipage_touch->vget();
+    shearptr = dpage_shear->vget();
 
     // loop over parent non-skip granular list and its history info
 
     touchptr_skip = firsttouch_skip[i];
     shearptr_skip = firstshear_skip[i];
     jlist = firstneigh_skip[i];
     jnum = numneigh_skip[i];
 
     for (jj = 0; jj < jnum; jj++) {
       joriginal = jlist[jj];
       j = joriginal & NEIGHMASK;
       if (ijskip[itype][type[j]]) continue;
       neighptr[n] = joriginal;
       touchptr[n++] = touchptr_skip[jj];
       shearptr[nn++] = shearptr_skip[3*jj];
       shearptr[nn++] = shearptr_skip[3*jj+1];
       shearptr[nn++] = shearptr_skip[3*jj+2];
     }
 
     ilist[inum++] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
+    ipage->vgot(n);
+    if (ipage->status())
+      error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
+
     firsttouch[i] = touchptr;
     firstshear[i] = shearptr;
-    npnt += n;
-    if (n > oneatom)
-      error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
+    ipage_touch->vgot(n);
+    dpage_shear->vgot(nn);
   }
 
   list->inum = inum;
 }
 
 /* ----------------------------------------------------------------------
    build skip list for subset of types from parent list
    iskip and ijskip flag which atom types and type pairs to skip
    this is for respa lists, copy the inner/middle values from parent
 ------------------------------------------------------------------------- */
 
 void Neighbor::skip_from_respa(NeighList *list)
 {
   int i,j,ii,jj,n,itype,jnum,joriginal,n_inner,n_middle;
   int *neighptr,*jlist,*neighptr_inner,*neighptr_middle;
 
   int *type = atom->type;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
-  int **pages = list->pages;
+  MyPage<int> *ipage = list->ipage;
+
   int *ilist_skip = list->listskip->ilist;
   int *numneigh_skip = list->listskip->numneigh;
   int **firstneigh_skip = list->listskip->firstneigh;
   int inum_skip = list->listskip->inum;
 
   int *iskip = list->iskip;
   int **ijskip = list->ijskip;
 
   NeighList *listinner = list->listinner;
   int *numneigh_inner = listinner->numneigh;
   int **firstneigh_inner = listinner->firstneigh;
-  int **pages_inner = listinner->pages;
+  MyPage<int> *ipage_inner = listinner->ipage;
+
   int *numneigh_inner_skip = list->listskip->listinner->numneigh;
   int **firstneigh_inner_skip = list->listskip->listinner->firstneigh;
 
   NeighList *listmiddle;
-  int *numneigh_middle,**firstneigh_middle,**pages_middle;
+  int *ilist_middle,*numneigh_middle,**firstneigh_middle;
+  MyPage<int> *ipage_middle;
   int *numneigh_middle_skip,**firstneigh_middle_skip;
   int respamiddle = list->respamiddle;
   if (respamiddle) {
     listmiddle = list->listmiddle;
     numneigh_middle = listmiddle->numneigh;
     firstneigh_middle = listmiddle->firstneigh;
-    pages_middle = listmiddle->pages;
+    ipage_middle = listmiddle->ipage;
     numneigh_middle_skip = list->listskip->listmiddle->numneigh;
     firstneigh_middle_skip = list->listskip->listmiddle->firstneigh;
   }
 
   int inum = 0;
-  int npage = 0;
-  int npnt = 0;
-  int npage_inner = 0;
-  int npnt_inner = 0;
-  int npage_middle = 0;
-  int npnt_middle = 0;
+  ipage->reset();
+  ipage_inner->reset();
+  if (respamiddle) ipage_middle->reset();
 
   // loop over atoms in other list
   // skip I atom entirely if iskip is set for type[I]
   // skip I,J pair if ijskip is set for type[I],type[J]
 
   for (ii = 0; ii < inum_skip; ii++) {
     i = ilist_skip[ii];
     itype = type[i];
     if (iskip[itype]) continue;
 
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage++;
-      if (npage == list->maxpage) pages = list->add_pages();
-    }
-    neighptr = &pages[npage][npnt];
-    n = 0;
-
-    if (pgsize - npnt_inner < oneatom) {
-      npnt_inner = 0;
-      npage_inner++;
-      if (npage_inner == listinner->maxpage)
-        pages_inner = listinner->add_pages();
-    }
-    neighptr_inner = &pages_inner[npage_inner][npnt_inner];
-    n_inner = 0;
-
+    n = n_inner = 0;
+    neighptr = ipage->vget();
+    neighptr_inner = ipage_inner->vget();
     if (respamiddle) {
-      if (pgsize - npnt_middle < oneatom) {
-        npnt_middle = 0;
-        npage_middle++;
-        if (npage_middle == listmiddle->maxpage)
-          pages_middle = listmiddle->add_pages();
-      }
-      neighptr_middle = &pages_middle[npage_middle][npnt_middle];
       n_middle = 0;
+      neighptr_middle = ipage_middle->vget();
     }
 
     // loop over parent outer rRESPA list
 
     jlist = firstneigh_skip[i];
     jnum = numneigh_skip[i];
 
     for (jj = 0; jj < jnum; jj++) {
       joriginal = jlist[jj];
       j = joriginal & NEIGHMASK;
       if (ijskip[itype][type[j]]) continue;
       neighptr[n++] = joriginal;
     }
 
     // loop over parent inner rRESPA list
 
     jlist = firstneigh_inner_skip[i];
     jnum = numneigh_inner_skip[i];
 
     for (jj = 0; jj < jnum; jj++) {
       joriginal = jlist[jj];
       j = joriginal & NEIGHMASK;
       if (ijskip[itype][type[j]]) continue;
       neighptr_inner[n_inner++] = joriginal;
     }
 
     // loop over parent middle rRESPA list
 
     if (respamiddle) {
       jlist = firstneigh_middle_skip[i];
       jnum = numneigh_middle_skip[i];
 
       for (jj = 0; jj < jnum; jj++) {
         joriginal = jlist[jj];
         j = joriginal & NEIGHMASK;
         if (ijskip[itype][type[j]]) continue;
         neighptr_middle[n_middle++] = joriginal;
       }
     }
 
-    ilist[inum++] = i;
+    ilist[inum] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage->vgot(n);
+    if (ipage->status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
 
     firstneigh_inner[i] = neighptr_inner;
     numneigh_inner[i] = n_inner;
-    npnt_inner += n_inner;
-    if (n_inner > oneatom)
+    ipage_inner->vgot(n);
+    if (ipage_inner->status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
 
     if (respamiddle) {
       firstneigh_middle[i] = neighptr_middle;
       numneigh_middle[i] = n_middle;
-      npnt_middle += n_middle;
-      if (n_middle > oneatom)
+      ipage_middle->vgot(n);
+      if (ipage_middle->status())
         error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
     }
   }
 
   list->inum = inum;
 }
 
 /* ----------------------------------------------------------------------
    create list which is simply a copy of parent list
 ------------------------------------------------------------------------- */
 
 void Neighbor::copy_from(NeighList *list)
 {
   NeighList *listcopy = list->listcopy;
 
   list->inum = listcopy->inum;
   list->gnum = listcopy->gnum;
   list->ilist = listcopy->ilist;
   list->numneigh = listcopy->numneigh;
   list->firstneigh = listcopy->firstneigh;
   list->firstdouble = listcopy->firstdouble;
-  list->pages = listcopy->pages;
-  list->dpages = listcopy->dpages;
+  list->ipage = listcopy->ipage;
+  list->dpage = listcopy->dpage;
 }
diff --git a/src/neigh_full.cpp b/src/neigh_full.cpp
index 970e3c572..0c830b372 100644
--- a/src/neigh_full.cpp
+++ b/src/neigh_full.cpp
@@ -1,542 +1,503 @@
 /* ----------------------------------------------------------------------
    LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
    http://lammps.sandia.gov, Sandia National Laboratories
    Steve Plimpton, sjplimp@sandia.gov
 
    Copyright (2003) Sandia Corporation.  Under the terms of Contract
    DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
    certain rights in this software.  This software is distributed under
    the GNU General Public License.
 
    See the README file in the top-level LAMMPS directory.
 ------------------------------------------------------------------------- */
 
 #include "neighbor.h"
 #include "neigh_list.h"
 #include "atom.h"
 #include "domain.h"
+#include "my_page.h"
 #include "group.h"
 #include "error.h"
 
 using namespace LAMMPS_NS;
 
 /* ----------------------------------------------------------------------
    N^2 search for all neighbors
    every neighbor pair appears in list of both atoms i and j
 ------------------------------------------------------------------------- */
 
 void Neighbor::full_nsq(NeighList *list)
 {
   int i,j,n,itype,jtype,which,bitmask;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int *neighptr;
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int nlocal = atom->nlocal;
   int nall = nlocal + atom->nghost;
   int molecular = atom->molecular;
   if (includegroup) {
     nlocal = atom->nfirst;
     bitmask = group->bitmask[includegroup];
   }
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
-  int **pages = list->pages;
+  MyPage<int> *ipage = list->ipage;
 
   int inum = 0;
-  int npage = 0;
-  int npnt = 0;
+  ipage->reset();
 
   // loop over owned atoms, storing neighbors
 
   for (i = 0; i < nlocal; i++) {
-
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage++;
-      if (npage == list->maxpage) pages = list->add_pages();
-    }
-
-    neighptr = &pages[npage][npnt];
     n = 0;
+    neighptr = ipage->vget();
 
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over all atoms, owned and ghost
     // skip i = j
 
     for (j = 0; j < nall; j++) {
       if (includegroup && !(mask[j] & bitmask)) continue;
       if (i == j) continue;
       jtype = type[j];
       if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
       delx = xtmp - x[j][0];
       dely = ytmp - x[j][1];
       delz = ztmp - x[j][2];
       rsq = delx*delx + dely*dely + delz*delz;
       if (rsq <= cutneighsq[itype][jtype]) {
         if (molecular) {
           which = find_special(special[i],nspecial[i],tag[j]);
           if (which == 0) neighptr[n++] = j;
           else if (domain->minimum_image_check(delx,dely,delz))
             neighptr[n++] = j;
           else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
         } else neighptr[n++] = j;
       }
     }
 
     ilist[inum++] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage->vgot(n);
+    if (ipage->status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
 
   list->inum = inum;
   list->gnum = 0;
 }
 
 /* ----------------------------------------------------------------------
    N^2 search for all neighbors
    include neighbors of ghost atoms, but no "special neighbors" for ghosts
    every neighbor pair appears in list of both atoms i and j
 ------------------------------------------------------------------------- */
 
 void Neighbor::full_nsq_ghost(NeighList *list)
 {
   int i,j,n,itype,jtype,which;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int *neighptr;
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int nlocal = atom->nlocal;
   int nall = nlocal + atom->nghost;
   int molecular = atom->molecular;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
-  int **pages = list->pages;
+  MyPage<int> *ipage = list->ipage;
 
   int inum = 0;
-  int npage = 0;
-  int npnt = 0;
+  ipage->reset();
 
   // loop over owned & ghost atoms, storing neighbors
 
   for (i = 0; i < nall; i++) {
-
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage++;
-      if (npage == list->maxpage) pages = list->add_pages();
-    }
-
-    neighptr = &pages[npage][npnt];
     n = 0;
+    neighptr = ipage->vget();
 
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over all atoms, owned and ghost
     // skip i = j
     // no molecular test when i = ghost atom
 
     if (i < nlocal) {
       for (j = 0; j < nall; j++) {
         if (i == j) continue;
         jtype = type[j];
         if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
         delx = xtmp - x[j][0];
         dely = ytmp - x[j][1];
         delz = ztmp - x[j][2];
         rsq = delx*delx + dely*dely + delz*delz;
         if (rsq <= cutneighsq[itype][jtype]) {
           if (molecular) {
             which = find_special(special[i],nspecial[i],tag[j]);
             if (which == 0) neighptr[n++] = j;
             else if (domain->minimum_image_check(delx,dely,delz))
               neighptr[n++] = j;
             else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
           } else neighptr[n++] = j;
         }
       }
     } else {
       for (j = 0; j < nall; j++) {
         if (i == j) continue;
         jtype = type[j];
         if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
         delx = xtmp - x[j][0];
         dely = ytmp - x[j][1];
         delz = ztmp - x[j][2];
         rsq = delx*delx + dely*dely + delz*delz;
 
         if (rsq <= cutneighghostsq[itype][jtype]) neighptr[n++] = j;
       }
     }
 
     ilist[inum++] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage->vgot(n);
+    if (ipage->status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
 
   list->inum = atom->nlocal;
   list->gnum = inum - atom->nlocal;
 }
 
 /* ----------------------------------------------------------------------
    binned neighbor list construction for all neighbors
    every neighbor pair appears in list of both atoms i and j
 ------------------------------------------------------------------------- */
 
 void Neighbor::full_bin(NeighList *list)
 {
   int i,j,k,n,itype,jtype,ibin,which;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int *neighptr;
 
   // bin owned & ghost atoms
 
   bin_atoms();
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int nlocal = atom->nlocal;
   int molecular = atom->molecular;
   if (includegroup) nlocal = atom->nfirst;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
-  int **pages = list->pages;
   int nstencil = list->nstencil;
   int *stencil = list->stencil;
+  MyPage<int> *ipage = list->ipage;
 
   int inum = 0;
-  int npage = 0;
-  int npnt = 0;
+  ipage->reset();
 
   // loop over owned atoms, storing neighbors
 
   for (i = 0; i < nlocal; i++) {
-
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage++;
-      if (npage == list->maxpage) pages = list->add_pages();
-    }
-
-    neighptr = &pages[npage][npnt];
     n = 0;
+    neighptr = ipage->vget();
 
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over all atoms in surrounding bins in stencil including self
     // skip i = j
 
     ibin = coord2bin(x[i]);
 
     for (k = 0; k < nstencil; k++) {
       for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
         if (i == j) continue;
 
         jtype = type[j];
         if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
         delx = xtmp - x[j][0];
         dely = ytmp - x[j][1];
         delz = ztmp - x[j][2];
         rsq = delx*delx + dely*dely + delz*delz;
 
         if (rsq <= cutneighsq[itype][jtype]) {
           if (molecular) {
             which = find_special(special[i],nspecial[i],tag[j]);
             if (which == 0) neighptr[n++] = j;
             else if (domain->minimum_image_check(delx,dely,delz))
               neighptr[n++] = j;
             else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
           } else neighptr[n++] = j;
         }
       }
     }
 
     ilist[inum++] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage->vgot(n);
+    if (ipage->status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
 
   list->inum = inum;
   list->gnum = 0;
 }
 
 /* ----------------------------------------------------------------------
    binned neighbor list construction for all neighbors
    include neighbors of ghost atoms, but no "special neighbors" for ghosts
    every neighbor pair appears in list of both atoms i and j
 ------------------------------------------------------------------------- */
 
 void Neighbor::full_bin_ghost(NeighList *list)
 {
   int i,j,k,n,itype,jtype,ibin,which;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int xbin,ybin,zbin,xbin2,ybin2,zbin2;
   int *neighptr;
 
   // bin owned & ghost atoms
 
   bin_atoms();
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int nlocal = atom->nlocal;
   int nall = nlocal + atom->nghost;
   int molecular = atom->molecular;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
-  int **pages = list->pages;
   int nstencil = list->nstencil;
   int *stencil = list->stencil;
   int **stencilxyz = list->stencilxyz;
+  MyPage<int> *ipage = list->ipage;
 
   int inum = 0;
-  int npage = 0;
-  int npnt = 0;
+  ipage->reset();
 
   // loop over owned & ghost atoms, storing neighbors
 
   for (i = 0; i < nall; i++) {
-
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage++;
-      if (npage == list->maxpage) pages = list->add_pages();
-    }
-
-    neighptr = &pages[npage][npnt];
     n = 0;
+    neighptr = ipage->vget();
 
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over all atoms in surrounding bins in stencil including self
     // when i is a ghost atom, must check if stencil bin is out of bounds
     // skip i = j
     // no molecular test when i = ghost atom
 
     if (i < nlocal) {
       ibin = coord2bin(x[i]);
       for (k = 0; k < nstencil; k++) {
         for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
           if (i == j) continue;
 
           jtype = type[j];
           if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
           delx = xtmp - x[j][0];
           dely = ytmp - x[j][1];
           delz = ztmp - x[j][2];
           rsq = delx*delx + dely*dely + delz*delz;
 
           if (rsq <= cutneighsq[itype][jtype]) {
             if (molecular) {
               which = find_special(special[i],nspecial[i],tag[j]);
               if (which == 0) neighptr[n++] = j;
               else if (domain->minimum_image_check(delx,dely,delz))
                 neighptr[n++] = j;
               else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
             } else neighptr[n++] = j;
           }
         }
       }
 
     } else {
       ibin = coord2bin(x[i],xbin,ybin,zbin);
       for (k = 0; k < nstencil; k++) {
         xbin2 = xbin + stencilxyz[k][0];
         ybin2 = ybin + stencilxyz[k][1];
         zbin2 = zbin + stencilxyz[k][2];
         if (xbin2 < 0 || xbin2 >= mbinx ||
             ybin2 < 0 || ybin2 >= mbiny ||
             zbin2 < 0 || zbin2 >= mbinz) continue;
         for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
           if (i == j) continue;
 
           jtype = type[j];
           if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
           delx = xtmp - x[j][0];
           dely = ytmp - x[j][1];
           delz = ztmp - x[j][2];
           rsq = delx*delx + dely*dely + delz*delz;
 
           if (rsq <= cutneighghostsq[itype][jtype]) neighptr[n++] = j;
         }
       }
     }
 
     ilist[inum++] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage->vgot(n);
+    if (ipage->status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
 
   list->inum = atom->nlocal;
   list->gnum = inum - atom->nlocal;
 }
 
 /* ----------------------------------------------------------------------
    binned neighbor list construction for all neighbors
    multi-type stencil is itype dependent and is distance checked
    every neighbor pair appears in list of both atoms i and j
 ------------------------------------------------------------------------- */
 
 void Neighbor::full_multi(NeighList *list)
 {
   int i,j,k,n,itype,jtype,ibin,which,ns;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int *neighptr,*s;
   double *cutsq,*distsq;
 
   // bin local & ghost atoms
 
   bin_atoms();
 
   // loop over each atom, storing neighbors
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int nlocal = atom->nlocal;
   int molecular = atom->molecular;
   if (includegroup) nlocal = atom->nfirst;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
-  int **pages = list->pages;
   int *nstencil_multi = list->nstencil_multi;
   int **stencil_multi = list->stencil_multi;
   double **distsq_multi = list->distsq_multi;
+  MyPage<int> *ipage = list->ipage;
 
   int inum = 0;
-  int npage = 0;
-  int npnt = 0;
+  ipage->reset();
 
   for (i = 0; i < nlocal; i++) {
-
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage++;
-      if (npage == list->maxpage) pages = list->add_pages();
-    }
-
-    neighptr = &pages[npage][npnt];
     n = 0;
+    neighptr = ipage->vget();
 
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over all atoms in other bins in stencil, including self
     // skip if i,j neighbor cutoff is less than bin distance
     // skip i = j
 
     ibin = coord2bin(x[i]);
     s = stencil_multi[itype];
     distsq = distsq_multi[itype];
     cutsq = cutneighsq[itype];
     ns = nstencil_multi[itype];
     for (k = 0; k < ns; k++) {
       for (j = binhead[ibin+s[k]]; j >= 0; j = bins[j]) {
         jtype = type[j];
         if (cutsq[jtype] < distsq[k]) continue;
         if (i == j) continue;
 
         if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
         delx = xtmp - x[j][0];
         dely = ytmp - x[j][1];
         delz = ztmp - x[j][2];
         rsq = delx*delx + dely*dely + delz*delz;
 
         if (rsq <= cutneighsq[itype][jtype]) {
           if (molecular) {
             which = find_special(special[i],nspecial[i],tag[j]);
             if (which == 0) neighptr[n++] = j;
             else if (domain->minimum_image_check(delx,dely,delz))
               neighptr[n++] = j;
             else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
           } else neighptr[n++] = j;
         }
       }
     }
 
     ilist[inum++] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage->vgot(n);
+    if (ipage->status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
 
   list->inum = inum;
   list->gnum = 0;
 }
diff --git a/src/neigh_gran.cpp b/src/neigh_gran.cpp
index a5a70b2b4..204988e23 100644
--- a/src/neigh_gran.cpp
+++ b/src/neigh_gran.cpp
@@ -1,624 +1,586 @@
 /* ----------------------------------------------------------------------
    LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
    http://lammps.sandia.gov, Sandia National Laboratories
    Steve Plimpton, sjplimp@sandia.gov
 
    Copyright (2003) Sandia Corporation.  Under the terms of Contract
    DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
    certain rights in this software.  This software is distributed under
    the GNU General Public License.
 
    See the README file in the top-level LAMMPS directory.
 ------------------------------------------------------------------------- */
 
 #include "neighbor.h"
 #include "neigh_list.h"
 #include "atom.h"
 #include "group.h"
 #include "fix_shear_history.h"
 #include "error.h"
 
 using namespace LAMMPS_NS;
 
 /* ----------------------------------------------------------------------
    granular particles
    N^2 / 2 search for neighbor pairs with partial Newton's 3rd law
    shear history must be accounted for when a neighbor pair is added
    pair added to list if atoms i and j are both owned and i < j
    pair added if j is ghost (also stored by proc owning j)
 ------------------------------------------------------------------------- */
 
 void Neighbor::granular_nsq_no_newton(NeighList *list)
 {
   int i,j,m,n,nn,bitmask;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   double radi,radsum,cutsq;
   int *neighptr,*touchptr;
   double *shearptr;
 
   NeighList *listgranhistory;
   int *npartner,**partner;
-  double ***shearpartner;
+  double (**shearpartner)[3];
   int **firsttouch;
   double **firstshear;
-  int **pages_touch;
-  double **pages_shear;
+  MyPage<int> *ipage_touch;
+  MyPage<double> *dpage_shear;
 
   double **x = atom->x;
   double *radius = atom->radius;
   int *tag = atom->tag;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int nlocal = atom->nlocal;
   int nall = nlocal + atom->nghost;
   if (includegroup) {
     nlocal = atom->nfirst;
     bitmask = group->bitmask[includegroup];
   }
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
-  int **pages = list->pages;
+  MyPage<int> *ipage = list->ipage;
 
   FixShearHistory *fix_history = list->fix_history;
   if (fix_history) {
     npartner = fix_history->npartner;
     partner = fix_history->partner;
     shearpartner = fix_history->shearpartner;
     listgranhistory = list->listgranhistory;
     firsttouch = listgranhistory->firstneigh;
     firstshear = listgranhistory->firstdouble;
-    pages_touch = listgranhistory->pages;
-    pages_shear = listgranhistory->dpages;
+    ipage_touch = listgranhistory->ipage;
+    dpage_shear = listgranhistory->dpage;
   }
 
   int inum = 0;
-  int npage = 0;
-  int npnt = 0;
+  ipage->reset();
+  if (fix_history) {
+    ipage_touch->reset();
+    dpage_shear->reset();
+  }
 
   for (i = 0; i < nlocal; i++) {
-
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage++;
-      if (npage == list->maxpage) {
-        pages = list->add_pages();
-        if (fix_history) {
-          pages_touch = listgranhistory->add_pages();
-          pages_shear = listgranhistory->dpages;
-        }
-      }
-    }
-
     n = 0;
-    neighptr = &pages[npage][npnt];
+    neighptr = ipage->vget();
     if (fix_history) {
       nn = 0;
-      touchptr = &pages_touch[npage][npnt];
-      shearptr = &pages_shear[npage][3*npnt];
+      touchptr = ipage_touch->vget();
+      shearptr = dpage_shear->vget();
     }
 
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
     radi = radius[i];
 
     // loop over remaining atoms, owned and ghost
 
     for (j = i+1; j < nall; j++) {
       if (includegroup && !(mask[j] & bitmask)) continue;
       if (exclude && exclusion(i,j,type[i],type[j],mask,molecule)) continue;
 
       delx = xtmp - x[j][0];
       dely = ytmp - x[j][1];
       delz = ztmp - x[j][2];
       rsq = delx*delx + dely*dely + delz*delz;
       radsum = radi + radius[j];
       cutsq = (radsum+skin) * (radsum+skin);
 
       if (rsq <= cutsq) {
         neighptr[n] = j;
 
         if (fix_history) {
           if (rsq < radsum*radsum) {
             for (m = 0; m < npartner[i]; m++)
               if (partner[i][m] == tag[j]) break;
             if (m < npartner[i]) {
               touchptr[n] = 1;
               shearptr[nn++] = shearpartner[i][m][0];
               shearptr[nn++] = shearpartner[i][m][1];
               shearptr[nn++] = shearpartner[i][m][2];
             } else {
               touchptr[n] = 0;
               shearptr[nn++] = 0.0;
               shearptr[nn++] = 0.0;
               shearptr[nn++] = 0.0;
             }
           } else {
             touchptr[n] = 0;
             shearptr[nn++] = 0.0;
             shearptr[nn++] = 0.0;
             shearptr[nn++] = 0.0;
           }
         }
 
         n++;
       }
     }
 
     ilist[inum++] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
+    ipage->vgot(n);
+    if (ipage->status())
+      error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
+
     if (fix_history) {
       firsttouch[i] = touchptr;
       firstshear[i] = shearptr;
+      ipage_touch->vgot(n);
+      dpage_shear->vgot(nn);
     }
-    npnt += n;
-    if (n > oneatom)
-      error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
 
   list->inum = inum;
 }
 
 /* ----------------------------------------------------------------------
    granular particles
    N^2 / 2 search for neighbor pairs with full Newton's 3rd law
    no shear history is allowed for this option
    pair added to list if atoms i and j are both owned and i < j
    if j is ghost only me or other proc adds pair
    decision based on itag,jtag tests
 ------------------------------------------------------------------------- */
 
 void Neighbor::granular_nsq_newton(NeighList *list)
 {
   int i,j,n,itag,jtag,bitmask;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   double radi,radsum,cutsq;
   int *neighptr;
 
   double **x = atom->x;
   double *radius = atom->radius;
   int *tag = atom->tag;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int nlocal = atom->nlocal;
   int nall = nlocal + atom->nghost;
   if (includegroup) {
     nlocal = atom->nfirst;
     bitmask = group->bitmask[includegroup];
   }
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
-  int **pages = list->pages;
+  MyPage<int> *ipage = list->ipage;
 
   int inum = 0;
-  int npage = 0;
-  int npnt = 0;
+  ipage->reset();
 
   for (i = 0; i < nlocal; i++) {
-
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage++;
-      if (npage == list->maxpage) pages = list->add_pages();
-    }
-
     n = 0;
-    neighptr = &pages[npage][npnt];
+    neighptr = ipage->vget();
 
     itag = tag[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
     radi = radius[i];
 
     // loop over remaining atoms, owned and ghost
 
     for (j = i+1; j < nall; j++) {
       if (includegroup && !(mask[j] & bitmask)) continue;
 
       if (j >= nlocal) {
         jtag = tag[j];
         if (itag > jtag) {
           if ((itag+jtag) % 2 == 0) continue;
         } else if (itag < jtag) {
           if ((itag+jtag) % 2 == 1) continue;
         } else {
           if (x[j][2] < ztmp) continue;
           if (x[j][2] == ztmp) {
             if (x[j][1] < ytmp) continue;
             if (x[j][1] == ytmp && x[j][0] < xtmp) continue;
           }
         }
       }
 
       if (exclude && exclusion(i,j,type[i],type[j],mask,molecule)) continue;
 
       delx = xtmp - x[j][0];
       dely = ytmp - x[j][1];
       delz = ztmp - x[j][2];
       rsq = delx*delx + dely*dely + delz*delz;
       radsum = radi + radius[j];
       cutsq = (radsum+skin) * (radsum+skin);
 
       if (rsq <= cutsq) neighptr[n++] = j;
     }
 
     ilist[inum++] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage->vgot(n);
+    if (ipage->status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
 
   list->inum = inum;
 }
 
 /* ----------------------------------------------------------------------
    granular particles
    binned neighbor list construction with partial Newton's 3rd law
    shear history must be accounted for when a neighbor pair is added
    each owned atom i checks own bin and surrounding bins in non-Newton stencil
    pair stored once if i,j are both owned and i < j
    pair stored by me if j is ghost (also stored by proc owning j)
 ------------------------------------------------------------------------- */
 
 void Neighbor::granular_bin_no_newton(NeighList *list)
 {
   int i,j,k,m,n,nn,ibin;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   double radi,radsum,cutsq;
   int *neighptr,*touchptr;
   double *shearptr;
 
   NeighList *listgranhistory;
   int *npartner,**partner;
-  double ***shearpartner;
+  double (**shearpartner)[3];
   int **firsttouch;
   double **firstshear;
-  int **pages_touch;
-  double **pages_shear;
+  MyPage<int> *ipage_touch;
+  MyPage<double> *dpage_shear;
 
   // bin local & ghost atoms
 
   bin_atoms();
 
   // loop over each atom, storing neighbors
 
   double **x = atom->x;
   double *radius = atom->radius;
   int *tag = atom->tag;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int nlocal = atom->nlocal;
   if (includegroup) nlocal = atom->nfirst;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
-  int **pages = list->pages;
   int nstencil = list->nstencil;
   int *stencil = list->stencil;
+  MyPage<int> *ipage = list->ipage;
 
   FixShearHistory *fix_history = list->fix_history;
   if (fix_history) {
     npartner = fix_history->npartner;
     partner = fix_history->partner;
     shearpartner = fix_history->shearpartner;
     listgranhistory = list->listgranhistory;
     firsttouch = listgranhistory->firstneigh;
     firstshear = listgranhistory->firstdouble;
-    pages_touch = listgranhistory->pages;
-    pages_shear = listgranhistory->dpages;
+    ipage_touch = listgranhistory->ipage;
+    dpage_shear = listgranhistory->dpage;
   }
 
   int inum = 0;
-  int npage = 0;
-  int npnt = 0;
+  ipage->reset();
+  if (fix_history) {
+    ipage_touch->reset();
+    dpage_shear->reset();
+  }
 
   for (i = 0; i < nlocal; i++) {
-
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage++;
-      if (npage == list->maxpage) {
-        pages = list->add_pages();
-        if (fix_history) {
-          pages_touch = listgranhistory->add_pages();
-          pages_shear = listgranhistory->dpages;
-        }
-      }
-    }
-
     n = 0;
-    neighptr = &pages[npage][npnt];
+    neighptr = ipage->vget();
     if (fix_history) {
       nn = 0;
-      touchptr = &pages_touch[npage][npnt];
-      shearptr = &pages_shear[npage][3*npnt];
+      touchptr = ipage_touch->vget();
+      shearptr = dpage_shear->vget();
     }
 
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
     radi = radius[i];
     ibin = coord2bin(x[i]);
 
     // loop over all atoms in surrounding bins in stencil including self
     // only store pair if i < j
     // stores own/own pairs only once
     // stores own/ghost pairs on both procs
 
     for (k = 0; k < nstencil; k++) {
       for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
         if (j <= i) continue;
         if (exclude && exclusion(i,j,type[i],type[j],mask,molecule)) continue;
 
         delx = xtmp - x[j][0];
         dely = ytmp - x[j][1];
         delz = ztmp - x[j][2];
         rsq = delx*delx + dely*dely + delz*delz;
         radsum = radi + radius[j];
         cutsq = (radsum+skin) * (radsum+skin);
 
         if (rsq <= cutsq) {
           neighptr[n] = j;
 
           if (fix_history) {
             if (rsq < radsum*radsum) {
               for (m = 0; m < npartner[i]; m++)
                 if (partner[i][m] == tag[j]) break;
               if (m < npartner[i]) {
                 touchptr[n] = 1;
                 shearptr[nn++] = shearpartner[i][m][0];
                 shearptr[nn++] = shearpartner[i][m][1];
                 shearptr[nn++] = shearpartner[i][m][2];
               } else {
                 touchptr[n] = 0;
                 shearptr[nn++] = 0.0;
                 shearptr[nn++] = 0.0;
                 shearptr[nn++] = 0.0;
               }
             } else {
               touchptr[n] = 0;
               shearptr[nn++] = 0.0;
               shearptr[nn++] = 0.0;
               shearptr[nn++] = 0.0;
             }
           }
 
           n++;
         }
       }
     }
 
     ilist[inum++] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
+    ipage->vgot(n);
+    if (ipage->status())
+      error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
+
     if (fix_history) {
       firsttouch[i] = touchptr;
       firstshear[i] = shearptr;
+      ipage_touch->vgot(n);
+      dpage_shear->vgot(nn);
     }
-    npnt += n;
-    if (n > oneatom)
-      error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
 
   list->inum = inum;
 }
 
 /* ----------------------------------------------------------------------
    granular particles
    binned neighbor list construction with full Newton's 3rd law
    no shear history is allowed for this option
    each owned atom i checks its own bin and other bins in Newton stencil
    every pair stored exactly once by some processor
 ------------------------------------------------------------------------- */
 
 void Neighbor::granular_bin_newton(NeighList *list)
 {
   int i,j,k,n,ibin;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   double radi,radsum,cutsq;
   int *neighptr;
 
   // bin local & ghost atoms
 
   bin_atoms();
 
   // loop over each atom, storing neighbors
 
   double **x = atom->x;
   double *radius = atom->radius;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int nlocal = atom->nlocal;
   if (includegroup) nlocal = atom->nfirst;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
-  int **pages = list->pages;
   int nstencil = list->nstencil;
   int *stencil = list->stencil;
+  MyPage<int> *ipage = list->ipage;
 
   int inum = 0;
-  int npage = 0;
-  int npnt = 0;
+  ipage->reset();
 
   for (i = 0; i < nlocal; i++) {
-
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage++;
-      if (npage == list->maxpage) pages = list->add_pages();
-    }
-
     n = 0;
-    neighptr = &pages[npage][npnt];
+    neighptr = ipage->vget();
 
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
     radi = radius[i];
 
     // loop over rest of atoms in i's bin, ghosts are at end of linked list
     // if j is owned atom, store it, since j is beyond i in linked list
     // if j is ghost, only store if j coords are "above and to the right" of i
 
     for (j = bins[i]; j >= 0; j = bins[j]) {
       if (j >= nlocal) {
         if (x[j][2] < ztmp) continue;
         if (x[j][2] == ztmp) {
           if (x[j][1] < ytmp) continue;
           if (x[j][1] == ytmp && x[j][0] < xtmp) continue;
         }
       }
 
       if (exclude && exclusion(i,j,type[i],type[j],mask,molecule)) continue;
 
       delx = xtmp - x[j][0];
       dely = ytmp - x[j][1];
       delz = ztmp - x[j][2];
       rsq = delx*delx + dely*dely + delz*delz;
       radsum = radi + radius[j];
       cutsq = (radsum+skin) * (radsum+skin);
 
       if (rsq <= cutsq) neighptr[n++] = j;
     }
 
     // loop over all atoms in other bins in stencil, store every pair
 
     ibin = coord2bin(x[i]);
     for (k = 0; k < nstencil; k++) {
       for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
         if (exclude && exclusion(i,j,type[i],type[j],mask,molecule)) continue;
 
         delx = xtmp - x[j][0];
         dely = ytmp - x[j][1];
         delz = ztmp - x[j][2];
         rsq = delx*delx + dely*dely + delz*delz;
         radsum = radi + radius[j];
         cutsq = (radsum+skin) * (radsum+skin);
 
         if (rsq <= cutsq) neighptr[n++] = j;
       }
     }
 
     ilist[inum++] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage->vgot(n);
+    if (ipage->status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
 
   list->inum = inum;
 }
 
 /* ----------------------------------------------------------------------
    granular particles
    binned neighbor list construction with Newton's 3rd law for triclinic
    no shear history is allowed for this option
    each owned atom i checks its own bin and other bins in triclinic stencil
    every pair stored exactly once by some processor
 ------------------------------------------------------------------------- */
 
 void Neighbor::granular_bin_newton_tri(NeighList *list)
 {
   int i,j,k,n,ibin;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   double radi,radsum,cutsq;
   int *neighptr;
 
   // bin local & ghost atoms
 
   bin_atoms();
 
   // loop over each atom, storing neighbors
 
   double **x = atom->x;
   double *radius = atom->radius;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int nlocal = atom->nlocal;
   if (includegroup) nlocal = atom->nfirst;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
-  int **pages = list->pages;
   int nstencil = list->nstencil;
   int *stencil = list->stencil;
+  MyPage<int> *ipage = list->ipage;
 
   int inum = 0;
-  int npage = 0;
-  int npnt = 0;
+  ipage->reset();
 
   for (i = 0; i < nlocal; i++) {
-
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage++;
-      if (npage == list->maxpage) pages = list->add_pages();
-    }
-
     n = 0;
-    neighptr = &pages[npage][npnt];
+    neighptr = ipage->vget();
 
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
     radi = radius[i];
 
     // loop over all atoms in bins in stencil
     // pairs for atoms j "below" i are excluded
     // below = lower z or (equal z and lower y) or (equal zy and lower x)
     //         (equal zyx and j <= i)
     // latter excludes self-self interaction but allows superposed atoms
 
     ibin = coord2bin(x[i]);
     for (k = 0; k < nstencil; k++) {
       for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
         if (x[j][2] < ztmp) continue;
         if (x[j][2] == ztmp) {
           if (x[j][1] < ytmp) continue;
           if (x[j][1] == ytmp) {
             if (x[j][0] < xtmp) continue;
             if (x[j][0] == xtmp && j <= i) continue;
           }
         }
 
         if (exclude && exclusion(i,j,type[i],type[j],mask,molecule)) continue;
 
         delx = xtmp - x[j][0];
         dely = ytmp - x[j][1];
         delz = ztmp - x[j][2];
         rsq = delx*delx + dely*dely + delz*delz;
         radsum = radi + radius[j];
         cutsq = (radsum+skin) * (radsum+skin);
 
         if (rsq <= cutsq) neighptr[n++] = j;
       }
     }
 
     ilist[inum++] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage->vgot(n);
+    if (ipage->status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
 
   list->inum = inum;
 }
diff --git a/src/neigh_half_bin.cpp b/src/neigh_half_bin.cpp
index 9d89274ab..ef55cb5ba 100644
--- a/src/neigh_half_bin.cpp
+++ b/src/neigh_half_bin.cpp
@@ -1,487 +1,456 @@
 /* ----------------------------------------------------------------------
    LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
    http://lammps.sandia.gov, Sandia National Laboratories
    Steve Plimpton, sjplimp@sandia.gov
 
    Copyright (2003) Sandia Corporation.  Under the terms of Contract
    DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
    certain rights in this software.  This software is distributed under
    the GNU General Public License.
 
    See the README file in the top-level LAMMPS directory.
 ------------------------------------------------------------------------- */
 
 #include "neighbor.h"
 #include "neigh_list.h"
 #include "atom.h"
 #include "domain.h"
+#include "my_page.h"
 #include "error.h"
 
 using namespace LAMMPS_NS;
 
 /* ----------------------------------------------------------------------
    binned neighbor list construction with partial Newton's 3rd law
    each owned atom i checks own bin and other bins in stencil
    pair stored once if i,j are both owned and i < j
    pair stored by me if j is ghost (also stored by proc owning j)
 ------------------------------------------------------------------------- */
 
 void Neighbor::half_bin_no_newton(NeighList *list)
 {
   int i,j,k,n,itype,jtype,ibin,which;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int *neighptr;
 
   // bin local & ghost atoms
 
   bin_atoms();
 
   // loop over each atom, storing neighbors
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int nlocal = atom->nlocal;
   if (includegroup) nlocal = atom->nfirst;
   int molecular = atom->molecular;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
-  int **pages = list->pages;
   int nstencil = list->nstencil;
   int *stencil = list->stencil;
+  MyPage<int> *ipage = list->ipage;
 
   int inum = 0;
-  int npage = 0;
-  int npnt = 0;
+  ipage->reset();
 
   for (i = 0; i < nlocal; i++) {
-
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage++;
-      if (npage == list->maxpage) pages = list->add_pages();
-    }
-
-    neighptr = &pages[npage][npnt];
     n = 0;
+    neighptr = ipage->vget();
 
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over all atoms in other bins in stencil including self
     // only store pair if i < j
     // stores own/own pairs only once
     // stores own/ghost pairs on both procs
 
     ibin = coord2bin(x[i]);
 
     for (k = 0; k < nstencil; k++) {
       for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
         if (j <= i) continue;
 
         jtype = type[j];
         if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
         delx = xtmp - x[j][0];
         dely = ytmp - x[j][1];
         delz = ztmp - x[j][2];
         rsq = delx*delx + dely*dely + delz*delz;
 
         if (rsq <= cutneighsq[itype][jtype]) {
           if (molecular) {
             which = find_special(special[i],nspecial[i],tag[j]);
             if (which == 0) neighptr[n++] = j;
             else if (domain->minimum_image_check(delx,dely,delz))
               neighptr[n++] = j;
             else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
           } else neighptr[n++] = j;
         }
       }
     }
 
     ilist[inum++] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage->vgot(n);
+    if (ipage->status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
 
   list->inum = inum;
 }
 
 /* ----------------------------------------------------------------------
    binned neighbor list construction with partial Newton's 3rd law
    include neighbors of ghost atoms, but no "special neighbors" for ghosts
    owned and ghost atoms check own bin and other bins in stencil
    pair stored once if i,j are both owned and i < j
    pair stored by me if i owned and j ghost (also stored by proc owning j)
    pair stored once if i,j are both ghost and i < j
 ------------------------------------------------------------------------- */
 
 void Neighbor::half_bin_no_newton_ghost(NeighList *list)
 {
   int i,j,k,n,itype,jtype,ibin,which;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int xbin,ybin,zbin,xbin2,ybin2,zbin2;
   int *neighptr;
 
   // bin local & ghost atoms
 
   bin_atoms();
 
   // loop over each atom, storing neighbors
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int nlocal = atom->nlocal;
   int nall = nlocal + atom->nghost;
   int molecular = atom->molecular;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
-  int **pages = list->pages;
   int nstencil = list->nstencil;
   int *stencil = list->stencil;
   int **stencilxyz = list->stencilxyz;
+  MyPage<int> *ipage = list->ipage;
 
   int inum = 0;
-  int npage = 0;
-  int npnt = 0;
+  ipage->reset();
 
   for (i = 0; i < nall; i++) {
-
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage++;
-      if (npage == list->maxpage) pages = list->add_pages();
-    }
-
-    neighptr = &pages[npage][npnt];
     n = 0;
+    neighptr = ipage->vget();
 
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over all atoms in other bins in stencil including self
     // when i is a ghost atom, must check if stencil bin is out of bounds
     // only store pair if i < j
     // stores own/own pairs only once
     // stores own/ghost pairs with owned atom only, on both procs
     // stores ghost/ghost pairs only once
     // no molecular test when i = ghost atom
 
     if (i < nlocal) {
       ibin = coord2bin(x[i]);
 
       for (k = 0; k < nstencil; k++) {
         for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
           if (j <= i) continue;
 
           jtype = type[j];
           if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
           delx = xtmp - x[j][0];
           dely = ytmp - x[j][1];
           delz = ztmp - x[j][2];
           rsq = delx*delx + dely*dely + delz*delz;
 
           if (rsq <= cutneighsq[itype][jtype]) {
             if (molecular) {
               which = find_special(special[i],nspecial[i],tag[j]);
               if (which == 0) neighptr[n++] = j;
               else if (domain->minimum_image_check(delx,dely,delz))
                 neighptr[n++] = j;
               else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
             } else neighptr[n++] = j;
           }
         }
       }
 
     } else {
       ibin = coord2bin(x[i],xbin,ybin,zbin);
       for (k = 0; k < nstencil; k++) {
         xbin2 = xbin + stencilxyz[k][0];
         ybin2 = ybin + stencilxyz[k][1];
         zbin2 = zbin + stencilxyz[k][2];
         if (xbin2 < 0 || xbin2 >= mbinx ||
             ybin2 < 0 || ybin2 >= mbiny ||
             zbin2 < 0 || zbin2 >= mbinz) continue;
         for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
           if (j <= i) continue;
 
           jtype = type[j];
           if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
           delx = xtmp - x[j][0];
           dely = ytmp - x[j][1];
           delz = ztmp - x[j][2];
           rsq = delx*delx + dely*dely + delz*delz;
 
           if (rsq <= cutneighghostsq[itype][jtype]) neighptr[n++] = j;
         }
       }
     }
 
     ilist[inum++] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage->vgot(n);
+    if (ipage->status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
 
   list->inum = atom->nlocal;
   list->gnum = inum - atom->nlocal;
 }
 
 /* ----------------------------------------------------------------------
    binned neighbor list construction with full Newton's 3rd law
    each owned atom i checks its own bin and other bins in Newton stencil
    every pair stored exactly once by some processor
 ------------------------------------------------------------------------- */
 
 void Neighbor::half_bin_newton(NeighList *list)
 {
   int i,j,k,n,itype,jtype,ibin,which;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int *neighptr;
 
   // bin local & ghost atoms
 
   bin_atoms();
 
   // loop over each atom, storing neighbors
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int nlocal = atom->nlocal;
   if (includegroup) nlocal = atom->nfirst;
   int molecular = atom->molecular;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
-  int **pages = list->pages;
   int nstencil = list->nstencil;
   int *stencil = list->stencil;
+  MyPage<int> *ipage = list->ipage;
 
   int inum = 0;
-  int npage = 0;
-  int npnt = 0;
+  ipage->reset();
 
   for (i = 0; i < nlocal; i++) {
-
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage++;
-      if (npage == list->maxpage) pages = list->add_pages();
-    }
-
-    neighptr = &pages[npage][npnt];
     n = 0;
+    neighptr = ipage->vget();
 
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over rest of atoms in i's bin, ghosts are at end of linked list
     // if j is owned atom, store it, since j is beyond i in linked list
     // if j is ghost, only store if j coords are "above and to the right" of i
 
     for (j = bins[i]; j >= 0; j = bins[j]) {
       if (j >= nlocal) {
         if (x[j][2] < ztmp) continue;
         if (x[j][2] == ztmp) {
           if (x[j][1] < ytmp) continue;
           if (x[j][1] == ytmp && x[j][0] < xtmp) continue;
         }
       }
 
       jtype = type[j];
       if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
       delx = xtmp - x[j][0];
       dely = ytmp - x[j][1];
       delz = ztmp - x[j][2];
       rsq = delx*delx + dely*dely + delz*delz;
 
       if (rsq <= cutneighsq[itype][jtype]) {
         if (molecular) {
           which = find_special(special[i],nspecial[i],tag[j]);
           if (which == 0) neighptr[n++] = j;
           else if (domain->minimum_image_check(delx,dely,delz))
             neighptr[n++] = j;
           else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
           // OLD: if (which >= 0) neighptr[n++] = j ^ (which << SBBITS);
         } else neighptr[n++] = j;
       }
     }
 
     // loop over all atoms in other bins in stencil, store every pair
 
     ibin = coord2bin(x[i]);
     for (k = 0; k < nstencil; k++) {
       for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
         jtype = type[j];
         if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
         delx = xtmp - x[j][0];
         dely = ytmp - x[j][1];
         delz = ztmp - x[j][2];
         rsq = delx*delx + dely*dely + delz*delz;
 
         if (rsq <= cutneighsq[itype][jtype]) {
           if (molecular) {
             which = find_special(special[i],nspecial[i],tag[j]);
             if (which == 0) neighptr[n++] = j;
             else if (domain->minimum_image_check(delx,dely,delz))
               neighptr[n++] = j;
             else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
             // OLD: if (which >= 0) neighptr[n++] = j ^ (which << SBBITS);
           } else neighptr[n++] = j;
         }
       }
     }
 
     ilist[inum++] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage->vgot(n);
+    if (ipage->status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
 
   list->inum = inum;
 }
 
 /* ----------------------------------------------------------------------
    binned neighbor list construction with Newton's 3rd law for triclinic
    each owned atom i checks its own bin and other bins in triclinic stencil
    every pair stored exactly once by some processor
 ------------------------------------------------------------------------- */
 
 void Neighbor::half_bin_newton_tri(NeighList *list)
 {
   int i,j,k,n,itype,jtype,ibin,which;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int *neighptr;
 
   // bin local & ghost atoms
 
   bin_atoms();
 
   // loop over each atom, storing neighbors
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int nlocal = atom->nlocal;
   if (includegroup) nlocal = atom->nfirst;
   int molecular = atom->molecular;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
-  int **pages = list->pages;
   int nstencil = list->nstencil;
   int *stencil = list->stencil;
+  MyPage<int> *ipage = list->ipage;
 
   int inum = 0;
-  int npage = 0;
-  int npnt = 0;
+  ipage->reset();
 
   for (i = 0; i < nlocal; i++) {
-
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage++;
-      if (npage == list->maxpage) pages = list->add_pages();
-    }
-
-    neighptr = &pages[npage][npnt];
     n = 0;
+    neighptr = ipage->vget();
 
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over all atoms in bins in stencil
     // pairs for atoms j "below" i are excluded
     // below = lower z or (equal z and lower y) or (equal zy and lower x)
     //         (equal zyx and j <= i)
     // latter excludes self-self interaction but allows superposed atoms
 
     ibin = coord2bin(x[i]);
     for (k = 0; k < nstencil; k++) {
       for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
         if (x[j][2] < ztmp) continue;
         if (x[j][2] == ztmp) {
           if (x[j][1] < ytmp) continue;
           if (x[j][1] == ytmp) {
             if (x[j][0] < xtmp) continue;
             if (x[j][0] == xtmp && j <= i) continue;
           }
         }
 
         jtype = type[j];
         if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
         delx = xtmp - x[j][0];
         dely = ytmp - x[j][1];
         delz = ztmp - x[j][2];
         rsq = delx*delx + dely*dely + delz*delz;
 
         if (rsq <= cutneighsq[itype][jtype]) {
           if (molecular) {
             which = find_special(special[i],nspecial[i],tag[j]);
             if (which == 0) neighptr[n++] = j;
             else if (domain->minimum_image_check(delx,dely,delz))
               neighptr[n++] = j;
             else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
           } else neighptr[n++] = j;
         }
       }
     }
 
     ilist[inum++] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage->vgot(n);
+    if (ipage->status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
 
   list->inum = inum;
 }
diff --git a/src/neigh_half_multi.cpp b/src/neigh_half_multi.cpp
index bee0bfffc..46a76be6d 100644
--- a/src/neigh_half_multi.cpp
+++ b/src/neigh_half_multi.cpp
@@ -1,379 +1,356 @@
 /* ----------------------------------------------------------------------
    LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
    http://lammps.sandia.gov, Sandia National Laboratories
    Steve Plimpton, sjplimp@sandia.gov
 
    Copyright (2003) Sandia Corporation.  Under the terms of Contract
    DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
    certain rights in this software.  This software is distributed under
    the GNU General Public License.
 
    See the README file in the top-level LAMMPS directory.
 ------------------------------------------------------------------------- */
 
 #include "neighbor.h"
 #include "neigh_list.h"
 #include "atom.h"
 #include "domain.h"
+#include "my_page.h"
 #include "error.h"
 
 using namespace LAMMPS_NS;
 
 /* ----------------------------------------------------------------------
    binned neighbor list construction with partial Newton's 3rd law
    each owned atom i checks own bin and other bins in stencil
    multi-type stencil is itype dependent and is distance checked
    pair stored once if i,j are both owned and i < j
    pair stored by me if j is ghost (also stored by proc owning j)
 ------------------------------------------------------------------------- */
 
 void Neighbor::half_multi_no_newton(NeighList *list)
 {
   int i,j,k,n,itype,jtype,ibin,which,ns;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int *neighptr,*s;
   double *cutsq,*distsq;
 
   // bin local & ghost atoms
 
   bin_atoms();
 
   // loop over each atom, storing neighbors
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int nlocal = atom->nlocal;
   int molecular = atom->molecular;
   if (includegroup) nlocal = atom->nfirst;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
-  int **pages = list->pages;
   int *nstencil_multi = list->nstencil_multi;
   int **stencil_multi = list->stencil_multi;
   double **distsq_multi = list->distsq_multi;
+  MyPage<int> *ipage = list->ipage;
 
   int inum = 0;
-  int npage = 0;
-  int npnt = 0;
+  ipage->reset();
 
   for (i = 0; i < nlocal; i++) {
-
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage++;
-      if (npage == list->maxpage) pages = list->add_pages();
-    }
-
-    neighptr = &pages[npage][npnt];
     n = 0;
+    neighptr = ipage->vget();
 
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over all atoms in other bins in stencil including self
     // only store pair if i < j
     // skip if i,j neighbor cutoff is less than bin distance
     // stores own/own pairs only once
     // stores own/ghost pairs on both procs
 
     ibin = coord2bin(x[i]);
     s = stencil_multi[itype];
     distsq = distsq_multi[itype];
     cutsq = cutneighsq[itype];
     ns = nstencil_multi[itype];
     for (k = 0; k < ns; k++) {
       for (j = binhead[ibin+s[k]]; j >= 0; j = bins[j]) {
         if (j <= i) continue;
         jtype = type[j];
         if (cutsq[jtype] < distsq[k]) continue;
 
         if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
         delx = xtmp - x[j][0];
         dely = ytmp - x[j][1];
         delz = ztmp - x[j][2];
         rsq = delx*delx + dely*dely + delz*delz;
 
         if (rsq <= cutneighsq[itype][jtype]) {
           if (molecular) {
             which = find_special(special[i],nspecial[i],tag[j]);
             if (which == 0) neighptr[n++] = j;
             else if (domain->minimum_image_check(delx,dely,delz))
               neighptr[n++] = j;
             else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
           } else neighptr[n++] = j;
         }
       }
     }
 
     ilist[inum++] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage->vgot(n);
+    if (ipage->status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
 
   list->inum = inum;
 }
 
 /* ----------------------------------------------------------------------
    binned neighbor list construction with full Newton's 3rd law
    each owned atom i checks its own bin and other bins in Newton stencil
    multi-type stencil is itype dependent and is distance checked
    every pair stored exactly once by some processor
 ------------------------------------------------------------------------- */
 
 void Neighbor::half_multi_newton(NeighList *list)
 {
   int i,j,k,n,itype,jtype,ibin,which,ns;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int *neighptr,*s;
   double *cutsq,*distsq;
 
   // bin local & ghost atoms
 
   bin_atoms();
 
   // loop over each atom, storing neighbors
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int nlocal = atom->nlocal;
   int molecular = atom->molecular;
   if (includegroup) nlocal = atom->nfirst;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
-  int **pages = list->pages;
   int *nstencil_multi = list->nstencil_multi;
   int **stencil_multi = list->stencil_multi;
   double **distsq_multi = list->distsq_multi;
+  MyPage<int> *ipage = list->ipage;
 
   int inum = 0;
-  int npage = 0;
-  int npnt = 0;
+  ipage->reset();
 
   for (i = 0; i < nlocal; i++) {
-
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage++;
-      if (npage == list->maxpage) pages = list->add_pages();
-    }
-
-    neighptr = &pages[npage][npnt];
     n = 0;
+    neighptr = ipage->vget();
 
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over rest of atoms in i's bin, ghosts are at end of linked list
     // if j is owned atom, store it, since j is beyond i in linked list
     // if j is ghost, only store if j coords are "above and to the right" of i
 
     for (j = bins[i]; j >= 0; j = bins[j]) {
       if (j >= nlocal) {
         if (x[j][2] < ztmp) continue;
         if (x[j][2] == ztmp) {
           if (x[j][1] < ytmp) continue;
           if (x[j][1] == ytmp && x[j][0] < xtmp) continue;
         }
       }
 
       jtype = type[j];
       if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
       delx = xtmp - x[j][0];
       dely = ytmp - x[j][1];
       delz = ztmp - x[j][2];
       rsq = delx*delx + dely*dely + delz*delz;
 
       if (rsq <= cutneighsq[itype][jtype]) {
         if (molecular) {
           which = find_special(special[i],nspecial[i],tag[j]);
           if (which == 0) neighptr[n++] = j;
           else if (domain->minimum_image_check(delx,dely,delz))
             neighptr[n++] = j;
           else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
         } else neighptr[n++] = j;
       }
     }
 
     // loop over all atoms in other bins in stencil, store every pair
     // skip if i,j neighbor cutoff is less than bin distance
 
     ibin = coord2bin(x[i]);
     s = stencil_multi[itype];
     distsq = distsq_multi[itype];
     cutsq = cutneighsq[itype];
     ns = nstencil_multi[itype];
     for (k = 0; k < ns; k++) {
       for (j = binhead[ibin+s[k]]; j >= 0; j = bins[j]) {
         jtype = type[j];
         if (cutsq[jtype] < distsq[k]) continue;
 
         if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
         delx = xtmp - x[j][0];
         dely = ytmp - x[j][1];
         delz = ztmp - x[j][2];
         rsq = delx*delx + dely*dely + delz*delz;
 
         if (rsq <= cutneighsq[itype][jtype]) {
           if (molecular) {
             which = find_special(special[i],nspecial[i],tag[j]);
             if (which == 0) neighptr[n++] = j;
             else if (domain->minimum_image_check(delx,dely,delz))
               neighptr[n++] = j;
             else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
           } else neighptr[n++] = j;
         }
       }
     }
 
     ilist[inum++] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage->vgot(n);
+    if (ipage->status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
 
   list->inum = inum;
 }
 
 /* ----------------------------------------------------------------------
    binned neighbor list construction with Newton's 3rd law for triclinic
    each owned atom i checks its own bin and other bins in triclinic stencil
    multi-type stencil is itype dependent and is distance checked
    every pair stored exactly once by some processor
 ------------------------------------------------------------------------- */
 
 void Neighbor::half_multi_newton_tri(NeighList *list)
 {
   int i,j,k,n,itype,jtype,ibin,which,ns;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int *neighptr,*s;
   double *cutsq,*distsq;
 
   // bin local & ghost atoms
 
   bin_atoms();
 
   // loop over each atom, storing neighbors
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int nlocal = atom->nlocal;
   int molecular = atom->molecular;
   if (includegroup) nlocal = atom->nfirst;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
-  int **pages = list->pages;
   int *nstencil_multi = list->nstencil_multi;
   int **stencil_multi = list->stencil_multi;
   double **distsq_multi = list->distsq_multi;
+  MyPage<int> *ipage = list->ipage;
 
   int inum = 0;
-  int npage = 0;
-  int npnt = 0;
+  ipage->reset();
 
   for (i = 0; i < nlocal; i++) {
-
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage++;
-      if (npage == list->maxpage) pages = list->add_pages();
-    }
-
-    neighptr = &pages[npage][npnt];
     n = 0;
+    neighptr = ipage->vget();
 
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over all atoms in bins, including self, in stencil
     // skip if i,j neighbor cutoff is less than bin distance
     // bins below self are excluded from stencil
     // pairs for atoms j "below" i are excluded
     // below = lower z or (equal z and lower y) or (equal zy and lower x)
     //         (equal zyx and j <= i)
     // latter excludes self-self interaction but allows superposed atoms
 
     ibin = coord2bin(x[i]);
     s = stencil_multi[itype];
     distsq = distsq_multi[itype];
     cutsq = cutneighsq[itype];
     ns = nstencil_multi[itype];
     for (k = 0; k < ns; k++) {
       for (j = binhead[ibin+s[k]]; j >= 0; j = bins[j]) {
         jtype = type[j];
         if (cutsq[jtype] < distsq[k]) continue;
         if (x[j][2] < ztmp) continue;
         if (x[j][2] == ztmp) {
           if (x[j][1] < ytmp) continue;
           if (x[j][1] == ytmp) {
             if (x[j][0] < xtmp) continue;
             if (x[j][0] == xtmp && j <= i) continue;
           }
         }
 
         if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
         delx = xtmp - x[j][0];
         dely = ytmp - x[j][1];
         delz = ztmp - x[j][2];
         rsq = delx*delx + dely*dely + delz*delz;
 
         if (rsq <= cutneighsq[itype][jtype]) {
           if (molecular) {
             which = find_special(special[i],nspecial[i],tag[j]);
             if (which == 0) neighptr[n++] = j;
             else if (domain->minimum_image_check(delx,dely,delz))
               neighptr[n++] = j;
             else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
           } else neighptr[n++] = j;
         }
       }
     }
 
     ilist[inum++] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage->vgot(n);
+    if (ipage->status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
 
   list->inum = inum;
 }
diff --git a/src/neigh_half_nsq.cpp b/src/neigh_half_nsq.cpp
index 7266df0eb..8446c9d98 100644
--- a/src/neigh_half_nsq.cpp
+++ b/src/neigh_half_nsq.cpp
@@ -1,331 +1,307 @@
 /* ----------------------------------------------------------------------
    LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
    http://lammps.sandia.gov, Sandia National Laboratories
    Steve Plimpton, sjplimp@sandia.gov
 
    Copyright (2003) Sandia Corporation.  Under the terms of Contract
    DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
    certain rights in this software.  This software is distributed under
    the GNU General Public License.
 
    See the README file in the top-level LAMMPS directory.
 ------------------------------------------------------------------------- */
 
 #include "neighbor.h"
 #include "neigh_list.h"
 #include "atom.h"
 #include "domain.h"
 #include "group.h"
 #include "error.h"
 
 using namespace LAMMPS_NS;
 
 /* ----------------------------------------------------------------------
    N^2 / 2 search for neighbor pairs with partial Newton's 3rd law
    pair stored once if i,j are both owned and i < j
    pair stored by me if j is ghost (also stored by proc owning j)
 ------------------------------------------------------------------------- */
 
 void Neighbor::half_nsq_no_newton(NeighList *list)
 {
   int i,j,n,itype,jtype,which,bitmask;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int *neighptr;
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int nlocal = atom->nlocal;
   int nall = nlocal + atom->nghost;
   int molecular = atom->molecular;
   if (includegroup) {
     nlocal = atom->nfirst;
     bitmask = group->bitmask[includegroup];
   }
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
-  int **pages = list->pages;
+  MyPage<int> *ipage = list->ipage;
 
   int inum = 0;
-  int npage = 0;
-  int npnt = 0;
+  ipage->reset();
 
   // loop over owned atoms, storing neighbors
 
   for (i = 0; i < nlocal; i++) {
-
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage++;
-      if (npage == list->maxpage) pages = list->add_pages();
-    }
-
-    neighptr = &pages[npage][npnt];
     n = 0;
+    neighptr = ipage->vget();
 
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over remaining atoms, owned and ghost
     // only store pair if i < j
 
     for (j = i+1; j < nall; j++) {
       if (includegroup && !(mask[j] & bitmask)) continue;
       jtype = type[j];
       if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
       delx = xtmp - x[j][0];
       dely = ytmp - x[j][1];
       delz = ztmp - x[j][2];
       rsq = delx*delx + dely*dely + delz*delz;
 
       if (rsq <= cutneighsq[itype][jtype]) {
         if (molecular) {
           which = find_special(special[i],nspecial[i],tag[j]);
           if (which == 0) neighptr[n++] = j;
           else if (domain->minimum_image_check(delx,dely,delz))
             neighptr[n++] = j;
           else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
         } else neighptr[n++] = j;
       }
     }
 
     ilist[inum++] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage->vgot(n);
+    if (ipage->status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
 
   list->inum = inum;
 }
 
 /* ----------------------------------------------------------------------
    N^2 / 2 search for neighbor pairs with partial Newton's 3rd law
    include neighbors of ghost atoms, but no "special neighbors" for ghosts
    pair stored once if i,j are both owned and i < j
    pair stored by me if i owned and j ghost (also stored by proc owning j)
    pair stored once if i,j are both ghost and i < j
 ------------------------------------------------------------------------- */
 
 void Neighbor::half_nsq_no_newton_ghost(NeighList *list)
 {
   int i,j,n,itype,jtype,which,bitmask;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int *neighptr;
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int nlocal = atom->nlocal;
   int nall = nlocal + atom->nghost;
   int molecular = atom->molecular;
   if (includegroup) {
     nlocal = atom->nfirst;
     bitmask = group->bitmask[includegroup];
   }
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
-  int **pages = list->pages;
+  MyPage<int> *ipage = list->ipage;
 
   int inum = 0;
-  int npage = 0;
-  int npnt = 0;
+  ipage->reset();
 
   // loop over owned & ghost atoms, storing neighbors
 
   for (i = 0; i < nall; i++) {
-
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage++;
-      if (npage == list->maxpage) pages = list->add_pages();
-    }
-
-    neighptr = &pages[npage][npnt];
     n = 0;
+    neighptr = ipage->vget();
 
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over remaining atoms, owned and ghost
     // only store pair if i < j
     // stores own/own pairs only once
     // stores own/ghost pairs with owned atom only, on both procs
     // stores ghost/ghost pairs only once
     // no molecular test when i = ghost atom
 
     if (i < nlocal) {
       for (j = i+1; j < nall; j++) {
         if (includegroup && !(mask[j] & bitmask)) continue;
         jtype = type[j];
         if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
         delx = xtmp - x[j][0];
         dely = ytmp - x[j][1];
         delz = ztmp - x[j][2];
         rsq = delx*delx + dely*dely + delz*delz;
 
         if (rsq <= cutneighsq[itype][jtype]) {
           if (molecular) {
             which = find_special(special[i],nspecial[i],tag[j]);
             if (which == 0) neighptr[n++] = j;
             else if (domain->minimum_image_check(delx,dely,delz))
               neighptr[n++] = j;
             else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
           } else neighptr[n++] = j;
         }
       }
 
     } else {
       for (j = i+1; j < nall; j++) {
         if (includegroup && !(mask[j] & bitmask)) continue;
         jtype = type[j];
         if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
         delx = xtmp - x[j][0];
         dely = ytmp - x[j][1];
         delz = ztmp - x[j][2];
         rsq = delx*delx + dely*dely + delz*delz;
 
         if (rsq <= cutneighsq[itype][jtype]) neighptr[n++] = j;
       }
     }
 
     ilist[inum++] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage->vgot(n);
+    if (ipage->status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
 
   list->inum = atom->nlocal;
   list->gnum = inum - atom->nlocal;
 }
 
 /* ----------------------------------------------------------------------
    N^2 / 2 search for neighbor pairs with full Newton's 3rd law
    every pair stored exactly once by some processor
    decision on ghost atoms based on itag,jtag tests
 ------------------------------------------------------------------------- */
 
 void Neighbor::half_nsq_newton(NeighList *list)
 {
   int i,j,n,itype,jtype,itag,jtag,which,bitmask;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int *neighptr;
 
   // loop over each atom, storing neighbors
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int nlocal = atom->nlocal;
   int nall = nlocal + atom->nghost;
   int molecular = atom->molecular;
   if (includegroup) {
     nlocal = atom->nfirst;
     bitmask = group->bitmask[includegroup];
   }
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
-  int **pages = list->pages;
+  MyPage<int> *ipage = list->ipage;
 
   int inum = 0;
-  int npage = 0;
-  int npnt = 0;
+  ipage->reset();
 
   for (i = 0; i < nlocal; i++) {
-
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage++;
-      if (npage == list->maxpage) pages = list->add_pages();
-    }
-
-    neighptr = &pages[npage][npnt];
     n = 0;
+    neighptr = ipage->vget();
 
     itag = tag[i];
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over remaining atoms, owned and ghost
     // itag = jtag is possible for long cutoffs that include images of self
 
     for (j = i+1; j < nall; j++) {
       if (includegroup && !(mask[j] & bitmask)) continue;
 
       if (j >= nlocal) {
         jtag = tag[j];
         if (itag > jtag) {
           if ((itag+jtag) % 2 == 0) continue;
         } else if (itag < jtag) {
           if ((itag+jtag) % 2 == 1) continue;
         } else {
           if (x[j][2] < ztmp) continue;
           if (x[j][2] == ztmp) {
             if (x[j][1] < ytmp) continue;
             if (x[j][1] == ytmp && x[j][0] < xtmp) continue;
           }
         }
       }
 
       jtype = type[j];
       if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
       delx = xtmp - x[j][0];
       dely = ytmp - x[j][1];
       delz = ztmp - x[j][2];
       rsq = delx*delx + dely*dely + delz*delz;
 
       if (rsq <= cutneighsq[itype][jtype]) {
         if (molecular) {
           which = find_special(special[i],nspecial[i],tag[j]);
           if (which == 0) neighptr[n++] = j;
           else if (domain->minimum_image_check(delx,dely,delz))
             neighptr[n++] = j;
           else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
         } else neighptr[n++] = j;
       }
     }
 
     ilist[inum++] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage->vgot(n);
+    if (ipage->status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
   }
 
   list->inum = inum;
 }
diff --git a/src/neigh_list.cpp b/src/neigh_list.cpp
index e294dcaf4..28b192db0 100644
--- a/src/neigh_list.cpp
+++ b/src/neigh_list.cpp
@@ -1,290 +1,289 @@
 /* ----------------------------------------------------------------------
    LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
    http://lammps.sandia.gov, Sandia National Laboratories
    Steve Plimpton, sjplimp@sandia.gov
 
    Copyright (2003) Sandia Corporation.  Under the terms of Contract
    DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
    certain rights in this software.  This software is distributed under
    the GNU General Public License.
 
    See the README file in the top-level LAMMPS directory.
 ------------------------------------------------------------------------- */
 
 #include "neigh_list.h"
 #include "atom.h"
 #include "comm.h"
 #include "update.h"
 #include "neighbor.h"
 #include "neigh_request.h"
+#include "my_page.h"
 #include "memory.h"
 #include "error.h"
 
 using namespace LAMMPS_NS;
 
 #define PGDELTA 1
 
 enum{NSQ,BIN,MULTI};     // also in neighbor.cpp
 
 /* ---------------------------------------------------------------------- */
 
-NeighList::NeighList(LAMMPS *lmp, int size) : Pointers(lmp)
+NeighList::NeighList(LAMMPS *lmp) :
+  Pointers(lmp)
 {
   maxatoms = 0;
-  pgsize = size;
 
   inum = gnum = 0;
   ilist = NULL;
   numneigh = NULL;
   firstneigh = NULL;
   firstdouble = NULL;
 
-  maxpage = 0;
-  pages = NULL;
-  dpages = NULL;
-  dnum = 0;
-
   iskip = NULL;
   ijskip = NULL;
 
   listgranhistory = NULL;
   fix_history = NULL;
 
   respamiddle = 0;
   listinner = NULL;
   listmiddle = NULL;
   listfull = NULL;
   listcopy = NULL;
   listskip = NULL;
 
   maxstencil = 0;
   stencil = NULL;
   stencilxyz = NULL;
 
   maxstencil_multi = 0;
   nstencil_multi = NULL;
   stencil_multi = NULL;
   distsq_multi = NULL;
+
+  ipage = NULL;
+  dpage = NULL;
 }
 
 /* ---------------------------------------------------------------------- */
 
 NeighList::~NeighList()
 {
   if (!listcopy) {
     memory->destroy(ilist);
     memory->destroy(numneigh);
     memory->sfree(firstneigh);
     memory->sfree(firstdouble);
 
-    for (int i = 0; i < maxpage; i++) memory->destroy(pages[i]);
-    memory->sfree(pages);
-    if (dnum) {
-      for (int i = 0; i < maxpage; i++) memory->destroy(dpages[i]);
-      memory->sfree(dpages);
-    }
+    delete[] ipage;
+    if (dnum) 
+      delete[] dpage;
   }
 
   delete [] iskip;
   memory->destroy(ijskip);
 
   if (maxstencil) memory->destroy(stencil);
   if (ghostflag) memory->destroy(stencilxyz);
 
   if (maxstencil_multi) {
     for (int i = 1; i <= atom->ntypes; i++) {
       memory->destroy(stencil_multi[i]);
       memory->destroy(distsq_multi[i]);
     }
     delete [] nstencil_multi;
     delete [] stencil_multi;
     delete [] distsq_multi;
   }
 }
 
+/* ---------------------------------------------------------------------- */
+
+void NeighList::setup_pages(int pgsize_caller, int oneatom_caller, 
+                            int dnum_caller)
+{
+  pgsize = pgsize_caller;
+  oneatom = oneatom_caller;
+  dnum = dnum_caller;
+
+  int nmypage = comm->nthreads;
+  ipage = new MyPage<int>[nmypage];
+  for (int i=0; i < nmypage; ++i)
+    ipage[i].init(oneatom,pgsize,PGDELTA);
+
+  if (dnum) {
+    dpage = new MyPage<double>[nmypage];
+    for (int i=0; i < nmypage; ++i)
+      dpage[i].init(dnum*oneatom,dnum*pgsize,PGDELTA);
+  }
+  else dpage = NULL;
+}
+
 /* ----------------------------------------------------------------------
    grow atom arrays to allow for nmax atoms
    triggered by more atoms on a processor
    caller knows if this list stores neighs of local atoms or local+ghost
 ------------------------------------------------------------------------- */
 
 void NeighList::grow(int nmax)
 {
   // skip if this list is already long enough to store nmax atoms
 
   if (nmax <= maxatoms) return;
   maxatoms = nmax;
 
   memory->destroy(ilist);
   memory->destroy(numneigh);
   memory->sfree(firstneigh);
   memory->sfree(firstdouble);
 
   memory->create(ilist,maxatoms,"neighlist:ilist");
   memory->create(numneigh,maxatoms,"neighlist:numneigh");
   firstneigh = (int **) memory->smalloc(maxatoms*sizeof(int *),
                                         "neighlist:firstneigh");
 
   if (dnum)
     firstdouble = (double **) memory->smalloc(maxatoms*sizeof(double *),
                                               "neighlist:firstdouble");
 }
 
 /* ----------------------------------------------------------------------
    insure stencils are large enough for smax bins
    style = BIN or MULTI
 ------------------------------------------------------------------------- */
 
 void NeighList::stencil_allocate(int smax, int style)
 {
   int i;
 
   if (style == BIN) {
     if (smax > maxstencil) {
       maxstencil = smax;
       memory->destroy(stencil);
       memory->create(stencil,maxstencil,"neighlist:stencil");
       if (ghostflag) {
         memory->destroy(stencilxyz);
         memory->create(stencilxyz,maxstencil,3,"neighlist:stencilxyz");
       }
     }
 
   } else {
     int n = atom->ntypes;
     if (maxstencil_multi == 0) {
       nstencil_multi = new int[n+1];
       stencil_multi = new int*[n+1];
       distsq_multi = new double*[n+1];
       for (i = 1; i <= n; i++) {
         nstencil_multi[i] = 0;
         stencil_multi[i] = NULL;
         distsq_multi[i] = NULL;
       }
     }
     if (smax > maxstencil_multi) {
       maxstencil_multi = smax;
       for (i = 1; i <= n; i++) {
         memory->destroy(stencil_multi[i]);
         memory->destroy(distsq_multi[i]);
         memory->create(stencil_multi[i],maxstencil_multi,
                        "neighlist:stencil_multi");
         memory->create(distsq_multi[i],maxstencil_multi,
                        "neighlist:distsq_multi");
       }
     }
   }
 }
 
-/* ----------------------------------------------------------------------
-   add PGDELTA pages to neighbor list
-------------------------------------------------------------------------- */
-
-int **NeighList::add_pages(int howmany)
-{
-  int toppage = maxpage;
-  maxpage += howmany*PGDELTA;
-
-  pages = (int **)
-    memory->srealloc(pages,maxpage*sizeof(int *),"neighlist:pages");
-  for (int i = toppage; i < maxpage; i++)
-    memory->create(pages[i],pgsize,"neighlist:pages[i]");
-
-  if (dnum) {
-    dpages = (double **)
-      memory->srealloc(dpages,maxpage*sizeof(double *),"neighlist:dpages");
-    for (int i = toppage; i < maxpage; i++)
-      memory->create(dpages[i],dnum*pgsize,"neighlist:dpages[i]");
-  }
-
-  return pages;
-}
-
 /* ----------------------------------------------------------------------
    copy skip info from request rq into list's iskip,ijskip
 ------------------------------------------------------------------------- */
 
 void NeighList::copy_skip_info(int *rq_iskip, int **rq_ijskip)
 {
   int ntypes = atom->ntypes;
   iskip = new int[ntypes+1];
   memory->create(ijskip,ntypes+1,ntypes+1,"neigh_list:ijskip");
   int i,j;
   for (i = 1; i <= ntypes; i++) iskip[i] = rq_iskip[i];
   for (i = 1; i <= ntypes; i++)
     for (j = 1; j <= ntypes; j++)
       ijskip[i][j] = rq_ijskip[i][j];
 }
 
 /* ----------------------------------------------------------------------
    print attributes of this list and associated request
 ------------------------------------------------------------------------- */
 
 void NeighList::print_attributes()
 {
   if (comm->me != 0) return;
 
   NeighRequest *rq = neighbor->requests[index];
 
   printf("Neighbor list/request %d:\n",index);
   printf("  %d = build flag\n",buildflag);
   printf("  %d = grow flag\n",growflag);
   printf("  %d = stencil flag\n",stencilflag);
   printf("  %d = ghost flag\n",ghostflag);
   printf("\n");
   printf("  %d = pair\n",rq->pair);
   printf("  %d = fix\n",rq->fix);
   printf("  %d = compute\n",rq->compute);
   printf("  %d = command\n",rq->command);
   printf("\n");
   printf("  %d = half\n",rq->half);
   printf("  %d = full\n",rq->full);
   printf("  %d = gran\n",rq->gran);
   printf("  %d = granhistory\n",rq->granhistory);
   printf("  %d = respainner\n",rq->respainner);
   printf("  %d = respamiddle\n",rq->respamiddle);
   printf("  %d = respaouter\n",rq->respaouter);
   printf("  %d = half_from_full\n",rq->half_from_full);
   printf("\n");
   printf("  %d = occasional\n",rq->occasional);
   printf("  %d = dnum\n",rq->dnum);
   printf("  %d = omp\n",rq->omp);
   printf("  %d = ghost\n",rq->ghost);
   printf("  %d = cudable\n",rq->cudable);
   printf("  %d = omp\n",rq->omp);
   printf("  %d = copy\n",rq->copy);
   printf("  %d = skip\n",rq->skip);
   printf("  %d = otherlist\n",rq->otherlist);
   printf("  %p = listskip\n",listskip);
   printf("\n");
 }
 
 /* ----------------------------------------------------------------------
    return # of bytes of allocated memory
    if growflag = 0, maxatoms & maxpage will also be 0
    if stencilflag = 0, maxstencil * maxstencil_multi will also be 0
 ------------------------------------------------------------------------- */
 
 bigint NeighList::memory_usage()
 {
   bigint bytes = 0;
   bytes += memory->usage(ilist,maxatoms);
   bytes += memory->usage(numneigh,maxatoms);
   bytes += maxatoms * sizeof(int *);
-  bytes += memory->usage(pages,maxpage,pgsize);
+
+  int nmypage = comm->nthreads;
+  for (int i=0; i < nmypage; ++i)
+    bytes += ipage[i].size();
 
   if (dnum) {
-    bytes += maxatoms * sizeof(double *);
-    bytes += memory->usage(dpages,maxpage,dnum*pgsize);
+    for (int i=0; i < nmypage; ++i) {
+      bytes += maxatoms * sizeof(double *);
+      bytes += dpage[i].size();
+    }
   }
 
   if (maxstencil) bytes += memory->usage(stencil,maxstencil);
   if (ghostflag) bytes += memory->usage(stencilxyz,maxstencil,3);
 
   if (maxstencil_multi) {
     bytes += memory->usage(stencil_multi,atom->ntypes,maxstencil_multi);
     bytes += memory->usage(distsq_multi,atom->ntypes,maxstencil_multi);
   }
 
   return bytes;
 }
diff --git a/src/neigh_list.h b/src/neigh_list.h
index 2ecf534cd..97528b3de 100644
--- a/src/neigh_list.h
+++ b/src/neigh_list.h
@@ -1,95 +1,96 @@
 /* -*- c++ -*- ----------------------------------------------------------
    LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
    http://lammps.sandia.gov, Sandia National Laboratories
    Steve Plimpton, sjplimp@sandia.gov
 
    Copyright (2003) Sandia Corporation.  Under the terms of Contract
    DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
    certain rights in this software.  This software is distributed under
    the GNU General Public License.
 
    See the README file in the top-level LAMMPS directory.
 ------------------------------------------------------------------------- */
 
 #ifndef LMP_NEIGH_LIST_H
 #define LMP_NEIGH_LIST_H
 
 #include "pointers.h"
+#include "my_page.h"
 
 namespace LAMMPS_NS {
 
 class NeighList : protected Pointers {
  public:
   int index;                       // index of which neigh list it is
                                    // needed when a class invokes it directly
                                    // also indexes the request it came from
 
   int buildflag;                   // 1 if pair_build invoked every reneigh
   int growflag;                    // 1 if stores atom-based arrays & pages
   int stencilflag;                 // 1 if stores stencil arrays
   int ghostflag;                   // 1 if it stores neighbors of ghosts
 
   // data structs to store neighbor pairs I,J and associated values
 
   int inum;                        // # of I atoms neighbors are stored for
   int gnum;                        // # of ghost atoms neighbors are stored for
   int *ilist;                      // local indices of I atoms
   int *numneigh;                   // # of J neighbors for each I atom
   int **firstneigh;                // ptr to 1st J int value of each I atom
   double **firstdouble;            // ptr to 1st J double value of each I atom
 
   int pgsize;                      // size of each page
-  int maxpage;                     // # of pages currently allocated
-  int **pages;                     // neighbor list pages for ints
-  double **dpages;                 // neighbor list pages for doubles
-  int dnum;                        // # of doubles for each pair (0 if none)
+  int oneatom;                     // max size for one atom
+  int dnum;                        // # of doubles per neighbor, 0 if none
+  MyPage<int> *ipage;              // pages of neighbor indices
+  MyPage<double> *dpage;           // pages of neighbor doubles, if dnum > 0
 
   // atom types to skip when building list
   // iskip,ijskip are just ptrs to corresponding request
 
   int *iskip;         // iskip[i] = 1 if atoms of type I are not in list
   int **ijskip;       // ijskip[i][j] = 1 if pairs of type I,J are not in list
 
   // settings and pointers for related neighbor lists and fixes
 
   NeighList *listgranhistory;          // point at history list
   class FixShearHistory *fix_history;  // fix that stores history info
 
   int respamiddle;              // 1 if this respaouter has middle list
   NeighList *listinner;         // me = respaouter, point to respainner
   NeighList *listmiddle;        // me = respaouter, point to respamiddle
   NeighList *listfull;          // me = half list, point to full I derive from
   NeighList *listcopy;          // me = copy list, point to list I copy from
   NeighList *listskip;          // me = skip list, point to list I skip from
 
   // stencils of bin indices for neighbor finding
 
   int maxstencil;                  // max size of stencil
   int nstencil;                    // # of bins in stencil
   int *stencil;                    // list of bin offsets
   int **stencilxyz;                // bin offsets in xyz dims
 
   int maxstencil_multi;            // max sizes of stencils
   int *nstencil_multi;             // # bins in each type-based multi stencil
   int **stencil_multi;             // list of bin offsets in each stencil
   double **distsq_multi;           // sq distances to bins in each stencil
 
   class CudaNeighList *cuda_list;  // CUDA neighbor list
 
-  NeighList(class LAMMPS *, int);
+  NeighList(class LAMMPS *);
   ~NeighList();
+  void setup_pages(int, int, int);      // setup page data structures
   void grow(int);                       // grow maxlocal
   void stencil_allocate(int, int);      // allocate stencil arrays
-  int **add_pages(int howmany=1);       // add pages to neigh list
   void copy_skip_info(int *, int **);   // copy skip info from a neigh request
   void print_attributes();              // debug routine
   int get_maxlocal() {return maxatoms;}
   bigint memory_usage();
 
  private:
   int maxatoms;                    // size of allocated atom arrays
 };
 
 }
 
 #endif
diff --git a/src/neigh_respa.cpp b/src/neigh_respa.cpp
index c152eba2b..8d1ea14ae 100644
--- a/src/neigh_respa.cpp
+++ b/src/neigh_respa.cpp
@@ -1,953 +1,834 @@
 /* ----------------------------------------------------------------------
    LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
    http://lammps.sandia.gov, Sandia National Laboratories
    Steve Plimpton, sjplimp@sandia.gov
 
    Copyright (2003) Sandia Corporation.  Under the terms of Contract
    DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
    certain rights in this software.  This software is distributed under
    the GNU General Public License.
 
    See the README file in the top-level LAMMPS directory.
 ------------------------------------------------------------------------- */
 
 #include "neighbor.h"
 #include "neigh_list.h"
 #include "atom.h"
 #include "domain.h"
 #include "group.h"
+#include "my_page.h"
 #include "error.h"
 
 using namespace LAMMPS_NS;
 
 /* ----------------------------------------------------------------------
    multiple respa lists
    N^2 / 2 search for neighbor pairs with partial Newton's 3rd law
    pair added to list if atoms i and j are both owned and i < j
    pair added if j is ghost (also stored by proc owning j)
 ------------------------------------------------------------------------- */
 
 void Neighbor::respa_nsq_no_newton(NeighList *list)
 {
   int i,j,n,itype,jtype,n_inner,n_middle,bitmask;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int *neighptr,*neighptr_inner,*neighptr_middle;
 
   // loop over each atom, storing neighbors
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int nlocal = atom->nlocal;
   int nall = nlocal + atom->nghost;
   int molecular = atom->molecular;
   if (includegroup) {
     nlocal = atom->nfirst;
     bitmask = group->bitmask[includegroup];
   }
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
-  int **pages = list->pages;
+  MyPage<int> *ipage = list->ipage;
 
   NeighList *listinner = list->listinner;
   int *ilist_inner = listinner->ilist;
   int *numneigh_inner = listinner->numneigh;
   int **firstneigh_inner = listinner->firstneigh;
-  int **pages_inner = listinner->pages;
+  MyPage<int> *ipage_inner = listinner->ipage;
 
   NeighList *listmiddle;
-  int *ilist_middle,*numneigh_middle,**firstneigh_middle,**pages_middle;
+  int *ilist_middle,*numneigh_middle,**firstneigh_middle;
+  MyPage<int> *ipage_middle;
   int respamiddle = list->respamiddle;
   if (respamiddle) {
     listmiddle = list->listmiddle;
     ilist_middle = listmiddle->ilist;
     numneigh_middle = listmiddle->numneigh;
     firstneigh_middle = listmiddle->firstneigh;
-    pages_middle = listmiddle->pages;
+    ipage_middle = listmiddle->ipage;
   }
 
   int inum = 0;
-  int npage = 0;
-  int npnt = 0;
-  int npage_inner = 0;
-  int npnt_inner = 0;
-  int npage_middle = 0;
-  int npnt_middle = 0;
-
   int which = 0;
   int minchange = 0;
+  ipage->reset();
+  ipage_inner->reset();
+  if (respamiddle) ipage_middle->reset();
 
   for (i = 0; i < nlocal; i++) {
-
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage++;
-      if (npage == list->maxpage) pages = list->add_pages();
-    }
-    neighptr = &pages[npage][npnt];
-    n = 0;
-
-    if (pgsize - npnt_inner < oneatom) {
-      npnt_inner = 0;
-      npage_inner++;
-      if (npage_inner == listinner->maxpage)
-        pages_inner = listinner->add_pages();
-    }
-    neighptr_inner = &pages_inner[npage_inner][npnt_inner];
-    n_inner = 0;
-
+    n = n_inner = 0;
+    neighptr = ipage->vget();
+    neighptr_inner = ipage_inner->vget();
     if (respamiddle) {
-      if (pgsize - npnt_middle < oneatom) {
-        npnt_middle = 0;
-        npage_middle++;
-        if (npage_middle == listmiddle->maxpage)
-          pages_middle = listmiddle->add_pages();
-      }
-      neighptr_middle = &pages_middle[npage_middle][npnt_middle];
       n_middle = 0;
+      neighptr_middle = ipage_middle->vget();
     }
 
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over remaining atoms, owned and ghost
 
     for (j = i+1; j < nall; j++) {
       if (includegroup && !(mask[j] & bitmask)) continue;
       jtype = type[j];
       if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
       delx = xtmp - x[j][0];
       dely = ytmp - x[j][1];
       delz = ztmp - x[j][2];
       rsq = delx*delx + dely*dely + delz*delz;
 
       if (rsq <= cutneighsq[itype][jtype]) {
         if (molecular) {
           which = find_special(special[i],nspecial[i],tag[j]);
           if (which == 0) neighptr[n++] = j;
           else if (minchange = domain->minimum_image_check(delx,dely,delz))
             neighptr[n++] = j;
           else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
         } else neighptr[n++] = j;
 
         if (rsq < cut_inner_sq) {
           if (which == 0) neighptr_inner[n_inner++] = j;
           else if (minchange) neighptr_inner[n_inner++] = j;
           else if (which > 0) neighptr_inner[n_inner++] = j ^ (which << SBBITS);
         }
 
         if (respamiddle && rsq < cut_middle_sq && rsq > cut_middle_inside_sq) {
           if (which == 0) neighptr_middle[n_middle++] = j;
           else if (minchange) neighptr_middle[n_middle++] = j;
           else if (which > 0)
             neighptr_middle[n_middle++] = j ^ (which << SBBITS);
         }
       }
     }
 
     ilist[inum] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage->vgot(n);
+    if (ipage->status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
 
     ilist_inner[inum] = i;
     firstneigh_inner[i] = neighptr_inner;
     numneigh_inner[i] = n_inner;
-    npnt_inner += n_inner;
-    if (n_inner > oneatom)
+    ipage_inner->vgot(n_inner);
+    if (ipage_inner->status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
 
     if (respamiddle) {
       ilist_middle[inum] = i;
       firstneigh_middle[i] = neighptr_middle;
       numneigh_middle[i] = n_middle;
-      npnt_middle += n_middle;
-      if (n_middle > oneatom)
+      ipage_middle->vgot(n_middle);
+      if (ipage_middle->status())
         error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
     }
 
     inum++;
   }
 
   list->inum = inum;
   listinner->inum = inum;
   if (respamiddle) listmiddle->inum = inum;
 }
 
 /* ----------------------------------------------------------------------
    multiple respa lists
    N^2 / 2 search for neighbor pairs with full Newton's 3rd law
    pair added to list if atoms i and j are both owned and i < j
    if j is ghost only me or other proc adds pair
    decision based on itag,jtag tests
 ------------------------------------------------------------------------- */
 
 void Neighbor::respa_nsq_newton(NeighList *list)
 {
   int i,j,n,itype,jtype,itag,jtag,n_inner,n_middle,bitmask;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int *neighptr,*neighptr_inner,*neighptr_middle;
 
   // loop over each atom, storing neighbors
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int nlocal = atom->nlocal;
   int nall = nlocal + atom->nghost;
   int molecular = atom->molecular;
   if (includegroup) {
     nlocal = atom->nfirst;
     bitmask = group->bitmask[includegroup];
   }
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
-  int **pages = list->pages;
+  MyPage<int> *ipage = list->ipage;
 
   NeighList *listinner = list->listinner;
   int *ilist_inner = listinner->ilist;
   int *numneigh_inner = listinner->numneigh;
   int **firstneigh_inner = listinner->firstneigh;
-  int **pages_inner = listinner->pages;
+  MyPage<int> *ipage_inner = listinner->ipage;
 
   NeighList *listmiddle;
-  int *ilist_middle,*numneigh_middle,**firstneigh_middle,**pages_middle;
+  int *ilist_middle,*numneigh_middle,**firstneigh_middle;
+  MyPage<int> *ipage_middle;
   int respamiddle = list->respamiddle;
   if (respamiddle) {
     listmiddle = list->listmiddle;
     ilist_middle = listmiddle->ilist;
     numneigh_middle = listmiddle->numneigh;
     firstneigh_middle = listmiddle->firstneigh;
-    pages_middle = listmiddle->pages;
+    ipage_middle = listmiddle->ipage;
   }
 
   int inum = 0;
-  int npage = 0;
-  int npnt = 0;
-  int npage_inner = 0;
-  int npnt_inner = 0;
-  int npage_middle = 0;
-  int npnt_middle = 0;
-
   int which = 0;
   int minchange = 0;
+  ipage->reset();
+  ipage_inner->reset();
+  if (respamiddle) ipage_middle->reset();
 
   for (i = 0; i < nlocal; i++) {
-
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage++;
-      if (npage == list->maxpage) pages = list->add_pages();
-    }
-    neighptr = &pages[npage][npnt];
-    n = 0;
-
-    if (pgsize - npnt_inner < oneatom) {
-      npnt_inner = 0;
-      npage_inner++;
-      if (npage_inner == listinner->maxpage)
-        pages_inner = listinner->add_pages();
-    }
-    neighptr_inner = &pages_inner[npage_inner][npnt_inner];
-    n_inner = 0;
-
+    n = n_inner = 0;
+    neighptr = ipage->vget();
+    neighptr_inner = ipage_inner->vget();
     if (respamiddle) {
-      if (pgsize - npnt_middle < oneatom) {
-        npnt_middle = 0;
-        npage_middle++;
-        if (npage_middle == listmiddle->maxpage)
-          pages_middle = listmiddle->add_pages();
-      }
-      neighptr_middle = &pages_middle[npage_middle][npnt_middle];
       n_middle = 0;
+      neighptr_middle = ipage_middle->vget();
     }
 
     itag = tag[i];
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over remaining atoms, owned and ghost
 
     for (j = i+1; j < nall; j++) {
       if (includegroup && !(mask[j] & bitmask)) continue;
 
       if (j >= nlocal) {
         jtag = tag[j];
         if (itag > jtag) {
           if ((itag+jtag) % 2 == 0) continue;
         } else if (itag < jtag) {
           if ((itag+jtag) % 2 == 1) continue;
         } else {
           if (x[j][2] < ztmp) continue;
           if (x[j][2] == ztmp) {
             if (x[j][1] < ytmp) continue;
             if (x[j][1] == ytmp && x[j][0] < xtmp) continue;
           }
         }
       }
 
       jtype = type[j];
       if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
       delx = xtmp - x[j][0];
       dely = ytmp - x[j][1];
       delz = ztmp - x[j][2];
       rsq = delx*delx + dely*dely + delz*delz;
 
       if (rsq <= cutneighsq[itype][jtype]) {
         if (molecular) {
           which = find_special(special[i],nspecial[i],tag[j]);
           if (which == 0) neighptr[n++] = j;
           else if (minchange = domain->minimum_image_check(delx,dely,delz))
             neighptr[n++] = j;
           else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
         } else neighptr[n++] = j;
 
         if (rsq < cut_inner_sq) {
           if (which == 0) neighptr_inner[n_inner++] = j;
           else if (minchange) neighptr_inner[n_inner++] = j;
           else if (which > 0) neighptr_inner[n_inner++] = j ^ (which << SBBITS);
         }
 
         if (respamiddle &&
             rsq < cut_middle_sq && rsq > cut_middle_inside_sq) {
           if (which == 0) neighptr_middle[n_middle++] = j;
           else if (minchange) neighptr_middle[n_middle++] = j;
           else if (which > 0)
             neighptr_middle[n_middle++] = j ^ (which << SBBITS);
         }
       }
     }
 
     ilist[inum] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage->vgot(n);
+    if (ipage->status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
 
     ilist_inner[inum] = i;
     firstneigh_inner[i] = neighptr_inner;
     numneigh_inner[i] = n_inner;
-    npnt_inner += n_inner;
-    if (n_inner > oneatom)
+    ipage_inner->vgot(n_inner);
+    if (ipage_inner->status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
 
     if (respamiddle) {
       ilist_middle[inum] = i;
       firstneigh_middle[i] = neighptr_middle;
       numneigh_middle[i] = n_middle;
-      npnt_middle += n_middle;
-      if (n_middle > oneatom)
+      ipage_middle->vgot(n_middle);
+      if (ipage_middle->status())
         error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
     }
 
     inum++;
   }
 
   list->inum = inum;
   listinner->inum = inum;
   if (respamiddle) listmiddle->inum = inum;
 }
 
 /* ----------------------------------------------------------------------
    multiple respa lists
    binned neighbor list construction with partial Newton's 3rd law
    each owned atom i checks own bin and surrounding bins in non-Newton stencil
    pair stored once if i,j are both owned and i < j
    pair stored by me if j is ghost (also stored by proc owning j)
 ------------------------------------------------------------------------- */
 
 void Neighbor::respa_bin_no_newton(NeighList *list)
 {
   int i,j,k,n,itype,jtype,ibin,n_inner,n_middle;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int *neighptr,*neighptr_inner,*neighptr_middle;
 
   // bin local & ghost atoms
 
   bin_atoms();
 
   // loop over each atom, storing neighbors
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int nlocal = atom->nlocal;
   int molecular = atom->molecular;
   if (includegroup) nlocal = atom->nfirst;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
-  int **pages = list->pages;
   int nstencil = list->nstencil;
   int *stencil = list->stencil;
+  MyPage<int> *ipage = list->ipage;
 
   NeighList *listinner = list->listinner;
   int *ilist_inner = listinner->ilist;
   int *numneigh_inner = listinner->numneigh;
   int **firstneigh_inner = listinner->firstneigh;
-  int **pages_inner = listinner->pages;
+  MyPage<int> *ipage_inner = listinner->ipage;
 
   NeighList *listmiddle;
-  int *ilist_middle,*numneigh_middle,**firstneigh_middle,**pages_middle;
+  int *ilist_middle,*numneigh_middle,**firstneigh_middle;
+  MyPage<int> *ipage_middle;
   int respamiddle = list->respamiddle;
   if (respamiddle) {
     listmiddle = list->listmiddle;
     ilist_middle = listmiddle->ilist;
     numneigh_middle = listmiddle->numneigh;
     firstneigh_middle = listmiddle->firstneigh;
-    pages_middle = listmiddle->pages;
+    ipage_middle = listmiddle->ipage;
   }
 
   int inum = 0;
-  int npage = 0;
-  int npnt = 0;
-  int npage_inner = 0;
-  int npnt_inner = 0;
-  int npage_middle = 0;
-  int npnt_middle = 0;
-
   int which = 0;
   int minchange = 0;
+  ipage->reset();
+  ipage_inner->reset();
+  if (respamiddle) ipage_middle->reset();
 
   for (i = 0; i < nlocal; i++) {
-
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage++;
-      if (npage == list->maxpage) pages = list->add_pages();
-    }
-    neighptr = &pages[npage][npnt];
-    n = 0;
-
-    if (pgsize - npnt_inner < oneatom) {
-      npnt_inner = 0;
-      npage_inner++;
-      if (npage_inner == listinner->maxpage)
-        pages_inner = listinner->add_pages();
-    }
-    neighptr_inner = &pages_inner[npage_inner][npnt_inner];
-    n_inner = 0;
-
+    n = n_inner = 0;
+    neighptr = ipage->vget();
+    neighptr_inner = ipage_inner->vget();
     if (respamiddle) {
-      if (pgsize - npnt_middle < oneatom) {
-        npnt_middle = 0;
-        npage_middle++;
-        if (npage_middle == listmiddle->maxpage)
-          pages_middle = listmiddle->add_pages();
-      }
-      neighptr_middle = &pages_middle[npage_middle][npnt_middle];
       n_middle = 0;
+      neighptr_middle = ipage_middle->vget();
     }
 
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
     ibin = coord2bin(x[i]);
 
     // loop over all atoms in surrounding bins in stencil including self
     // only store pair if i < j
     // stores own/own pairs only once
     // stores own/ghost pairs on both procs
 
     for (k = 0; k < nstencil; k++) {
       for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
         if (j <= i) continue;
 
         jtype = type[j];
         if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
         delx = xtmp - x[j][0];
         dely = ytmp - x[j][1];
         delz = ztmp - x[j][2];
         rsq = delx*delx + dely*dely + delz*delz;
 
         if (rsq <= cutneighsq[itype][jtype]) {
           if (molecular) {
             which = find_special(special[i],nspecial[i],tag[j]);
             if (which == 0) neighptr[n++] = j;
             else if (minchange = domain->minimum_image_check(delx,dely,delz))
               neighptr[n++] = j;
             else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
           } else neighptr[n++] = j;
 
           if (rsq < cut_inner_sq) {
             if (which == 0) neighptr_inner[n_inner++] = j;
             else if (minchange) neighptr_inner[n_inner++] = j;
             else if (which > 0)
               neighptr_inner[n_inner++] = j ^ (which << SBBITS);
           }
 
           if (respamiddle &&
               rsq < cut_middle_sq && rsq > cut_middle_inside_sq) {
             if (which == 0) neighptr_middle[n_middle++] = j;
             else if (minchange) neighptr_middle[n_middle++] = j;
             else if (which > 0)
               neighptr_middle[n_middle++] = j ^ (which << SBBITS);
           }
         }
       }
     }
 
     ilist[inum] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage->vgot(n);
+    if (ipage->status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
 
     ilist_inner[inum] = i;
     firstneigh_inner[i] = neighptr_inner;
     numneigh_inner[i] = n_inner;
-    npnt_inner += n_inner;
-    if (n_inner > oneatom)
+    ipage_inner->vgot(n_inner);
+    if (ipage_inner->status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
 
     if (respamiddle) {
       ilist_middle[inum] = i;
       firstneigh_middle[i] = neighptr_middle;
       numneigh_middle[i] = n_middle;
-      npnt_middle += n_middle;
-      if (n_middle > oneatom)
+      ipage_middle->vgot(n_middle);
+      if (ipage_middle->status())
         error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
     }
 
     inum++;
   }
 
   list->inum = inum;
   listinner->inum = inum;
   if (respamiddle) listmiddle->inum = inum;
 }
 
 /* ----------------------------------------------------------------------
    multiple respa lists
    binned neighbor list construction with full Newton's 3rd law
    each owned atom i checks its own bin and other bins in Newton stencil
    every pair stored exactly once by some processor
 ------------------------------------------------------------------------- */
 
 void Neighbor::respa_bin_newton(NeighList *list)
 {
   int i,j,k,n,itype,jtype,ibin,n_inner,n_middle;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int *neighptr,*neighptr_inner,*neighptr_middle;
 
   // bin local & ghost atoms
 
   bin_atoms();
 
   // loop over each atom, storing neighbors
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int nlocal = atom->nlocal;
   int molecular = atom->molecular;
   if (includegroup) nlocal = atom->nfirst;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
-  int **pages = list->pages;
   int nstencil = list->nstencil;
   int *stencil = list->stencil;
+  MyPage<int> *ipage = list->ipage;
 
   NeighList *listinner = list->listinner;
   int *ilist_inner = listinner->ilist;
   int *numneigh_inner = listinner->numneigh;
   int **firstneigh_inner = listinner->firstneigh;
-  int **pages_inner = listinner->pages;
+  MyPage<int> *ipage_inner = listinner->ipage;
 
   NeighList *listmiddle;
-  int *ilist_middle,*numneigh_middle,**firstneigh_middle,**pages_middle;
+  int *ilist_middle,*numneigh_middle,**firstneigh_middle;
+  MyPage<int> *ipage_middle;
   int respamiddle = list->respamiddle;
   if (respamiddle) {
     listmiddle = list->listmiddle;
     ilist_middle = listmiddle->ilist;
     numneigh_middle = listmiddle->numneigh;
     firstneigh_middle = listmiddle->firstneigh;
-    pages_middle = listmiddle->pages;
+    ipage_middle = listmiddle->ipage;
   }
 
   int inum = 0;
-  int npage = 0;
-  int npnt = 0;
-  int npage_inner = 0;
-  int npnt_inner = 0;
-  int npage_middle = 0;
-  int npnt_middle = 0;
-
   int which = 0;
   int minchange = 0;
+  ipage->reset();
+  ipage_inner->reset();
+  if (respamiddle) ipage_middle->reset();
 
   for (i = 0; i < nlocal; i++) {
-
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage++;
-      if (npage == list->maxpage) pages = list->add_pages();
-    }
-    neighptr = &pages[npage][npnt];
-    n = 0;
-
-    if (pgsize - npnt_inner < oneatom) {
-      npnt_inner = 0;
-      npage_inner++;
-      if (npage_inner == listinner->maxpage)
-        pages_inner = listinner->add_pages();
-    }
-    neighptr_inner = &pages_inner[npage_inner][npnt_inner];
-    n_inner = 0;
-
+    n = n_inner = 0;
+    neighptr = ipage->vget();
+    neighptr_inner = ipage_inner->vget();
     if (respamiddle) {
-      if (pgsize - npnt_middle < oneatom) {
-        npnt_middle = 0;
-        npage_middle++;
-        if (npage_middle == listmiddle->maxpage)
-          pages_middle = listmiddle->add_pages();
-      }
-      neighptr_middle = &pages_middle[npage_middle][npnt_middle];
       n_middle = 0;
+      neighptr_middle = ipage_middle->vget();
     }
 
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over rest of atoms in i's bin, ghosts are at end of linked list
     // if j is owned atom, store it, since j is beyond i in linked list
     // if j is ghost, only store if j coords are "above and to the right" of i
 
     for (j = bins[i]; j >= 0; j = bins[j]) {
       if (j >= nlocal) {
         if (x[j][2] < ztmp) continue;
         if (x[j][2] == ztmp) {
           if (x[j][1] < ytmp) continue;
           if (x[j][1] == ytmp && x[j][0] < xtmp) continue;
         }
       }
 
       jtype = type[j];
       if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
       delx = xtmp - x[j][0];
       dely = ytmp - x[j][1];
       delz = ztmp - x[j][2];
       rsq = delx*delx + dely*dely + delz*delz;
 
       if (rsq <= cutneighsq[itype][jtype]) {
         if (molecular) {
           which = find_special(special[i],nspecial[i],tag[j]);
           if (which == 0) neighptr[n++] = j;
           else if (minchange = domain->minimum_image_check(delx,dely,delz))
             neighptr[n++] = j;
           else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
         } else neighptr[n++] = j;
 
         if (rsq < cut_inner_sq) {
           if (which == 0) neighptr_inner[n_inner++] = j;
           else if (minchange) neighptr_inner[n_inner++] = j;
           else if (which > 0) neighptr_inner[n_inner++] = j ^ (which << SBBITS);
         }
 
         if (respamiddle &&
             rsq < cut_middle_sq && rsq > cut_middle_inside_sq) {
           if (which == 0) neighptr_middle[n_middle++] = j;
           else if (minchange) neighptr_middle[n_middle++] = j;
           else if (which > 0)
             neighptr_middle[n_middle++] = j ^ (which << SBBITS);
         }
       }
     }
 
     // loop over all atoms in other bins in stencil, store every pair
 
     ibin = coord2bin(x[i]);
     for (k = 0; k < nstencil; k++) {
       for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
         jtype = type[j];
         if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
         delx = xtmp - x[j][0];
         dely = ytmp - x[j][1];
         delz = ztmp - x[j][2];
         rsq = delx*delx + dely*dely + delz*delz;
 
         if (rsq <= cutneighsq[itype][jtype]) {
           if (molecular) {
             which = find_special(special[i],nspecial[i],tag[j]);
             if (which == 0) neighptr[n++] = j;
             else if (minchange = domain->minimum_image_check(delx,dely,delz))
               neighptr[n++] = j;
             else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
           } else neighptr[n++] = j;
 
           if (rsq < cut_inner_sq) {
             if (which == 0) neighptr_inner[n_inner++] = j;
             else if (minchange) neighptr_inner[n_inner++] = j;
             else if (which > 0)
               neighptr_inner[n_inner++] = j ^ (which << SBBITS);
           }
 
           if (respamiddle &&
               rsq < cut_middle_sq && rsq > cut_middle_inside_sq) {
             if (which == 0) neighptr_middle[n_middle++] = j;
             else if (minchange) neighptr_middle[n_middle++] = j;
             else if (which > 0)
               neighptr_middle[n_middle++] = j ^ (which << SBBITS);
           }
         }
       }
     }
 
     ilist[inum] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage->vgot(n);
+    if (ipage->status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
 
     ilist_inner[inum] = i;
     firstneigh_inner[i] = neighptr_inner;
     numneigh_inner[i] = n_inner;
-    npnt_inner += n_inner;
-    if (n_inner > oneatom)
+    ipage_inner->vgot(n_inner);
+    if (ipage_inner->status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
 
     if (respamiddle) {
       ilist_middle[inum] = i;
       firstneigh_middle[i] = neighptr_middle;
       numneigh_middle[i] = n_middle;
-      npnt_middle += n_middle;
-      if (n_middle > oneatom)
+      ipage_middle->vgot(n_middle);
+      if (ipage_middle->status())
         error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
     }
 
     inum++;
   }
 
   list->inum = inum;
   listinner->inum = inum;
   if (respamiddle) listmiddle->inum = inum;
 }
 
 /* ----------------------------------------------------------------------
    multiple respa lists
    binned neighbor list construction with Newton's 3rd law for triclinic
    each owned atom i checks its own bin and other bins in triclinic stencil
    every pair stored exactly once by some processor
 ------------------------------------------------------------------------- */
 
 void Neighbor::respa_bin_newton_tri(NeighList *list)
 {
   int i,j,k,n,itype,jtype,ibin,n_inner,n_middle;
   double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
   int *neighptr,*neighptr_inner,*neighptr_middle;
 
   // bin local & ghost atoms
 
   bin_atoms();
 
   // loop over each atom, storing neighbors
 
   int **special = atom->special;
   int **nspecial = atom->nspecial;
   int *tag = atom->tag;
 
   double **x = atom->x;
   int *type = atom->type;
   int *mask = atom->mask;
   int *molecule = atom->molecule;
   int nlocal = atom->nlocal;
   int molecular = atom->molecular;
   if (includegroup) nlocal = atom->nfirst;
 
   int *ilist = list->ilist;
   int *numneigh = list->numneigh;
   int **firstneigh = list->firstneigh;
-  int **pages = list->pages;
   int nstencil = list->nstencil;
   int *stencil = list->stencil;
+  MyPage<int> *ipage = list->ipage;
 
   NeighList *listinner = list->listinner;
   int *ilist_inner = listinner->ilist;
   int *numneigh_inner = listinner->numneigh;
   int **firstneigh_inner = listinner->firstneigh;
-  int **pages_inner = listinner->pages;
+  MyPage<int> *ipage_inner = listinner->ipage;
 
   NeighList *listmiddle;
-  int *ilist_middle,*numneigh_middle,**firstneigh_middle,**pages_middle;
+  int *ilist_middle,*numneigh_middle,**firstneigh_middle;
+  MyPage<int> *ipage_middle;
   int respamiddle = list->respamiddle;
   if (respamiddle) {
     listmiddle = list->listmiddle;
     ilist_middle = listmiddle->ilist;
     numneigh_middle = listmiddle->numneigh;
     firstneigh_middle = listmiddle->firstneigh;
-    pages_middle = listmiddle->pages;
+    ipage_middle = listmiddle->ipage;
   }
 
   int inum = 0;
-  int npage = 0;
-  int npnt = 0;
-  int npage_inner = 0;
-  int npnt_inner = 0;
-  int npage_middle = 0;
-  int npnt_middle = 0;
-
   int which = 0;
   int minchange = 0;
+  ipage->reset();
+  ipage_inner->reset();
+  if (respamiddle) ipage_middle->reset();
 
   for (i = 0; i < nlocal; i++) {
-
-    if (pgsize - npnt < oneatom) {
-      npnt = 0;
-      npage++;
-      if (npage == list->maxpage) pages = list->add_pages();
-    }
-    neighptr = &pages[npage][npnt];
-    n = 0;
-
-    if (pgsize - npnt_inner < oneatom) {
-      npnt_inner = 0;
-      npage_inner++;
-      if (npage_inner == listinner->maxpage)
-        pages_inner = listinner->add_pages();
-    }
-    neighptr_inner = &pages_inner[npage_inner][npnt_inner];
-    n_inner = 0;
-
+    n = n_inner = 0;
+    neighptr = ipage->vget();
+    neighptr_inner = ipage_inner->vget();
     if (respamiddle) {
-      if (pgsize - npnt_middle < oneatom) {
-        npnt_middle = 0;
-        npage_middle++;
-        if (npage_middle == listmiddle->maxpage)
-          pages_middle = listmiddle->add_pages();
-      }
-      neighptr_middle = &pages_middle[npage_middle][npnt_middle];
       n_middle = 0;
+      neighptr_middle = ipage_middle->vget();
     }
 
     itype = type[i];
     xtmp = x[i][0];
     ytmp = x[i][1];
     ztmp = x[i][2];
 
     // loop over all atoms in bins in stencil
     // pairs for atoms j "below" i are excluded
     // below = lower z or (equal z and lower y) or (equal zy and lower x)
     //         (equal zyx and j <= i)
     // latter excludes self-self interaction but allows superposed atoms
 
     ibin = coord2bin(x[i]);
     for (k = 0; k < nstencil; k++) {
       for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
         if (x[j][2] < ztmp) continue;
         if (x[j][2] == ztmp) {
           if (x[j][1] < ytmp) continue;
           if (x[j][1] == ytmp) {
             if (x[j][0] < xtmp) continue;
             if (x[j][0] == xtmp && j <= i) continue;
           }
         }
 
         jtype = type[j];
         if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
 
         delx = xtmp - x[j][0];
         dely = ytmp - x[j][1];
         delz = ztmp - x[j][2];
         rsq = delx*delx + dely*dely + delz*delz;
 
         if (rsq <= cutneighsq[itype][jtype]) {
           if (molecular) {
             which = find_special(special[i],nspecial[i],tag[j]);
             if (which == 0) neighptr[n++] = j;
             else if (minchange = domain->minimum_image_check(delx,dely,delz))
               neighptr[n++] = j;
             else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
           } else neighptr[n++] = j;
 
           if (rsq < cut_inner_sq) {
             if (which == 0) neighptr_inner[n_inner++] = j;
             else if (minchange) neighptr_inner[n_inner++] = j;
             else if (which > 0)
               neighptr_inner[n_inner++] = j ^ (which << SBBITS);
           }
 
           if (respamiddle &&
               rsq < cut_middle_sq && rsq > cut_middle_inside_sq) {
             if (which == 0) neighptr_middle[n_middle++] = j;
             else if (minchange) neighptr_middle[n_middle++] = j;
             else if (which > 0)
               neighptr_middle[n_middle++] = j ^ (which << SBBITS);
           }
         }
       }
     }
 
     ilist[inum] = i;
     firstneigh[i] = neighptr;
     numneigh[i] = n;
-    npnt += n;
-    if (n > oneatom)
+    ipage->vgot(n);
+    if (ipage->status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
 
     ilist_inner[inum] = i;
     firstneigh_inner[i] = neighptr_inner;
     numneigh_inner[i] = n_inner;
-    npnt_inner += n_inner;
-    if (n_inner > oneatom)
+    ipage_inner->vgot(n_inner);
+    if (ipage_inner->status())
       error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
 
     if (respamiddle) {
       ilist_middle[inum] = i;
       firstneigh_middle[i] = neighptr_middle;
       numneigh_middle[i] = n_middle;
-      npnt_middle += n_middle;
-      if (n_middle > oneatom)
+      ipage_middle->vgot(n_middle);
+      if (ipage_middle->status())
         error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
     }
 
     inum++;
   }
 
   list->inum = inum;
   listinner->inum = inum;
   if (respamiddle) listmiddle->inum = inum;
 }
diff --git a/src/neighbor.cpp b/src/neighbor.cpp
index 47a0630da..998d2db62 100644
--- a/src/neighbor.cpp
+++ b/src/neighbor.cpp
@@ -1,1946 +1,1949 @@
 /* ----------------------------------------------------------------------
    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 (triclinic and multi-neigh) : Pieter in 't Veld (SNL)
 ------------------------------------------------------------------------- */
 
 #include "lmptype.h"
 #include "mpi.h"
 #include "math.h"
 #include "stdlib.h"
 #include "string.h"
 #include "neighbor.h"
 #include "neigh_list.h"
 #include "neigh_request.h"
 #include "atom.h"
 #include "atom_vec.h"
 #include "comm.h"
 #include "force.h"
 #include "pair.h"
 #include "domain.h"
 #include "group.h"
 #include "modify.h"
 #include "fix.h"
 #include "compute.h"
 #include "update.h"
 #include "respa.h"
 #include "output.h"
 #include "memory.h"
 #include "error.h"
 #include "citeme.h"
 
 using namespace LAMMPS_NS;
 
 #define RQDELTA 1
 #define EXDELTA 1
 
 #define LB_FACTOR 1.5
 #define SMALL 1.0e-6
 #define BIG 1.0e20
 #define CUT2BIN_RATIO 100
 
 enum{NSQ,BIN,MULTI};     // also in neigh_list.cpp
 
 //#define NEIGH_LIST_DEBUG 1
 
 /* ---------------------------------------------------------------------- */
 
 Neighbor::Neighbor(LAMMPS *lmp) : Pointers(lmp)
 {
   MPI_Comm_rank(world,&me);
   MPI_Comm_size(world,&nprocs);
 
   style = BIN;
   every = 1;
   delay = 10;
   dist_check = 1;
   pgsize = 100000;
   oneatom = 2000;
   binsizeflag = 0;
   build_once = 0;
   cluster_check = 0;
 
   cutneighsq = NULL;
   cutneighghostsq = NULL;
   cuttype = NULL;
   cuttypesq = NULL;
   fixchecklist = NULL;
 
   // coords at last neighboring
 
   maxhold = 0;
   xhold = NULL;
 
   // binning
 
   maxhead = 0;
   binhead = NULL;
   maxbin = 0;
   bins = NULL;
 
   // pair exclusion list info
 
   includegroup = 0;
 
   nex_type = maxex_type = 0;
   ex1_type = ex2_type = NULL;
   ex_type = NULL;
 
   nex_group = maxex_group = 0;
   ex1_group = ex2_group = ex1_bit = ex2_bit = NULL;
 
   nex_mol = maxex_mol = 0;
   ex_mol_group = ex_mol_bit = NULL;
 
   // pair lists
 
   maxatom = 0;
   nblist = nglist = nslist = 0;
 
   nlist = 0;
   lists = NULL;
   pair_build = NULL;
   stencil_create = NULL;
   blist = glist = slist = NULL;
   anyghostlist = 0;
 
   nrequest = maxrequest = 0;
   requests = NULL;
 
   old_style = BIN;
   old_triclinic = 0;
+  old_pgsize = pgsize;
+  old_oneatom = oneatom;
   old_nrequest = 0;
   old_requests = NULL;
 
   // bond lists
 
   maxbond = 0;
   bondlist = NULL;
   maxangle = 0;
   anglelist = NULL;
   maxdihedral = 0;
   dihedrallist = NULL;
   maximproper = 0;
   improperlist = NULL;
 }
 
 /* ---------------------------------------------------------------------- */
 
 Neighbor::~Neighbor()
 {
   memory->destroy(cutneighsq);
   memory->destroy(cutneighghostsq);
   delete [] cuttype;
   delete [] cuttypesq;
   delete [] fixchecklist;
 
   memory->destroy(xhold);
 
   memory->destroy(binhead);
   memory->destroy(bins);
 
   memory->destroy(ex1_type);
   memory->destroy(ex2_type);
   memory->destroy(ex_type);
 
   memory->destroy(ex1_group);
   memory->destroy(ex2_group);
   delete [] ex1_bit;
   delete [] ex2_bit;
 
   memory->destroy(ex_mol_group);
   delete [] ex_mol_bit;
 
   for (int i = 0; i < nlist; i++) delete lists[i];
   delete [] lists;
   delete [] pair_build;
   delete [] stencil_create;
   delete [] blist;
   delete [] glist;
   delete [] slist;
 
   for (int i = 0; i < nrequest; i++) delete requests[i];
   memory->sfree(requests);
   for (int i = 0; i < old_nrequest; i++) delete old_requests[i];
   memory->sfree(old_requests);
 
   memory->destroy(bondlist);
   memory->destroy(anglelist);
   memory->destroy(dihedrallist);
   memory->destroy(improperlist);
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Neighbor::init()
 {
   int i,j,m,n;
 
   ncalls = ndanger = 0;
   dimension = domain->dimension;
   triclinic = domain->triclinic;
   newton_pair = force->newton_pair;
 
   // error check
 
   if (delay > 0 && (delay % every) != 0)
     error->all(FLERR,"Neighbor delay must be 0 or multiple of every setting");
 
   if (pgsize < 10*oneatom)
     error->all(FLERR,"Neighbor page size must be >= 10x the one atom setting");
 
   // ------------------------------------------------------------------
   // settings
 
   // bbox lo/hi = bounding box of entire domain, stored by Domain
 
   if (triclinic == 0) {
     bboxlo = domain->boxlo;
     bboxhi = domain->boxhi;
   } else {
     bboxlo = domain->boxlo_bound;
     bboxhi = domain->boxhi_bound;
   }
 
   // set neighbor cutoffs (force cutoff + skin)
   // trigger determines when atoms migrate and neighbor lists are rebuilt
   //   needs to be non-zero for migration distance check
   //   even if pair = NULL and no neighbor lists are used
   // cutneigh = force cutoff + skin if cutforce > 0, else cutneigh = 0
 
   triggersq = 0.25*skin*skin;
   boxcheck = 0;
   if (domain->box_change && (domain->xperiodic || domain->yperiodic ||
                              (dimension == 3 && domain->zperiodic)))
       boxcheck = 1;
 
   n = atom->ntypes;
   if (cutneighsq == NULL) {
     memory->create(cutneighsq,n+1,n+1,"neigh:cutneighsq");
     memory->create(cutneighghostsq,n+1,n+1,"neigh:cutneighghostsq");
     cuttype = new double[n+1];
     cuttypesq = new double[n+1];
   }
 
   double cutoff,delta,cut;
   cutneighmin = BIG;
   cutneighmax = 0.0;
 
   for (i = 1; i <= n; i++) {
     cuttype[i] = cuttypesq[i] = 0.0;
     for (j = 1; j <= n; j++) {
       if (force->pair) cutoff = sqrt(force->pair->cutsq[i][j]);
       else cutoff = 0.0;
       if (cutoff > 0.0) delta = skin;
       else delta = 0.0;
       cut = cutoff + delta;
 
       cutneighsq[i][j] = cut*cut;
       cuttype[i] = MAX(cuttype[i],cut);
       cuttypesq[i] = MAX(cuttypesq[i],cut*cut);
       cutneighmin = MIN(cutneighmin,cut);
       cutneighmax = MAX(cutneighmax,cut);
 
       if (force->pair && force->pair->ghostneigh) {
         cut = force->pair->cutghost[i][j] + skin;
         cutneighghostsq[i][j] = cut*cut;
       }
     }
   }
   cutneighmaxsq = cutneighmax * cutneighmax;
 
   // check other classes that can induce reneighboring in decide()
   // don't check if build_once is set
 
   restart_check = 0;
   if (output->restart_flag) restart_check = 1;
 
   delete [] fixchecklist;
   fixchecklist = NULL;
   fixchecklist = new int[modify->nfix];
 
   fix_check = 0;
   for (i = 0; i < modify->nfix; i++)
     if (modify->fix[i]->force_reneighbor)
       fixchecklist[fix_check++] = i;
 
   must_check = 0;
   if (restart_check || fix_check) must_check = 1;
   if (build_once) must_check = 0;
 
   // set special_flag for 1-2, 1-3, 1-4 neighbors
   // flag[0] is not used, flag[1] = 1-2, flag[2] = 1-3, flag[3] = 1-4
   // flag = 0 if both LJ/Coulomb special values are 0.0
   // flag = 1 if both LJ/Coulomb special values are 1.0
   // flag = 2 otherwise or if KSpace solver is enabled
   // pairwise portion of KSpace solver uses all 1-2,1-3,1-4 neighbors
 
   if (force->special_lj[1] == 0.0 && force->special_coul[1] == 0.0)
     special_flag[1] = 0;
   else if (force->special_lj[1] == 1.0 && force->special_coul[1] == 1.0)
     special_flag[1] = 1;
   else special_flag[1] = 2;
 
   if (force->special_lj[2] == 0.0 && force->special_coul[2] == 0.0)
     special_flag[2] = 0;
   else if (force->special_lj[2] == 1.0 && force->special_coul[2] == 1.0)
     special_flag[2] = 1;
   else special_flag[2] = 2;
 
   if (force->special_lj[3] == 0.0 && force->special_coul[3] == 0.0)
     special_flag[3] = 0;
   else if (force->special_lj[3] == 1.0 && force->special_coul[3] == 1.0)
     special_flag[3] = 1;
   else special_flag[3] = 2;
 
   if (force->kspace) special_flag[1] = special_flag[2] = special_flag[3] = 2;
 
   // maxwt = max multiplicative factor on atom indices stored in neigh list
 
   maxwt = 0;
   if (special_flag[1] == 2) maxwt = 2;
   if (special_flag[2] == 2) maxwt = 3;
   if (special_flag[3] == 2) maxwt = 4;
 
   // rRESPA cutoffs
 
   int respa = 0;
   if (update->whichflag == 1 && strstr(update->integrate_style,"respa")) {
     if (((Respa *) update->integrate)->level_inner >= 0) respa = 1;
     if (((Respa *) update->integrate)->level_middle >= 0) respa = 2;
   }
 
   if (respa) {
     double *cut_respa = ((Respa *) update->integrate)->cutoff;
     cut_inner_sq = (cut_respa[1] + skin) * (cut_respa[1] + skin);
     cut_middle_sq = (cut_respa[3] + skin) * (cut_respa[3] + skin);
     cut_middle_inside_sq = (cut_respa[0] - skin) * (cut_respa[0] - skin);
   }
 
   // ------------------------------------------------------------------
   // xhold, bins, exclusion lists
 
   // free xhold and bins if not needed for this run
 
   if (dist_check == 0) {
     memory->destroy(xhold);
     maxhold = 0;
     xhold = NULL;
   }
 
   if (style == NSQ) {
     memory->destroy(bins);
     memory->destroy(binhead);
     maxbin = maxhead = 0;
     binhead = NULL;
     bins = NULL;
   }
 
   // 1st time allocation of xhold and bins
 
   if (dist_check) {
     if (maxhold == 0) {
       maxhold = atom->nmax;
       memory->create(xhold,maxhold,3,"neigh:xhold");
     }
   }
 
   if (style != NSQ) {
     if (maxbin == 0) {
       maxbin = atom->nmax;
       memory->create(bins,maxbin,"bins");
     }
   }
 
   // exclusion lists for type, group, molecule settings from neigh_modify
   // warn if exclusions used with KSpace solver
 
   n = atom->ntypes;
 
   if (nex_type == 0 && nex_group == 0 && nex_mol == 0) exclude = 0;
   else exclude = 1;
 
   if (nex_type) {
     memory->destroy(ex_type);
     memory->create(ex_type,n+1,n+1,"neigh:ex_type");
 
     for (i = 1; i <= n; i++)
       for (j = 1; j <= n; j++)
         ex_type[i][j] = 0;
 
     for (i = 0; i < nex_type; i++) {
       if (ex1_type[i] <= 0 || ex1_type[i] > n ||
           ex2_type[i] <= 0 || ex2_type[i] > n)
         error->all(FLERR,"Invalid atom type in neighbor exclusion list");
       ex_type[ex1_type[i]][ex2_type[i]] = 1;
       ex_type[ex2_type[i]][ex1_type[i]] = 1;
     }
   }
 
   if (nex_group) {
     delete [] ex1_bit;
     delete [] ex2_bit;
     ex1_bit = new int[nex_group];
     ex2_bit = new int[nex_group];
 
     for (i = 0; i < nex_group; i++) {
       ex1_bit[i] = group->bitmask[ex1_group[i]];
       ex2_bit[i] = group->bitmask[ex2_group[i]];
     }
   }
 
   if (nex_mol) {
     delete [] ex_mol_bit;
     ex_mol_bit = new int[nex_mol];
 
     for (i = 0; i < nex_mol; i++)
       ex_mol_bit[i] = group->bitmask[ex_mol_group[i]];
   }
 
   if (exclude && force->kspace && me == 0)
     error->warning(FLERR,"Neighbor exclusions used with KSpace solver "
                    "may give inconsistent Coulombic energies");
 
   // ------------------------------------------------------------------
   // pairwise lists
 
   // test if pairwise lists need to be re-created
   // no need to re-create if:
-  //   neigh style and triclinic has not changed and
+  //   neigh style, triclinic, pgsize, oneatom have not changed
   //   current requests = old requests
 
   int same = 1;
   if (style != old_style) same = 0;
   if (triclinic != old_triclinic) same = 0;
+  if (pgsize != old_pgsize) same = 0;
+  if (oneatom != old_oneatom) same = 0;
   if (nrequest != old_nrequest) same = 0;
   else
     for (i = 0; i < nrequest; i++)
       if (requests[i]->identical(old_requests[i]) == 0) same = 0;
 
 #ifdef NEIGH_LIST_DEBUG
   if (comm->me == 0) printf("SAME flag %d\n",same);
 #endif
 
   // if old and new are not the same, create new pairwise lists
 
   if (!same) {
 
     // delete old lists and create new ones
 
     for (i = 0; i < nlist; i++) delete lists[i];
     delete [] lists;
     delete [] pair_build;
     delete [] stencil_create;
 
     nlist = nrequest;
     lists = new NeighList*[nlist];
     pair_build = new PairPtr[nlist];
     stencil_create = new StencilPtr[nlist];
 
     // create individual lists, one per request
     // copy dnum setting from request to list
     // pass list ptr back to requestor (except for Command class)
 
     for (i = 0; i < nlist; i++) {
-      lists[i] = new NeighList(lmp,pgsize);
+      lists[i] = new NeighList(lmp);
+      lists[i]->setup_pages(pgsize,oneatom,requests[i]->dnum);
       lists[i]->index = i;
-      lists[i]->dnum = requests[i]->dnum;
 
       if (requests[i]->pair) {
         Pair *pair = (Pair *) requests[i]->requestor;
         pair->init_list(requests[i]->id,lists[i]);
       } else if (requests[i]->fix) {
         Fix *fix = (Fix *) requests[i]->requestor;
         fix->init_list(requests[i]->id,lists[i]);
       } else if (requests[i]->compute) {
         Compute *compute = (Compute *) requests[i]->requestor;
         compute->init_list(requests[i]->id,lists[i]);
       }
     }
 
     // detect lists that are connected to other lists
     // if-then-else sequence and processed flag is important
     //   since don't want to re-process skip or copy lists further down
     //   skip list needs to have granhistory or respa info added
     // copy: point this list at request->otherlist, could be a skip list
     // skip: point this list at request->otherlist, copy skip info from request
     //   also set granular and respa info if applicable
     // half_from_full: point this list at preceeding full list
     // granhistory: set preceeding list's listgranhistory to this list
     //   also set preceeding list's ptr to FixShearHistory
     // respaouter: point this list at preceeding 1/2 inner/middle lists
     // pair and half: if there is a full non-occasional non-skip list
     //   change this list to half_from_full and point at the full list
     //   parent could be copy list or pair or fix
     // fix/compute requests:
     //   whether request is occasional or not doesn't matter
     //   if request = half and non-skip pair half/respaouter exists,
     //     become copy of that list if cudable flag matches
     //   if request = full and non-skip pair full exists,
     //     become copy of that list if cudable flag matches
     //   if request = half and non-skip pair full exists,
     //     become half_from_full of that list if cudable flag matches
     //   if no matches, do nothing, fix/compute list will be built directly
     //   ok if parent is copy list
 
     int processed;
 
     for (i = 0; i < nlist; i++) {
       processed = 0;
 
       if (requests[i]->copy) {
         lists[i]->listcopy = lists[requests[i]->otherlist];
         processed = 1;
 
       } else if (requests[i]->skip) {
         lists[i]->listskip = lists[requests[i]->otherlist];
         lists[i]->copy_skip_info(requests[i]->iskip,requests[i]->ijskip);
         processed = 1;
 
       } else if (requests[i]->half_from_full) {
         lists[i]->listfull = lists[i-1];
         processed = 1;
       }
 
       if (requests[i]->granhistory) {
         lists[i-1]->listgranhistory = lists[i];
         for (int ifix = 0; ifix < modify->nfix; ifix++)
           if (strcmp(modify->fix[ifix]->style,"SHEAR_HISTORY") == 0)
             lists[i-1]->fix_history = (FixShearHistory *) modify->fix[ifix];
         processed = 1;
 
       } else if (requests[i]->respaouter) {
         if (requests[i-1]->respainner) {
           lists[i]->respamiddle = 0;
           lists[i]->listinner = lists[i-1];
         } else {
           lists[i]->respamiddle = 1;
           lists[i]->listmiddle = lists[i-1];
           lists[i]->listinner = lists[i-2];
         }
         processed = 1;
       }
 
       if (processed) continue;
 
       if (requests[i]->pair && requests[i]->half) {
         for (j = 0; j < nlist; j++)
           if (requests[j]->full && requests[j]->occasional == 0 &&
               requests[j]->skip == 0) break;
         if (j < nlist) {
           requests[i]->half = 0;
           requests[i]->half_from_full = 1;
           lists[i]->listfull = lists[j];
         }
         
       } else if (requests[i]->fix || requests[i]->compute) {
         for (j = 0; j < nlist; j++) {
           if (requests[i]->half && requests[j]->pair &&
               requests[j]->skip == 0 && requests[j]->half) break;
           if (requests[i]->full && requests[j]->pair &&
               requests[j]->skip == 0 && requests[j]->full) break;
           if (requests[i]->gran && requests[j]->pair &&
               requests[j]->skip == 0 && requests[j]->gran) break;
           if (requests[i]->half && requests[j]->pair &&
               requests[j]->skip == 0 && requests[j]->respaouter) break;
         }
         if (j < nlist && requests[j]->cudable != requests[i]->cudable)
           j = nlist;
         if (j < nlist) {
           requests[i]->copy = 1;
           requests[i]->otherlist = j;
           lists[i]->listcopy = lists[j];
         } else {
           for (j = 0; j < nlist; j++) {
             if (requests[i]->half && requests[j]->pair &&
                 requests[j]->skip == 0 && requests[j]->full) break;
           }
           if (j < nlist && requests[j]->cudable != requests[i]->cudable)
             j = nlist;
           if (j < nlist) {
             requests[i]->half = 0;
             requests[i]->half_from_full = 1;
             lists[i]->listfull = lists[j];
           }
         }
       }
     }
 
     // set ptrs to pair_build and stencil_create functions for each list
     // ptrs set to NULL if not set explicitly
     // also set cudable to 0 if any neigh list request is not cudable
 
     for (i = 0; i < nlist; i++) {
       choose_build(i,requests[i]);
       if (style != NSQ) choose_stencil(i,requests[i]);
       else stencil_create[i] = NULL;
       if (!requests[i]->cudable) cudable = 0;
     }
 
     // set each list's build/grow/stencil/ghost flags based on neigh request
     // buildflag = 1 if its pair_build() invoked every reneighbor
     // growflag = 1 if it stores atom-based arrays and pages
     // stencilflag = 1 if it stores stencil arrays
     // ghostflag = 1 if it stores neighbors of ghosts
     // anyghostlist = 1 if any non-occasional list stores neighbors of ghosts
 
     anyghostlist = 0;
     for (i = 0; i < nlist; i++) {
       lists[i]->buildflag = 1;
       if (pair_build[i] == NULL) lists[i]->buildflag = 0;
       if (requests[i]->occasional) lists[i]->buildflag = 0;
 
       lists[i]->growflag = 1;
       if (requests[i]->copy) lists[i]->growflag = 0;
 
       lists[i]->stencilflag = 1;
       if (style == NSQ) lists[i]->stencilflag = 0;
       if (stencil_create[i] == NULL) lists[i]->stencilflag = 0;
 
       lists[i]->ghostflag = 0;
       if (requests[i]->ghost) lists[i]->ghostflag = 1;
       if (requests[i]->ghost && !requests[i]->occasional) anyghostlist = 1;
     }
 
 #ifdef NEIGH_LIST_DEBUG
     for (i = 0; i < nlist; i++) lists[i]->print_attributes();
 #endif
 
-    // allocate atom arrays and 1st pages of lists that store them
+    // allocate atom arrays for neighbor lists that store them
 
     maxatom = atom->nmax;
     for (i = 0; i < nlist; i++)
-      if (lists[i]->growflag) {
-        lists[i]->grow(maxatom);
-        lists[i]->add_pages();
-      }
+      if (lists[i]->growflag) lists[i]->grow(maxatom);
 
     // setup 3 vectors of pairwise neighbor lists
     // blist = lists whose pair_build() is invoked every reneighbor
     // glist = lists who store atom arrays which are used every reneighbor
     // slist = lists who store stencil arrays which are used every reneighbor
     // blist and glist vectors are used by neighbor::build()
     // slist vector is used by neighbor::setup_bins()
 
     nblist = nglist = nslist = 0;
     delete [] blist;
     delete [] glist;
     delete [] slist;
     blist = new int[nlist];
     glist = new int[nlist];
     slist = new int[nlist];
 
     for (i = 0; i < nlist; i++) {
       if (lists[i]->buildflag) blist[nblist++] = i;
       if (lists[i]->growflag && requests[i]->occasional == 0)
         glist[nglist++] = i;
       if (lists[i]->stencilflag && requests[i]->occasional == 0)
         slist[nslist++] = i;
     }
 
 #ifdef NEIGH_LIST_DEBUG
     print_lists_of_lists();
 #endif
 
     // reorder build vector if necessary
     // relevant for lists that copy/skip/half-full from parent
     // the derived list must appear in blist after the parent list
     // no occasional lists are in build vector
     // swap two lists within blist when dependency is mis-ordered
     // done when entire pass thru blist results in no swaps
 
     int done = 0;
     while (!done) {
       done = 1;
       for (i = 0; i < nblist; i++) {
         NeighList *ptr = NULL;
         if (lists[blist[i]]->listfull) ptr = lists[blist[i]]->listfull;
         if (lists[blist[i]]->listcopy) ptr = lists[blist[i]]->listcopy;
         if (lists[blist[i]]->listskip) ptr = lists[blist[i]]->listskip;
         if (ptr == NULL) continue;
         for (m = 0; m < nlist; m++)
           if (ptr == lists[m]) break;
         for (j = 0; j < nblist; j++)
           if (m == blist[j]) break;
         if (j < i) continue;
         int tmp = blist[i];
         blist[i] = blist[j];
         blist[j] = tmp;
         done = 0;
         break;
       }
     }
 
 #ifdef NEIGH_LIST_DEBUG
     print_lists_of_lists();
 #endif
   }
 
   // delete old requests
   // copy current requests and style to old for next run
 
   for (i = 0; i < old_nrequest; i++) delete old_requests[i];
   memory->sfree(old_requests);
   old_nrequest = nrequest;
   old_requests = requests;
   nrequest = maxrequest = 0;
   requests = NULL;
   old_style = style;
   old_triclinic = triclinic;
 
   // ------------------------------------------------------------------
   // topology lists
 
   // 1st time allocation of topology lists
 
   if (atom->molecular && atom->nbonds && maxbond == 0) {
     if (nprocs == 1) maxbond = atom->nbonds;
     else maxbond = static_cast<int> (LB_FACTOR * atom->nbonds / nprocs);
     memory->create(bondlist,maxbond,3,"neigh:bondlist");
   }
 
   if (atom->molecular && atom->nangles && maxangle == 0) {
     if (nprocs == 1) maxangle = atom->nangles;
     else maxangle = static_cast<int> (LB_FACTOR * atom->nangles / nprocs);
     memory->create(anglelist,maxangle,4,"neigh:anglelist");
   }
 
   if (atom->molecular && atom->ndihedrals && maxdihedral == 0) {
     if (nprocs == 1) maxdihedral = atom->ndihedrals;
     else maxdihedral = static_cast<int>
            (LB_FACTOR * atom->ndihedrals / nprocs);
     memory->create(dihedrallist,maxdihedral,5,"neigh:dihedrallist");
   }
 
   if (atom->molecular && atom->nimpropers && maximproper == 0) {
     if (nprocs == 1) maximproper = atom->nimpropers;
     else maximproper = static_cast<int>
            (LB_FACTOR * atom->nimpropers / nprocs);
     memory->create(improperlist,maximproper,5,"neigh:improperlist");
   }
 
   // set flags that determine which topology neighboring routines to use
   // SHAKE sets bonds and angles negative
   // bond_quartic sets bonds to 0
   // delete_bonds sets all interactions negative
 
   int bond_off = 0;
   int angle_off = 0;
   for (i = 0; i < modify->nfix; i++)
     if (strcmp(modify->fix[i]->style,"shake") == 0)
       bond_off = angle_off = 1;
   if (force->bond && force->bond_match("quartic")) bond_off = 1;
 
   if (atom->avec->bonds_allow) {
     for (i = 0; i < atom->nlocal; i++) {
       if (bond_off) break;
       for (m = 0; m < atom->num_bond[i]; m++)
         if (atom->bond_type[i][m] <= 0) bond_off = 1;
     }
   }
 
   if (atom->avec->angles_allow) {
     for (i = 0; i < atom->nlocal; i++) {
       if (angle_off) break;
       for (m = 0; m < atom->num_angle[i]; m++)
         if (atom->angle_type[i][m] <= 0) angle_off = 1;
     }
   }
 
   int dihedral_off = 0;
   if (atom->avec->dihedrals_allow) {
     for (i = 0; i < atom->nlocal; i++) {
       if (dihedral_off) break;
       for (m = 0; m < atom->num_dihedral[i]; m++)
         if (atom->dihedral_type[i][m] <= 0) dihedral_off = 1;
     }
   }
 
   int improper_off = 0;
   if (atom->avec->impropers_allow) {
     for (i = 0; i < atom->nlocal; i++) {
       if (improper_off) break;
       for (m = 0; m < atom->num_improper[i]; m++)
         if (atom->improper_type[i][m] <= 0) improper_off = 1;
     }
   }
 
   // set ptrs to topology build functions
 
   if (bond_off) bond_build = &Neighbor::bond_partial;
   else bond_build = &Neighbor::bond_all;
 
   if (angle_off) angle_build = &Neighbor::angle_partial;
   else angle_build = &Neighbor::angle_all;
 
   if (dihedral_off) dihedral_build = &Neighbor::dihedral_partial;
   else dihedral_build = &Neighbor::dihedral_all;
 
   if (improper_off) improper_build = &Neighbor::improper_partial;
   else improper_build = &Neighbor::improper_all;
 
   // set topology neighbor list counts to 0
   // in case all are turned off but potential is still defined
 
   nbondlist = nanglelist = ndihedrallist = nimproperlist = 0;
 }
 
 /* ---------------------------------------------------------------------- */
 
 int Neighbor::request(void *requestor)
 {
   if (nrequest == maxrequest) {
     maxrequest += RQDELTA;
     requests = (NeighRequest **)
       memory->srealloc(requests,maxrequest*sizeof(NeighRequest *),
                        "neighbor:requests");
   }
 
   requests[nrequest] = new NeighRequest(lmp);
   requests[nrequest]->requestor = requestor;
   nrequest++;
   return nrequest-1;
 }
 
 /* ----------------------------------------------------------------------
    determine which pair_build function each neigh list needs
    based on settings of neigh request
    copy -> copy_from function
    skip -> granular function if gran with granhistory,
            respa function if respaouter,
            skip_from function for everything else
    half_from_full, half, full, gran, respaouter ->
      choose by newton and rq->newton and tri settings
      style NSQ options = newton off, newton on
      style BIN options = newton off, newton on and not tri, newton on and tri
      stlye MULTI options = same options as BIN
    if none of these, ptr = NULL since pair_build is not invoked for this list
    use "else if" b/c skip,copy can be set in addition to half,full,etc
 ------------------------------------------------------------------------- */
 
 void Neighbor::choose_build(int index, NeighRequest *rq)
 {
   PairPtr pb = NULL;
 
   if (rq->omp == 0) {
 
     if (rq->copy) pb = &Neighbor::copy_from;
 
     else if (rq->skip) {
       if (rq->gran && lists[index]->listgranhistory)
         pb = &Neighbor::skip_from_granular;
       else if (rq->respaouter) pb = &Neighbor::skip_from_respa;
       else pb = &Neighbor::skip_from;
 
     } else if (rq->half_from_full) {
       if (newton_pair == 0) pb = &Neighbor::half_from_full_no_newton;
       else if (newton_pair == 1) pb = &Neighbor::half_from_full_newton;
 
     } else if (rq->half) {
       if (style == NSQ) {
         if (rq->newton == 0) {
           if (newton_pair == 0) {
             if (rq->ghost == 0) pb = &Neighbor::half_nsq_no_newton;
             else if (includegroup)
               error->all(FLERR,"Neighbor include group not allowed "
                          "with ghost neighbors");
             else pb = &Neighbor::half_nsq_no_newton_ghost;
           } else if (newton_pair == 1) pb = &Neighbor::half_nsq_newton;
         } else if (rq->newton == 1) {
           pb = &Neighbor::half_nsq_newton;
         } else if (rq->newton == 2) {
           if (rq->ghost == 0) pb = &Neighbor::half_nsq_no_newton;
           else if (includegroup)
             error->all(FLERR,"Neighbor include group not allowed "
                        "with ghost neighbors");
           else pb = &Neighbor::half_nsq_no_newton_ghost;
         }
       } else if (style == BIN) {
         if (rq->newton == 0) {
           if (newton_pair == 0) {
             if (rq->ghost == 0) pb = &Neighbor::half_bin_no_newton;
             else if (includegroup)
               error->all(FLERR,"Neighbor include group not allowed "
                          "with ghost neighbors");
             else pb = &Neighbor::half_bin_no_newton_ghost;
           } else if (triclinic == 0) {
             pb = &Neighbor::half_bin_newton;
           } else if (triclinic == 1)
             pb = &Neighbor::half_bin_newton_tri;
         } else if (rq->newton == 1) {
           if (triclinic == 0) pb = &Neighbor::half_bin_newton;
           else if (triclinic == 1) pb = &Neighbor::half_bin_newton_tri;
         } else if (rq->newton == 2) {
           if (rq->ghost == 0) pb = &Neighbor::half_bin_no_newton;
           else if (includegroup)
             error->all(FLERR,"Neighbor include group not allowed "
                        "with ghost neighbors");
           else pb = &Neighbor::half_bin_no_newton_ghost;
         }
       } else if (style == MULTI) {
         if (rq->ghost == 1)
           error->all(FLERR,
                      "Neighbor multi not yet enabled for ghost neighbors");
         if (rq->newton == 0) {
           if (newton_pair == 0) pb = &Neighbor::half_multi_no_newton;
           else if (triclinic == 0) pb = &Neighbor::half_multi_newton;
           else if (triclinic == 1) pb = &Neighbor::half_multi_newton_tri;
         } else if (rq->newton == 1) {
           if (triclinic == 0) pb = &Neighbor::half_multi_newton;
           else if (triclinic == 1) pb = &Neighbor::half_multi_newton_tri;
         } else if (rq->newton == 2) pb = &Neighbor::half_multi_no_newton;
       }
 
     } else if (rq->full) {
       if (style == NSQ) {
         if (rq->ghost == 0) pb = &Neighbor::full_nsq;
         else if (includegroup)
           error->all(FLERR,
                      "Neighbor include group not allowed with ghost neighbors");
         else pb = &Neighbor::full_nsq_ghost;
       } else if (style == BIN) {
         if (rq->ghost == 0) pb = &Neighbor::full_bin;
         else if (includegroup)
           error->all(FLERR,
                      "Neighbor include group not allowed with ghost neighbors");
         else pb = &Neighbor::full_bin_ghost;
       } else if (style == MULTI) {
         if (rq->ghost == 1)
           error->all(FLERR,
                      "Neighbor multi not yet enabled for ghost neighbors");
         pb = &Neighbor::full_multi;
       }
 
     } else if (rq->gran) {
       if (style == NSQ) {
         if (newton_pair == 0) pb = &Neighbor::granular_nsq_no_newton;
         else if (newton_pair == 1) pb = &Neighbor::granular_nsq_newton;
       } else if (style == BIN) {
         if (newton_pair == 0) pb = &Neighbor::granular_bin_no_newton;
         else if (triclinic == 0) pb = &Neighbor::granular_bin_newton;
         else if (triclinic == 1) pb = &Neighbor::granular_bin_newton_tri;
       } else if (style == MULTI)
         error->all(FLERR,"Neighbor multi not yet enabled for granular");
 
     } else if (rq->respaouter) {
       if (style == NSQ) {
         if (newton_pair == 0) pb = &Neighbor::respa_nsq_no_newton;
         else if (newton_pair == 1) pb = &Neighbor::respa_nsq_newton;
       } else if (style == BIN) {
         if (newton_pair == 0) pb = &Neighbor::respa_bin_no_newton;
         else if (triclinic == 0) pb = &Neighbor::respa_bin_newton;
         else if (triclinic == 1) pb = &Neighbor::respa_bin_newton_tri;
       } else if (style == MULTI)
         error->all(FLERR,"Neighbor multi not yet enabled for rRESPA");
     }
 
   // OMP versions of build methods
 
   } else {
 
     if (rq->copy) pb = &Neighbor::copy_from;
 
     else if (rq->skip) {
       if (rq->gran && lists[index]->listgranhistory)
         pb = &Neighbor::skip_from_granular;
       else if (rq->respaouter) pb = &Neighbor::skip_from_respa;
       else pb = &Neighbor::skip_from;
 
     } else if (rq->half_from_full) {
       if (newton_pair == 0) pb = &Neighbor::half_from_full_no_newton_omp;
       else if (newton_pair == 1) pb = &Neighbor::half_from_full_newton_omp;
 
     } else if (rq->half) {
       if (style == NSQ) {
         if (rq->newton == 0) {
           if (newton_pair == 0) {
             if (rq->ghost == 0) pb = &Neighbor::half_nsq_no_newton_omp;
             else if (includegroup)
               error->all(FLERR,"Neighbor include group not allowed "
                          "with ghost neighbors");
             else pb = &Neighbor::half_nsq_no_newton_ghost_omp;
           } else if (newton_pair == 1) pb = &Neighbor::half_nsq_newton_omp;
         } else if (rq->newton == 1) {
           pb = &Neighbor::half_nsq_newton_omp;
         } else if (rq->newton == 2) {
           if (rq->ghost == 0) pb = &Neighbor::half_nsq_no_newton_omp;
           else if (includegroup)
             error->all(FLERR,"Neighbor include group not allowed "
                        "with ghost neighbors");
           else pb = &Neighbor::half_nsq_no_newton_ghost_omp;
         }
       } else if (style == BIN) {
         if (rq->newton == 0) {
           if (newton_pair == 0) {
             if (rq->ghost == 0) pb = &Neighbor::half_bin_no_newton_omp;
             else if (includegroup)
               error->all(FLERR,"Neighbor include group not allowed "
                          "with ghost neighbors");
             else pb = &Neighbor::half_bin_no_newton_ghost_omp;
           } else if (triclinic == 0) {
             pb = &Neighbor::half_bin_newton_omp;
           } else if (triclinic == 1)
             pb = &Neighbor::half_bin_newton_tri_omp;
         } else if (rq->newton == 1) {
           if (triclinic == 0) pb = &Neighbor::half_bin_newton_omp;
           else if (triclinic == 1) pb = &Neighbor::half_bin_newton_tri_omp;
         } else if (rq->newton == 2) {
           if (rq->ghost == 0) pb = &Neighbor::half_bin_no_newton_omp;
           else if (includegroup)
             error->all(FLERR,"Neighbor include group not allowed "
                        "with ghost neighbors");
           else pb = &Neighbor::half_bin_no_newton_ghost_omp;
         }
       } else if (style == MULTI) {
         if (rq->ghost == 1)
           error->all(FLERR,
                      "Neighbor multi not yet enabled for ghost neighbors");
         if (rq->newton == 0) {
           if (newton_pair == 0) pb = &Neighbor::half_multi_no_newton_omp;
           else if (triclinic == 0) pb = &Neighbor::half_multi_newton_omp;
           else if (triclinic == 1) pb = &Neighbor::half_multi_newton_tri_omp;
         } else if (rq->newton == 1) {
           if (triclinic == 0) pb = &Neighbor::half_multi_newton_omp;
           else if (triclinic == 1) pb = &Neighbor::half_multi_newton_tri_omp;
         } else if (rq->newton == 2) pb = &Neighbor::half_multi_no_newton_omp;
       }
 
     } else if (rq->full) {
       if (style == NSQ) {
         if (rq->ghost == 0) pb = &Neighbor::full_nsq_omp;
         else if (includegroup)
           error->all(FLERR,
                      "Neighbor include group not allowed with ghost neighbors");
         else pb = &Neighbor::full_nsq_ghost_omp;
       } else if (style == BIN) {
         if (rq->ghost == 0) pb = &Neighbor::full_bin_omp;
         else if (includegroup)
           error->all(FLERR,
                      "Neighbor include group not allowed with ghost neighbors");
         else pb = &Neighbor::full_bin_ghost_omp;
       } else if (style == MULTI) {
         if (rq->ghost == 1)
           error->all(FLERR,
                      "Neighbor multi not yet enabled for ghost neighbors");
         pb = &Neighbor::full_multi_omp;
       }
 
     } else if (rq->gran) {
       if (style == NSQ) {
         if (newton_pair == 0) pb = &Neighbor::granular_nsq_no_newton_omp;
         else if (newton_pair == 1) pb = &Neighbor::granular_nsq_newton_omp;
       } else if (style == BIN) {
         if (newton_pair == 0) pb = &Neighbor::granular_bin_no_newton_omp;
         else if (triclinic == 0) pb = &Neighbor::granular_bin_newton_omp;
         else if (triclinic == 1) pb = &Neighbor::granular_bin_newton_tri_omp;
       } else if (style == MULTI)
         error->all(FLERR,"Neighbor multi not yet enabled for granular");
 
     } else if (rq->respaouter) {
       if (style == NSQ) {
         if (newton_pair == 0) pb = &Neighbor::respa_nsq_no_newton_omp;
         else if (newton_pair == 1) pb = &Neighbor::respa_nsq_newton_omp;
       } else if (style == BIN) {
         if (newton_pair == 0) pb = &Neighbor::respa_bin_no_newton_omp;
         else if (triclinic == 0) pb = &Neighbor::respa_bin_newton_omp;
         else if (triclinic == 1) pb = &Neighbor::respa_bin_newton_tri_omp;
       } else if (style == MULTI)
         error->all(FLERR,"Neighbor multi not yet enabled for rRESPA");
     }
   }
 
   pair_build[index] = pb;
 }
 
 /* ----------------------------------------------------------------------
    determine which stencil_create function each neigh list needs
    based on settings of neigh request, only called if style != NSQ
    skip or copy or half_from_full -> no stencil
    half, gran, respaouter, full -> choose by newton and tri and dimension
    if none of these, ptr = NULL since this list needs no stencils
    use "else if" b/c skip,copy can be set in addition to half,full,etc
 ------------------------------------------------------------------------- */
 
 void Neighbor::choose_stencil(int index, NeighRequest *rq)
 {
   StencilPtr sc = NULL;
 
   if (rq->skip || rq->copy || rq->half_from_full) sc = NULL;
 
   else if (rq->half || rq->gran || rq->respaouter) {
     if (style == BIN) {
       if (rq->newton == 0) {
         if (newton_pair == 0) {
           if (dimension == 2) {
             if (rq->ghost) sc = &Neighbor::stencil_half_ghost_bin_2d_no_newton;
             else sc = &Neighbor::stencil_half_bin_2d_no_newton;
           } else if (dimension == 3) {
             if (rq->ghost) sc = &Neighbor::stencil_half_ghost_bin_3d_no_newton;
             else sc = &Neighbor::stencil_half_bin_3d_no_newton;
           }
         } else if (triclinic == 0) {
           if (dimension == 2)
             sc = &Neighbor::stencil_half_bin_2d_newton;
           else if (dimension == 3)
             sc = &Neighbor::stencil_half_bin_3d_newton;
         } else if (triclinic == 1) {
           if (dimension == 2)
             sc = &Neighbor::stencil_half_bin_2d_newton_tri;
           else if (dimension == 3)
             sc = &Neighbor::stencil_half_bin_3d_newton_tri;
         }
       } else if (rq->newton == 1) {
         if (triclinic == 0) {
           if (dimension == 2)
             sc = &Neighbor::stencil_half_bin_2d_newton;
           else if (dimension == 3)
             sc = &Neighbor::stencil_half_bin_3d_newton;
         } else if (triclinic == 1) {
           if (dimension == 2)
             sc = &Neighbor::stencil_half_bin_2d_newton_tri;
           else if (dimension == 3)
             sc = &Neighbor::stencil_half_bin_3d_newton_tri;
         }
       } else if (rq->newton == 2) {
         if (dimension == 2)
           if (rq->ghost) sc = &Neighbor::stencil_half_ghost_bin_2d_no_newton;
           else sc = &Neighbor::stencil_half_bin_2d_no_newton;
         else if (dimension == 3) {
           if (rq->ghost) sc = &Neighbor::stencil_half_ghost_bin_3d_no_newton;
           else sc = &Neighbor::stencil_half_bin_3d_no_newton;
         }
       }
 
     } else if (style == MULTI) {
       if (rq->newton == 0) {
         if (newton_pair == 0) {
           if (dimension == 2)
             sc = &Neighbor::stencil_half_multi_2d_no_newton;
           else if (dimension == 3)
             sc = &Neighbor::stencil_half_multi_3d_no_newton;
         } else if (triclinic == 0) {
           if (dimension == 2)
             sc = &Neighbor::stencil_half_multi_2d_newton;
           else if (dimension == 3)
             sc = &Neighbor::stencil_half_multi_3d_newton;
         } else if (triclinic == 1) {
           if (dimension == 2)
             sc = &Neighbor::stencil_half_multi_2d_newton_tri;
           else if (dimension == 3)
             sc = &Neighbor::stencil_half_multi_3d_newton_tri;
         }
       } else if (rq->newton == 1) {
         if (triclinic == 0) {
           if (dimension == 2)
             sc = &Neighbor::stencil_half_multi_2d_newton;
           else if (dimension == 3)
             sc = &Neighbor::stencil_half_multi_3d_newton;
         } else if (triclinic == 1) {
           if (dimension == 2)
             sc = &Neighbor::stencil_half_multi_2d_newton_tri;
           else if (dimension == 3)
             sc = &Neighbor::stencil_half_multi_3d_newton_tri;
         }
       } else if (rq->newton == 2) {
         if (dimension == 2)
           sc = &Neighbor::stencil_half_multi_2d_no_newton;
         else if (dimension == 3)
           sc = &Neighbor::stencil_half_multi_3d_no_newton;
       }
     }
 
   } else if (rq->full) {
     if (style == BIN) {
       if (dimension == 2) {
         if (rq->ghost) sc = &Neighbor::stencil_full_ghost_bin_2d;
         else sc = &Neighbor::stencil_full_bin_2d;
       }
       else if (dimension == 3) {
         if (rq->ghost) sc = &Neighbor::stencil_full_ghost_bin_3d;
         else sc = &Neighbor::stencil_full_bin_3d;
       }
     } else if (style == MULTI) {
       if (dimension == 2) sc = &Neighbor::stencil_full_multi_2d;
       else if (dimension == 3) sc = &Neighbor::stencil_full_multi_3d;
     }
   }
 
   stencil_create[index] = sc;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Neighbor::print_lists_of_lists()
 {
   if (comm->me == 0) {
     printf("Build lists = %d: ",nblist);
     for (int i = 0; i < nblist; i++) printf("%d ",blist[i]);
     printf("\n");
     printf("Grow lists = %d: ",nglist);
     for (int i = 0; i < nglist; i++) printf("%d ",glist[i]);
     printf("\n");
     printf("Stencil lists = %d: ",nslist);
     for (int i = 0; i < nslist; i++) printf("%d ",slist[i]);
     printf("\n");
   }
 }
 
 /* ---------------------------------------------------------------------- */
 
 int Neighbor::decide()
 {
   if (must_check) {
     int n = update->ntimestep;
     if (restart_check && n == output->next_restart) return 1;
     for (int i = 0; i < fix_check; i++)
       if (n == modify->fix[fixchecklist[i]]->next_reneighbor) return 1;
   }
 
   ago++;
   if (ago >= delay && ago % every == 0) {
     if (build_once) return 0;
     if (dist_check == 0) return 1;
     return check_distance();
   } else return 0;
 }
 
 /* ----------------------------------------------------------------------
    if any atom moved trigger distance (half of neighbor skin) return 1
    shrink trigger distance if box size has changed
    conservative shrink procedure:
      compute distance each of 8 corners of box has moved since last reneighbor
      reduce skin distance by sum of 2 largest of the 8 values
      new trigger = 1/2 of reduced skin distance
    for orthogonal box, only need 2 lo/hi corners
    for triclinic, need all 8 corners since deformations can displace all 8
 ------------------------------------------------------------------------- */
 
 int Neighbor::check_distance()
 {
   double delx,dely,delz,rsq;
   double delta,deltasq,delta1,delta2;
 
   if (boxcheck) {
     if (triclinic == 0) {
       delx = bboxlo[0] - boxlo_hold[0];
       dely = bboxlo[1] - boxlo_hold[1];
       delz = bboxlo[2] - boxlo_hold[2];
       delta1 = sqrt(delx*delx + dely*dely + delz*delz);
       delx = bboxhi[0] - boxhi_hold[0];
       dely = bboxhi[1] - boxhi_hold[1];
       delz = bboxhi[2] - boxhi_hold[2];
       delta2 = sqrt(delx*delx + dely*dely + delz*delz);
       delta = 0.5 * (skin - (delta1+delta2));
       deltasq = delta*delta;
     } else {
       domain->box_corners();
       delta1 = delta2 = 0.0;
       for (int i = 0; i < 8; i++) {
         delx = corners[i][0] - corners_hold[i][0];
         dely = corners[i][1] - corners_hold[i][1];
         delz = corners[i][2] - corners_hold[i][2];
         delta = sqrt(delx*delx + dely*dely + delz*delz);
         if (delta > delta1) delta1 = delta;
         else if (delta > delta2) delta2 = delta;
       }
       delta = 0.5 * (skin - (delta1+delta2));
       deltasq = delta*delta;
     }
   } else deltasq = triggersq;
 
   double **x = atom->x;
   int nlocal = atom->nlocal;
   if (includegroup) nlocal = atom->nfirst;
 
   int flag = 0;
   for (int i = 0; i < nlocal; i++) {
     delx = x[i][0] - xhold[i][0];
     dely = x[i][1] - xhold[i][1];
     delz = x[i][2] - xhold[i][2];
     rsq = delx*delx + dely*dely + delz*delz;
     if (rsq > deltasq) flag = 1;
   }
 
   int flagall;
   MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_MAX,world);
   if (flagall && ago == MAX(every,delay)) ndanger++;
   return flagall;
 }
 
 /* ----------------------------------------------------------------------
    build all perpetual neighbor lists every few timesteps
    pairwise & topology lists are created as needed
    topology lists only built if topoflag = 1
 ------------------------------------------------------------------------- */
 
 void Neighbor::build(int topoflag)
 {
   int i;
 
   ago = 0;
   ncalls++;
   lastcall = update->ntimestep;
 
   // store current atom positions and box size if needed
 
   if (dist_check) {
     double **x = atom->x;
     int nlocal = atom->nlocal;
     if (includegroup) nlocal = atom->nfirst;
     if (nlocal > maxhold) {
       maxhold = atom->nmax;
       memory->destroy(xhold);
       memory->create(xhold,maxhold,3,"neigh:xhold");
     }
     for (i = 0; i < nlocal; i++) {
       xhold[i][0] = x[i][0];
       xhold[i][1] = x[i][1];
       xhold[i][2] = x[i][2];
     }
     if (boxcheck) {
       if (triclinic == 0) {
         boxlo_hold[0] = bboxlo[0];
         boxlo_hold[1] = bboxlo[1];
         boxlo_hold[2] = bboxlo[2];
         boxhi_hold[0] = bboxhi[0];
         boxhi_hold[1] = bboxhi[1];
         boxhi_hold[2] = bboxhi[2];
       } else {
         domain->box_corners();
         corners = domain->corners;
         for (i = 0; i < 8; i++) {
           corners_hold[i][0] = corners[i][0];
           corners_hold[i][1] = corners[i][1];
           corners_hold[i][2] = corners[i][2];
         }
       }
     }
   }
 
   // if any lists store neighbors of ghosts:
   // invoke grow() if nlocal+nghost exceeds previous list size
   // else only invoke grow() if nlocal exceeds previous list size
   // only done for lists with growflag set and which are perpetual
 
   if (anyghostlist && atom->nlocal+atom->nghost > maxatom) {
     maxatom = atom->nmax;
     for (i = 0; i < nglist; i++) lists[glist[i]]->grow(maxatom);
   } else if (atom->nlocal > maxatom) {
     maxatom = atom->nmax;
     for (i = 0; i < nglist; i++) lists[glist[i]]->grow(maxatom);
   }
 
   // extend atom bin list if necessary
 
   if (style != NSQ && atom->nmax > maxbin) {
     maxbin = atom->nmax;
     memory->destroy(bins);
     memory->create(bins,maxbin,"bins");
   }
 
   // check that neighbor list with special bond flags will not overflow
 
   if (atom->nlocal+atom->nghost > NEIGHMASK)
     error->one(FLERR,"Too many local+ghost atoms for neighbor list");
 
   // invoke building of pair and molecular neighbor lists
   // only for pairwise lists with buildflag set
 
   for (i = 0; i < nblist; i++)
     (this->*pair_build[blist[i]])(lists[blist[i]]);
 
   if (atom->molecular && topoflag) build_topology();
 }
 
 /* ----------------------------------------------------------------------
    build all topology neighbor lists every few timesteps
    normally built with pair lists, but USER-CUDA separates them
 ------------------------------------------------------------------------- */
 
 void Neighbor::build_topology()
 {
   if (force->bond) (this->*bond_build)();
   if (force->angle) (this->*angle_build)();
   if (force->dihedral) (this->*dihedral_build)();
   if (force->improper) (this->*improper_build)();
 }
 
 /* ----------------------------------------------------------------------
    build a single occasional pairwise neighbor list indexed by I
    called by other classes
 ------------------------------------------------------------------------- */
 
 void Neighbor::build_one(int i)
 {
   // update stencils and grow atom arrays and bins as needed
   // only for relevant settings of stencilflag and growflag
   // grow atom array for this list to current size of perpetual lists
 
   if (lists[i]->stencilflag) {
     lists[i]->stencil_allocate(smax,style);
     (this->*stencil_create[i])(lists[i],sx,sy,sz);
   }
 
   if (lists[i]->growflag) lists[i]->grow(maxatom);
 
   if (style != NSQ && atom->nmax > maxbin) {
     maxbin = atom->nmax;
     memory->destroy(bins);
     memory->create(bins,maxbin,"bins");
   }
 
   // check that neighbor list with special bond flags will not overflow
 
   if (atom->nlocal+atom->nghost > NEIGHMASK)
     error->one(FLERR,"Too many local+ghost atoms for neighbor list");
 
   // when occasional list built, LAMMPS can crash if atoms have moved too far
   // why is this?, give warning if this is the case
   // no easy workaround b/c all neighbor lists really need to be rebuilt
   // solution is for input script to check more often for rebuild
   // only check_distance if running a simulation, not between simulations
 
   int flag = 0;
   if (dist_check && update->whichflag) flag = check_distance();
   if (flag && me == 0)
     error->warning(FLERR,"Building an occasional neighobr list when "
                    "atoms may have moved too far");
 
   (this->*pair_build[i])(lists[i]);
 }
 
 /* ----------------------------------------------------------------------
    setup neighbor binning parameters
    bin numbering in each dimension is global:
      0 = 0.0 to binsize, 1 = binsize to 2*binsize, etc
      nbin-1,nbin,etc = bbox-binsize to bbox, bbox to bbox+binsize, etc
      -1,-2,etc = -binsize to 0.0, -2*binsize to -binsize, etc
    code will work for any binsize
      since next(xyz) and stencil extend as far as necessary
      binsize = 1/2 of cutoff is roughly optimal
    for orthogonal boxes:
      a dim must be filled exactly by integer # of bins
      in periodic, procs on both sides of PBC must see same bin boundary
      in non-periodic, coord2bin() still assumes this by use of nbin xyz
    for triclinic boxes:
      tilted simulation box cannot contain integer # of bins
      stencil & neigh list built differently to account for this
    mbinlo = lowest global bin any of my ghost atoms could fall into
    mbinhi = highest global bin any of my ghost atoms could fall into
    mbin = number of bins I need in a dimension
 ------------------------------------------------------------------------- */
 
 void Neighbor::setup_bins()
 {
   // bbox = size of bbox of entire domain
   // bsubbox lo/hi = bounding box of my subdomain extended by comm->cutghost
   // for triclinic:
   //   bbox bounds all 8 corners of tilted box
   //   subdomain is in lamda coords
   //   include dimension-dependent extension via comm->cutghost
   //   domain->bbox() converts lamda extent to box coords and computes bbox
 
   double bbox[3],bsubboxlo[3],bsubboxhi[3];
   double *cutghost = comm->cutghost;
 
   if (triclinic == 0) {
     bsubboxlo[0] = domain->sublo[0] - cutghost[0];
     bsubboxlo[1] = domain->sublo[1] - cutghost[1];
     bsubboxlo[2] = domain->sublo[2] - cutghost[2];
     bsubboxhi[0] = domain->subhi[0] + cutghost[0];
     bsubboxhi[1] = domain->subhi[1] + cutghost[1];
     bsubboxhi[2] = domain->subhi[2] + cutghost[2];
   } else {
     double lo[3],hi[3];
     lo[0] = domain->sublo_lamda[0] - cutghost[0];
     lo[1] = domain->sublo_lamda[1] - cutghost[1];
     lo[2] = domain->sublo_lamda[2] - cutghost[2];
     hi[0] = domain->subhi_lamda[0] + cutghost[0];
     hi[1] = domain->subhi_lamda[1] + cutghost[1];
     hi[2] = domain->subhi_lamda[2] + cutghost[2];
     domain->bbox(lo,hi,bsubboxlo,bsubboxhi);
   }
 
   bbox[0] = bboxhi[0] - bboxlo[0];
   bbox[1] = bboxhi[1] - bboxlo[1];
   bbox[2] = bboxhi[2] - bboxlo[2];
 
   // optimal bin size is roughly 1/2 the cutoff
   // for BIN style, binsize = 1/2 of max neighbor cutoff
   // for MULTI style, binsize = 1/2 of min neighbor cutoff
   // special case of all cutoffs = 0.0, binsize = box size
 
   double binsize_optimal;
   if (binsizeflag) binsize_optimal = binsize_user;
   else if (style == BIN) binsize_optimal = 0.5*cutneighmax;
   else binsize_optimal = 0.5*cutneighmin;
   if (binsize_optimal == 0.0) binsize_optimal = bbox[0];
   double binsizeinv = 1.0/binsize_optimal;
 
   // test for too many global bins in any dimension due to huge global domain
 
   if (bbox[0]*binsizeinv > MAXSMALLINT || bbox[1]*binsizeinv > MAXSMALLINT ||
       bbox[2]*binsizeinv > MAXSMALLINT)
     error->all(FLERR,"Domain too large for neighbor bins");
 
   // create actual bins
   // always have one bin even if cutoff > bbox
   // for 2d, nbinz = 1
 
   nbinx = static_cast<int> (bbox[0]*binsizeinv);
   nbiny = static_cast<int> (bbox[1]*binsizeinv);
   if (dimension == 3) nbinz = static_cast<int> (bbox[2]*binsizeinv);
   else nbinz = 1;
 
   if (nbinx == 0) nbinx = 1;
   if (nbiny == 0) nbiny = 1;
   if (nbinz == 0) nbinz = 1;
 
   // compute actual bin size for nbins to fit into box exactly
   // error if actual bin size << cutoff, since will create a zillion bins
   // this happens when nbin = 1 and box size << cutoff
   // typically due to non-periodic, flat system in a particular dim
   // in that extreme case, should use NSQ not BIN neighbor style
 
   binsizex = bbox[0]/nbinx;
   binsizey = bbox[1]/nbiny;
   binsizez = bbox[2]/nbinz;
 
   bininvx = 1.0 / binsizex;
   bininvy = 1.0 / binsizey;
   bininvz = 1.0 / binsizez;
 
   if (binsize_optimal*bininvx > CUT2BIN_RATIO ||
       binsize_optimal*bininvy > CUT2BIN_RATIO ||
       binsize_optimal*bininvz > CUT2BIN_RATIO)
     error->all(FLERR,"Cannot use neighbor bins - box size << cutoff");
 
   // mbinlo/hi = lowest and highest global bins my ghost atoms could be in
   // coord = lowest and highest values of coords for my ghost atoms
   // static_cast(-1.5) = -1, so subract additional -1
   // add in SMALL for round-off safety
 
   int mbinxhi,mbinyhi,mbinzhi;
   double coord;
 
   coord = bsubboxlo[0] - SMALL*bbox[0];
   mbinxlo = static_cast<int> ((coord-bboxlo[0])*bininvx);
   if (coord < bboxlo[0]) mbinxlo = mbinxlo - 1;
   coord = bsubboxhi[0] + SMALL*bbox[0];
   mbinxhi = static_cast<int> ((coord-bboxlo[0])*bininvx);
 
   coord = bsubboxlo[1] - SMALL*bbox[1];
   mbinylo = static_cast<int> ((coord-bboxlo[1])*bininvy);
   if (coord < bboxlo[1]) mbinylo = mbinylo - 1;
   coord = bsubboxhi[1] + SMALL*bbox[1];
   mbinyhi = static_cast<int> ((coord-bboxlo[1])*bininvy);
 
   if (dimension == 3) {
     coord = bsubboxlo[2] - SMALL*bbox[2];
     mbinzlo = static_cast<int> ((coord-bboxlo[2])*bininvz);
     if (coord < bboxlo[2]) mbinzlo = mbinzlo - 1;
     coord = bsubboxhi[2] + SMALL*bbox[2];
     mbinzhi = static_cast<int> ((coord-bboxlo[2])*bininvz);
   }
 
   // extend bins by 1 to insure stencil extent is included
   // if 2d, only 1 bin in z
 
   mbinxlo = mbinxlo - 1;
   mbinxhi = mbinxhi + 1;
   mbinx = mbinxhi - mbinxlo + 1;
 
   mbinylo = mbinylo - 1;
   mbinyhi = mbinyhi + 1;
   mbiny = mbinyhi - mbinylo + 1;
 
   if (dimension == 3) {
     mbinzlo = mbinzlo - 1;
     mbinzhi = mbinzhi + 1;
   } else mbinzlo = mbinzhi = 0;
   mbinz = mbinzhi - mbinzlo + 1;
 
   // memory for bin ptrs
 
   bigint bbin = ((bigint) mbinx) * ((bigint) mbiny) * ((bigint) mbinz);
   if (bbin > MAXSMALLINT) error->one(FLERR,"Too many neighbor bins");
   mbins = bbin;
   if (mbins > maxhead) {
     maxhead = mbins;
     memory->destroy(binhead);
     memory->create(binhead,maxhead,"neigh:binhead");
   }
 
   // create stencil of bins to search over in neighbor list construction
   // sx,sy,sz = max range of stencil in each dim
   // smax = max possible size of entire 3d stencil
   // stencil is empty if cutneighmax = 0.0
 
   sx = static_cast<int> (cutneighmax*bininvx);
   if (sx*binsizex < cutneighmax) sx++;
   sy = static_cast<int> (cutneighmax*bininvy);
   if (sy*binsizey < cutneighmax) sy++;
   sz = static_cast<int> (cutneighmax*bininvz);
   if (sz*binsizez < cutneighmax) sz++;
   if (dimension == 2) sz = 0;
   smax = (2*sx+1) * (2*sy+1) * (2*sz+1);
 
   // create stencils for pairwise neighbor lists
   // only done for lists with stencilflag and buildflag set
 
   for (int i = 0; i < nslist; i++) {
     lists[slist[i]]->stencil_allocate(smax,style);
     (this->*stencil_create[slist[i]])(lists[slist[i]],sx,sy,sz);
   }
 }
 
 /* ----------------------------------------------------------------------
    compute closest distance between central bin (0,0,0) and bin (i,j,k)
 ------------------------------------------------------------------------- */
 
 double Neighbor::bin_distance(int i, int j, int k)
 {
   double delx,dely,delz;
 
   if (i > 0) delx = (i-1)*binsizex;
   else if (i == 0) delx = 0.0;
   else delx = (i+1)*binsizex;
 
   if (j > 0) dely = (j-1)*binsizey;
   else if (j == 0) dely = 0.0;
   else dely = (j+1)*binsizey;
 
   if (k > 0) delz = (k-1)*binsizez;
   else if (k == 0) delz = 0.0;
   else delz = (k+1)*binsizez;
 
   return (delx*delx + dely*dely + delz*delz);
 }
 
 /* ----------------------------------------------------------------------
    set neighbor style and skin distance
 ------------------------------------------------------------------------- */
 
 void Neighbor::set(int narg, char **arg)
 {
   if (narg != 2) error->all(FLERR,"Illegal neighbor command");
 
   skin = force->numeric(FLERR,arg[0]);
   if (skin < 0.0) error->all(FLERR,"Illegal neighbor command");
 
   if (strcmp(arg[1],"nsq") == 0) style = NSQ;
   else if (strcmp(arg[1],"bin") == 0) style = BIN;
   else if (strcmp(arg[1],"multi") == 0) style = MULTI;
   else error->all(FLERR,"Illegal neighbor command");
 
   if (style == MULTI) citeme->add(CiteMe::INTVELD_2008);
 }
 
 /* ----------------------------------------------------------------------
    modify parameters of the pair-wise neighbor build
 ------------------------------------------------------------------------- */
 
 void Neighbor::modify_params(int narg, char **arg)
 {
   int iarg = 0;
   while (iarg < narg) {
     if (strcmp(arg[iarg],"every") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal neigh_modify command");
       every = force->inumeric(FLERR,arg[iarg+1]);
       if (every <= 0) error->all(FLERR,"Illegal neigh_modify command");
       iarg += 2;
     } else if (strcmp(arg[iarg],"delay") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal neigh_modify command");
       delay = force->inumeric(FLERR,arg[iarg+1]);
       if (delay < 0) error->all(FLERR,"Illegal neigh_modify command");
       iarg += 2;
     } else if (strcmp(arg[iarg],"check") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal neigh_modify command");
       if (strcmp(arg[iarg+1],"yes") == 0) dist_check = 1;
       else if (strcmp(arg[iarg+1],"no") == 0) dist_check = 0;
       else error->all(FLERR,"Illegal neigh_modify command");
       iarg += 2;
     } else if (strcmp(arg[iarg],"once") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal neigh_modify command");
       if (strcmp(arg[iarg+1],"yes") == 0) build_once = 1;
       else if (strcmp(arg[iarg+1],"no") == 0) build_once = 0;
       else error->all(FLERR,"Illegal neigh_modify command");
       iarg += 2;
     } else if (strcmp(arg[iarg],"page") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal neigh_modify command");
+      old_pgsize = pgsize;
       pgsize = force->inumeric(FLERR,arg[iarg+1]);
       iarg += 2;
     } else if (strcmp(arg[iarg],"one") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal neigh_modify command");
+      old_oneatom = oneatom;
       oneatom = force->inumeric(FLERR,arg[iarg+1]);
       iarg += 2;
     } else if (strcmp(arg[iarg],"binsize") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal neigh_modify command");
       binsize_user = force->numeric(FLERR,arg[iarg+1]);
       if (binsize_user <= 0.0) binsizeflag = 0;
       else binsizeflag = 1;
       iarg += 2;
     } else if (strcmp(arg[iarg],"cluster") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal neigh_modify command");
       if (strcmp(arg[iarg+1],"yes") == 0) cluster_check = 1;
       else if (strcmp(arg[iarg+1],"no") == 0) cluster_check = 0;
       else error->all(FLERR,"Illegal neigh_modify command");
       iarg += 2;
 
     } else if (strcmp(arg[iarg],"include") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal neigh_modify command");
       includegroup = group->find(arg[iarg+1]);
       if (includegroup < 0)
         error->all(FLERR,"Invalid group ID in neigh_modify command");
       if (includegroup && (atom->firstgroupname == NULL ||
                             strcmp(arg[iarg+1],atom->firstgroupname) != 0))
         error->all(FLERR,
                    "Neigh_modify include group != atom_modify first group");
       iarg += 2;
 
     } else if (strcmp(arg[iarg],"exclude") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal neigh_modify command");
 
       if (strcmp(arg[iarg+1],"type") == 0) {
         if (iarg+4 > narg) error->all(FLERR,"Illegal neigh_modify command");
         if (nex_type == maxex_type) {
           maxex_type += EXDELTA;
           memory->grow(ex1_type,maxex_type,"neigh:ex1_type");
           memory->grow(ex2_type,maxex_type,"neigh:ex2_type");
         }
         ex1_type[nex_type] = force->inumeric(FLERR,arg[iarg+2]);
         ex2_type[nex_type] = force->inumeric(FLERR,arg[iarg+3]);
         nex_type++;
         iarg += 4;
 
       } else if (strcmp(arg[iarg+1],"group") == 0) {
         if (iarg+4 > narg) error->all(FLERR,"Illegal neigh_modify command");
         if (nex_group == maxex_group) {
           maxex_group += EXDELTA;
           memory->grow(ex1_group,maxex_group,"neigh:ex1_group");
           memory->grow(ex2_group,maxex_group,"neigh:ex2_group");
         }
         ex1_group[nex_group] = group->find(arg[iarg+2]);
         ex2_group[nex_group] = group->find(arg[iarg+3]);
         if (ex1_group[nex_group] == -1 || ex2_group[nex_group] == -1)
           error->all(FLERR,"Invalid group ID in neigh_modify command");
         nex_group++;
         iarg += 4;
 
       } else if (strcmp(arg[iarg+1],"molecule") == 0) {
         if (iarg+3 > narg) error->all(FLERR,"Illegal neigh_modify command");
         if (atom->molecule_flag == 0)
           error->all(FLERR,"Neigh_modify exclude molecule "
                      "requires atom attribute molecule");
         if (nex_mol == maxex_mol) {
           maxex_mol += EXDELTA;
           memory->grow(ex_mol_group,maxex_mol,"neigh:ex_mol_group");
         }
         ex_mol_group[nex_mol] = group->find(arg[iarg+2]);
         if (ex_mol_group[nex_mol] == -1)
           error->all(FLERR,"Invalid group ID in neigh_modify command");
         nex_mol++;
         iarg += 3;
 
       } else if (strcmp(arg[iarg+1],"none") == 0) {
         nex_type = nex_group = nex_mol = 0;
         iarg += 2;
 
       } else error->all(FLERR,"Illegal neigh_modify command");
 
     } else error->all(FLERR,"Illegal neigh_modify command");
   }
 }
 
 /* ----------------------------------------------------------------------
    bin owned and ghost atoms
 ------------------------------------------------------------------------- */
 
 void Neighbor::bin_atoms()
 {
   int i,ibin;
 
   for (i = 0; i < mbins; i++) binhead[i] = -1;
 
   // bin in reverse order so linked list will be in forward order
   // also puts ghost atoms at end of list, which is necessary
 
   double **x = atom->x;
   int *mask = atom->mask;
   int nlocal = atom->nlocal;
   int nall = nlocal + atom->nghost;
 
   if (includegroup) {
     int bitmask = group->bitmask[includegroup];
     for (i = nall-1; i >= nlocal; i--) {
       if (mask[i] & bitmask) {
         ibin = coord2bin(x[i]);
         bins[i] = binhead[ibin];
         binhead[ibin] = i;
       }
     }
     for (i = atom->nfirst-1; i >= 0; i--) {
       ibin = coord2bin(x[i]);
       bins[i] = binhead[ibin];
       binhead[ibin] = i;
     }
 
   } else {
     for (i = nall-1; i >= 0; i--) {
       ibin = coord2bin(x[i]);
       bins[i] = binhead[ibin];
       binhead[ibin] = i;
     }
   }
 }
 
 /* ----------------------------------------------------------------------
    convert atom coords into local bin #
    for orthogonal, only ghost atoms will have coord >= bboxhi or coord < bboxlo
      take special care to insure ghosts are in correct bins even w/ roundoff
      hi ghost atoms = nbin,nbin+1,etc
      owned atoms = 0 to nbin-1
      lo ghost atoms = -1,-2,etc
      this is necessary so that both procs on either side of PBC
        treat a pair of atoms straddling the PBC in a consistent way
    for triclinic, doesn't matter since stencil & neigh list built differently
 ------------------------------------------------------------------------- */
 
 int Neighbor::coord2bin(double *x)
 {
   int ix,iy,iz;
 
   if (x[0] >= bboxhi[0])
     ix = static_cast<int> ((x[0]-bboxhi[0])*bininvx) + nbinx;
   else if (x[0] >= bboxlo[0]) {
     ix = static_cast<int> ((x[0]-bboxlo[0])*bininvx);
     ix = MIN(ix,nbinx-1);
   } else
     ix = static_cast<int> ((x[0]-bboxlo[0])*bininvx) - 1;
 
   if (x[1] >= bboxhi[1])
     iy = static_cast<int> ((x[1]-bboxhi[1])*bininvy) + nbiny;
   else if (x[1] >= bboxlo[1]) {
     iy = static_cast<int> ((x[1]-bboxlo[1])*bininvy);
     iy = MIN(iy,nbiny-1);
   } else
     iy = static_cast<int> ((x[1]-bboxlo[1])*bininvy) - 1;
 
   if (x[2] >= bboxhi[2])
     iz = static_cast<int> ((x[2]-bboxhi[2])*bininvz) + nbinz;
   else if (x[2] >= bboxlo[2]) {
     iz = static_cast<int> ((x[2]-bboxlo[2])*bininvz);
     iz = MIN(iz,nbinz-1);
   } else
     iz = static_cast<int> ((x[2]-bboxlo[2])*bininvz) - 1;
 
   return (iz-mbinzlo)*mbiny*mbinx + (iy-mbinylo)*mbinx + (ix-mbinxlo);
 }
 
 /* ----------------------------------------------------------------------
    same as coord2bin, but also return ix,iy,iz offsets in each dim
 ------------------------------------------------------------------------- */
 
 int Neighbor::coord2bin(double *x, int &ix, int &iy, int &iz)
 {
   if (x[0] >= bboxhi[0])
     ix = static_cast<int> ((x[0]-bboxhi[0])*bininvx) + nbinx;
   else if (x[0] >= bboxlo[0]) {
     ix = static_cast<int> ((x[0]-bboxlo[0])*bininvx);
     ix = MIN(ix,nbinx-1);
   } else
     ix = static_cast<int> ((x[0]-bboxlo[0])*bininvx) - 1;
 
   if (x[1] >= bboxhi[1])
     iy = static_cast<int> ((x[1]-bboxhi[1])*bininvy) + nbiny;
   else if (x[1] >= bboxlo[1]) {
     iy = static_cast<int> ((x[1]-bboxlo[1])*bininvy);
     iy = MIN(iy,nbiny-1);
   } else
     iy = static_cast<int> ((x[1]-bboxlo[1])*bininvy) - 1;
 
   if (x[2] >= bboxhi[2])
     iz = static_cast<int> ((x[2]-bboxhi[2])*bininvz) + nbinz;
   else if (x[2] >= bboxlo[2]) {
     iz = static_cast<int> ((x[2]-bboxlo[2])*bininvz);
     iz = MIN(iz,nbinz-1);
   } else
     iz = static_cast<int> ((x[2]-bboxlo[2])*bininvz) - 1;
 
   ix -= mbinxlo;
   iy -= mbinylo;
   iz -= mbinzlo;
   return iz*mbiny*mbinx + iy*mbinx + ix;
 }
 
 /* ----------------------------------------------------------------------
    test if atom pair i,j is excluded from neighbor list
    due to type, group, molecule settings from neigh_modify command
    return 1 if should be excluded, 0 if included
 ------------------------------------------------------------------------- */
 
 int Neighbor::exclusion(int i, int j, int itype, int jtype,
                         int *mask, int *molecule) const {
   int m;
 
   if (nex_type && ex_type[itype][jtype]) return 1;
 
   if (nex_group) {
     for (m = 0; m < nex_group; m++) {
       if (mask[i] & ex1_bit[m] && mask[j] & ex2_bit[m]) return 1;
       if (mask[i] & ex2_bit[m] && mask[j] & ex1_bit[m]) return 1;
     }
   }
 
   if (nex_mol) {
     for (m = 0; m < nex_mol; m++)
       if (mask[i] & ex_mol_bit[m] && mask[j] & ex_mol_bit[m] &&
           molecule[i] == molecule[j]) return 1;
   }
 
   return 0;
 }
 
 /* ----------------------------------------------------------------------
    return # of bytes of allocated memory
 ------------------------------------------------------------------------- */
 
 bigint Neighbor::memory_usage()
 {
   bigint bytes = 0;
   bytes += memory->usage(xhold,maxhold,3);
 
   if (style != NSQ) {
     bytes += memory->usage(bins,maxbin);
     bytes += memory->usage(binhead,maxhead);
   }
 
   for (int i = 0; i < nlist; i++) bytes += lists[i]->memory_usage();
 
   bytes += memory->usage(bondlist,maxbond,3);
   bytes += memory->usage(anglelist,maxangle,4);
   bytes += memory->usage(dihedrallist,maxdihedral,5);
   bytes += memory->usage(improperlist,maximproper,5);
 
   return bytes;
 }
 
 /* ----------------------------------------------------------------------
    return the value of exclude - used to check compatibility with GPU
 ------------------------------------------------------------------------- */
 
 int Neighbor::exclude_setting()
 {
   return exclude;
 }
diff --git a/src/neighbor.h b/src/neighbor.h
index 2c58eb18d..13590dd47 100644
--- a/src/neighbor.h
+++ b/src/neighbor.h
@@ -1,405 +1,407 @@
 /* -*- c++ -*- ----------------------------------------------------------
    LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
    http://lammps.sandia.gov, Sandia National Laboratories
    Steve Plimpton, sjplimp@sandia.gov
 
    Copyright (2003) Sandia Corporation.  Under the terms of Contract
    DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
    certain rights in this software.  This software is distributed under
    the GNU General Public License.
 
    See the README file in the top-level LAMMPS directory.
 ------------------------------------------------------------------------- */
 
 #ifndef LMP_NEIGHBOR_H
 #define LMP_NEIGHBOR_H
 
 #include "pointers.h"
 
 namespace LAMMPS_NS {
 
 class Neighbor : protected Pointers {
   friend class Cuda;
 
  public:
   int style;                       // 0,1,2 = nsq, bin, multi
   int every;                       // build every this many steps
   int delay;                       // delay build for this many steps
   int dist_check;                  // 0 = always build, 1 = only if 1/2 dist
   int ago;                         // how many steps ago neighboring occurred
   int pgsize;                      // size of neighbor page
   int oneatom;                     // max # of neighbors for one atom
   int includegroup;                // only build pairwise lists for this group
   int build_once;                  // 1 if only build lists once per run
   int cudable;                     // GPU <-> CPU communication flag for CUDA
 
   double skin;                     // skin distance
   double cutneighmin;              // min neighbor cutoff for all type pairs
   double cutneighmax;              // max neighbor cutoff for all type pairs
   double *cuttype;                 // for each type, max neigh cut w/ others
 
   bigint ncalls;                   // # of times build has been called
   bigint ndanger;                  // # of dangerous builds
   bigint lastcall;                 // timestep of last neighbor::build() call
 
   int nrequest;                    // requests for pairwise neighbor lists
   class NeighRequest **requests;   // from Pair, Fix, Compute, Command classes
   int maxrequest;
 
   int old_style;                   // previous run info to avoid
   int old_nrequest;                // re-creation of pairwise neighbor lists
   int old_triclinic;
+  int old_pgsize;
+  int old_oneatom;
   class NeighRequest **old_requests;
 
   int nlist;                       // pairwise neighbor lists
   class NeighList **lists;
 
   int nbondlist;                   // list of bonds to compute
   int **bondlist;
   int nanglelist;                  // list of angles to compute
   int **anglelist;
   int ndihedrallist;               // list of dihedrals to compute
   int **dihedrallist;
   int nimproperlist;               // list of impropers to compute
   int **improperlist;
 
   Neighbor(class LAMMPS *);
   virtual ~Neighbor();
   virtual void init();
   int request(void *);              // another class requests a neighbor list
   void print_lists_of_lists();      // debug print out
   int decide();                     // decide whether to build or not
   virtual int check_distance();     // check max distance moved since last build
   void setup_bins();                // setup bins based on box and cutoff
   virtual void build(int topoflag=1);  // create all neighbor lists (pair,bond)
   virtual void build_topology();    // create all topology neighbor lists
   void build_one(int);              // create a single neighbor list
   void set(int, char **);           // set neighbor style and skin distance
   void modify_params(int, char**);  // modify parameters that control builds
   bigint memory_usage();
   int exclude_setting();
 
  protected:
   int me,nprocs;
 
   int maxatom;                     // size of atom-based NeighList arrays
   int maxbond,maxangle,maxdihedral,maximproper;   // size of bond lists
   int maxwt;                       // max weighting factor applied + 1
 
   int must_check;                  // 1 if must check other classes to reneigh
   int restart_check;               // 1 if restart enabled, 0 if no
   int fix_check;                   // # of fixes that induce reneigh
   int *fixchecklist;               // which fixes to check
 
   double **cutneighsq;             // neighbor cutneigh sq for each type pair
   double **cutneighghostsq;        // neighbor cutnsq for each ghost type pair
   double cutneighmaxsq;            // cutneighmax squared
   double *cuttypesq;               // cuttype squared
 
   double triggersq;                // trigger = build when atom moves this dist
   int cluster_check;               // 1 if check bond/angle/etc satisfies minimg
 
   double **xhold;                      // atom coords at last neighbor build
   int maxhold;                         // size of xhold array
   int boxcheck;                        // 1 if need to store box size
   double boxlo_hold[3],boxhi_hold[3];  // box size at last neighbor build
   double corners_hold[8][3];           // box corners at last neighbor build
 
   int nbinx,nbiny,nbinz;           // # of global bins
   int *bins;                       // ptr to next atom in each bin
   int maxbin;                      // size of bins array
 
   int *binhead;                    // ptr to 1st atom in each bin
   int maxhead;                     // size of binhead array
 
   int mbins;                       // # of local bins and offset
   int mbinx,mbiny,mbinz;
   int mbinxlo,mbinylo,mbinzlo;
 
   int binsizeflag;                 // user-chosen bin size
   double binsize_user;
 
   double binsizex,binsizey,binsizez;  // actual bin sizes and inverse sizes
   double bininvx,bininvy,bininvz;
 
   int sx,sy,sz,smax;               // bin stencil extents
 
   int dimension;                   // 2/3 for 2d/3d
   int triclinic;                   // 0 if domain is orthog, 1 if triclinic
   int newton_pair;                 // 0 if newton off, 1 if on for pairwise
 
   double *bboxlo,*bboxhi;          // ptrs to full domain bounding box
   double (*corners)[3];            // ptr to 8 corners of triclinic box
 
   double inner[2],middle[2];       // rRESPA cutoffs for extra lists
   double cut_inner_sq;                   // outer cutoff for inner neighbor list
   double cut_middle_sq;            // outer cutoff for middle neighbor list
   double cut_middle_inside_sq;     // inner cutoff for middle neighbor list
 
   int special_flag[4];             // flags for 1-2, 1-3, 1-4 neighbors
 
   int anyghostlist;                // 1 if any non-occasional list
                                    // stores neighbors of ghosts
 
   int exclude;                     // 0 if no type/group exclusions, 1 if yes
 
   int nex_type;                    // # of entries in type exclusion list
   int maxex_type;                  // max # in type list
   int *ex1_type,*ex2_type;         // pairs of types to exclude
   int **ex_type;                   // 2d array of excluded type pairs
 
   int nex_group;                   // # of entries in group exclusion list
   int maxex_group;                 // max # in group list
   int *ex1_group,*ex2_group;       // pairs of group #'s to exclude
   int *ex1_bit,*ex2_bit;           // pairs of group bits to exclude
 
   int nex_mol;                     // # of entries in molecule exclusion list
   int maxex_mol;                   // max # in molecule list
   int *ex_mol_group;               // molecule group #'s to exclude
   int *ex_mol_bit;                 // molecule group bits to exclude
 
   int nblist,nglist,nslist;    // # of pairwise neigh lists of various kinds
   int *blist;                  // lists to build every reneighboring
   int *glist;                  // lists to grow atom arrays every reneigh
   int *slist;                  // lists to grow stencil arrays every reneigh
 
   void bin_atoms();                     // bin all atoms
   double bin_distance(int, int, int);   // distance between binx
   int coord2bin(double *);              // mapping atom coord to a bin
   int coord2bin(double *, int &, int &, int&); // ditto
 
   int exclusion(int, int, int,
                 int, int *, int *) const;  // test for pair exclusion
 
   virtual void choose_build(int, class NeighRequest *);
   void choose_stencil(int, class NeighRequest *);
 
   // pairwise build functions
 
   typedef void (Neighbor::*PairPtr)(class NeighList *);
   PairPtr *pair_build;
 
   void half_nsq_no_newton(class NeighList *);
   void half_nsq_no_newton_ghost(class NeighList *);
   void half_nsq_newton(class NeighList *);
 
   void half_bin_no_newton(class NeighList *);
   void half_bin_no_newton_ghost(class NeighList *);
   void half_bin_newton(class NeighList *);
   void half_bin_newton_tri(class NeighList *);
 
   void half_multi_no_newton(class NeighList *);
   void half_multi_newton(class NeighList *);
   void half_multi_newton_tri(class NeighList *);
 
   void full_nsq(class NeighList *);
   void full_nsq_ghost(class NeighList *);
   void full_bin(class NeighList *);
   void full_bin_ghost(class NeighList *);
   void full_multi(class NeighList *);
 
   void half_from_full_no_newton(class NeighList *);
   void half_from_full_newton(class NeighList *);
   void skip_from(class NeighList *);
   void skip_from_granular(class NeighList *);
   void skip_from_respa(class NeighList *);
   void copy_from(class NeighList *);
 
   void granular_nsq_no_newton(class NeighList *);
   void granular_nsq_newton(class NeighList *);
   void granular_bin_no_newton(class NeighList *);
   void granular_bin_newton(class NeighList *);
   void granular_bin_newton_tri(class NeighList *);
 
   void respa_nsq_no_newton(class NeighList *);
   void respa_nsq_newton(class NeighList *);
   void respa_bin_no_newton(class NeighList *);
   void respa_bin_newton(class NeighList *);
   void respa_bin_newton_tri(class NeighList *);
 
   // include prototypes for multi-threaded neighbor lists
   // builds or their corresponding dummy versions
 
 #define LMP_INSIDE_NEIGHBOR_H
 #include "accelerator_omp.h"
 #undef LMP_INSIDE_NEIGHBOR_H
 
   // pairwise stencil creation functions
 
   typedef void (Neighbor::*StencilPtr)(class NeighList *, int, int, int);
   StencilPtr *stencil_create;
 
   void stencil_half_bin_2d_no_newton(class NeighList *, int, int, int);
   void stencil_half_ghost_bin_2d_no_newton(class NeighList *, int, int, int);
   void stencil_half_bin_3d_no_newton(class NeighList *, int, int, int);
   void stencil_half_ghost_bin_3d_no_newton(class NeighList *, int, int, int);
   void stencil_half_bin_2d_newton(class NeighList *, int, int, int);
   void stencil_half_bin_3d_newton(class NeighList *, int, int, int);
   void stencil_half_bin_2d_newton_tri(class NeighList *, int, int, int);
   void stencil_half_bin_3d_newton_tri(class NeighList *, int, int, int);
 
   void stencil_half_multi_2d_no_newton(class NeighList *, int, int, int);
   void stencil_half_multi_3d_no_newton(class NeighList *, int, int, int);
   void stencil_half_multi_2d_newton(class NeighList *, int, int, int);
   void stencil_half_multi_3d_newton(class NeighList *, int, int, int);
   void stencil_half_multi_2d_newton_tri(class NeighList *, int, int, int);
   void stencil_half_multi_3d_newton_tri(class NeighList *, int, int, int);
 
   void stencil_full_bin_2d(class NeighList *, int, int, int);
   void stencil_full_ghost_bin_2d(class NeighList *, int, int, int);
   void stencil_full_bin_3d(class NeighList *, int, int, int);
   void stencil_full_ghost_bin_3d(class NeighList *, int, int, int);
   void stencil_full_multi_2d(class NeighList *, int, int, int);
   void stencil_full_multi_3d(class NeighList *, int, int, int);
 
   // topology build functions
 
   typedef void (Neighbor::*BondPtr)();   // ptrs to topology build functions
 
   BondPtr bond_build;                 // ptr to bond list functions
   void bond_all();                    // bond list with all bonds
   void bond_partial();                // exclude certain bonds
   void bond_check();
 
   BondPtr angle_build;                // ptr to angle list functions
   void angle_all();                   // angle list with all angles
   void angle_partial();               // exclude certain angles
   void angle_check();
 
   BondPtr dihedral_build;             // ptr to dihedral list functions
   void dihedral_all();                // dihedral list with all dihedrals
   void dihedral_partial();            // exclude certain dihedrals
   void dihedral_check(int, int **);
 
   BondPtr improper_build;             // ptr to improper list functions
   void improper_all();                // improper list with all impropers
   void improper_partial();            // exclude certain impropers
 
   // find_special: determine if atom j is in special list of atom i
   // if it is not, return 0
   // if it is and special flag is 0 (both coeffs are 0.0), return -1
   // if it is and special flag is 1 (both coeffs are 1.0), return 0
   // if it is and special flag is 2 (otherwise), return 1,2,3
   //   for which level of neighbor it is (and which coeff it maps to)
 
   inline int find_special(const int *list, const int *nspecial,
                           const int tag) const {
     const int n1 = nspecial[0];
     const int n2 = nspecial[1];
     const int n3 = nspecial[2];
 
     for (int i = 0; i < n3; i++) {
       if (list[i] == tag) {
         if (i < n1) {
           if (special_flag[1] == 0) return -1;
           else if (special_flag[1] == 1) return 0;
           else return 1;
         } else if (i < n2) {
           if (special_flag[2] == 0) return -1;
           else if (special_flag[2] == 1) return 0;
           else return 2;
         } else {
           if (special_flag[3] == 0) return -1;
           else if (special_flag[3] == 1) return 0;
           else return 3;
         }
       }
     }
     return 0;
   };
 };
 
 }
 
 #endif
 
 /* ERROR/WARNING messages:
 
 E: Neighbor delay must be 0 or multiple of every setting
 
 The delay and every parameters set via the neigh_modify command are
 inconsistent.  If the delay setting is non-zero, then it must be a
 multiple of the every setting.
 
 E: Neighbor page size must be >= 10x the one atom setting
 
 This is required to prevent wasting too much memory.
 
 E: Invalid atom type in neighbor exclusion list
 
 Atom types must range from 1 to Ntypes inclusive.
 
 W: Neighbor exclusions used with KSpace solver may give inconsistent Coulombic energies
 
 This is because excluding specific pair interactions also excludes
 them from long-range interactions which may not be the desired effect.
 The special_bonds command handles this consistently by insuring
 excluded (or weighted) 1-2, 1-3, 1-4 interactions are treated
 consistently by both the short-range pair style and the long-range
 solver.  This is not done for exclusions of charged atom pairs via the
 neigh_modify exclude command.
 
 E: Neighbor include group not allowed with ghost neighbors
 
 This is a current restriction within LAMMPS.
 
 E: Neighbor multi not yet enabled for ghost neighbors
 
 This is a current restriction within LAMMPS.
 
 E: Neighbor multi not yet enabled for granular
 
 Self-explanatory.
 
 E: Neighbor multi not yet enabled for rRESPA
 
 Self-explanatory.
 
 E: Too many local+ghost atoms for neighbor list
 
 The number of nlocal + nghost atoms on a processor
 is limited by the size of a 32-bit integer with 2 bits
 removed for masking 1-2, 1-3, 1-4 neighbors.
 
 W: Building an occasional neighobr list when atoms may have moved too far
 
 This can cause LAMMPS to crash when the neighbor list is built.
 The solution is to check for building the regular neighbor lists
 more frequently.
 
 E: Domain too large for neighbor bins
 
 The domain has become extremely large so that neighbor bins cannot be
 used.  Most likely, one or more atoms have been blown out of the
 simulation box to a great distance.
 
 E: Cannot use neighbor bins - box size << cutoff
 
 Too many neighbor bins will be created.  This typically happens when
 the simulation box is very small in some dimension, compared to the
 neighbor cutoff.  Use the "nsq" style instead of "bin" style.
 
 E: Too many neighbor bins
 
 This is likely due to an immense simulation box that has blown up
 to a large size.
 
 E: Illegal ... command
 
 Self-explanatory.  Check the input script syntax and compare to the
 documentation for the command.  You can use -echo screen as a
 command-line option when running LAMMPS to see the offending line.
 
 E: Invalid group ID in neigh_modify command
 
 A group ID used in the neigh_modify command does not exist.
 
 E: Neigh_modify include group != atom_modify first group
 
 Self-explanatory.
 
 E: Neigh_modify exclude molecule requires atom attribute molecule
 
 Self-explanatory.
 
 */