diff --git a/src/REPLICA/neb.cpp b/src/REPLICA/neb.cpp
index b3d08373b..8cb0be746 100644
--- a/src/REPLICA/neb.cpp
+++ b/src/REPLICA/neb.cpp
@@ -1,611 +1,616 @@
 /* ----------------------------------------------------------------------
    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.
 ------------------------------------------------------------------------- */
 
+// lmptype.h must be first b/c this file uses MAXBIGINT and includes mpi.h
+// due to OpenMPI bug which sets INT64_MAX via its mpi.h
+//   before lmptype.h can set flags to insure it is done correctly
+
+#include "lmptype.h" 
 #include "mpi.h"
 #include "math.h"
 #include "stdlib.h"
 #include "string.h"
 #include "neb.h"
 #include "universe.h"
 #include "atom.h"
 #include "update.h"
 #include "domain.h"
 #include "comm.h"
 #include "min.h"
 #include "modify.h"
 #include "fix.h"
 #include "fix_neb.h"
 #include "output.h"
 #include "thermo.h"
 #include "finish.h"
 #include "timer.h"
 #include "memory.h"
 #include "error.h"
 #include "force.h"
 
 using namespace LAMMPS_NS;
 
 #define MAXLINE 256
 #define CHUNK 1024
 #define ATTRIBUTE_PERLINE 4
 
 /* ---------------------------------------------------------------------- */
 
 NEB::NEB(LAMMPS *lmp) : Pointers(lmp) {}
 
 /* ----------------------------------------------------------------------
    internal NEB constructor, called from TAD
 ------------------------------------------------------------------------- */
 
 NEB::NEB(LAMMPS *lmp, double etol_in, double ftol_in, int n1steps_in,
          int n2steps_in, int nevery_in, double *buf_init, double *buf_final)
   : Pointers(lmp)
 {
   double delx,dely,delz;
 
   etol = etol_in;
   ftol = ftol_in;
   n1steps = n1steps_in;
   n2steps = n2steps_in;
   nevery = nevery_in;
 
   // replica info
 
   nreplica = universe->nworlds;
   ireplica = universe->iworld;
   me_universe = universe->me;
   uworld = universe->uworld;
   MPI_Comm_rank(world,&me);
 
   // generate linear interpolate replica
 
   double fraction = ireplica/(nreplica-1.0);
 
   double **x = atom->x;
   int nlocal = atom->nlocal;
 
   int ii = 0;
   for (int i = 0; i < nlocal; i++) {
     delx = buf_final[ii] - buf_init[ii];
     dely = buf_final[ii+1] - buf_init[ii+1];
     delz = buf_final[ii+2] - buf_init[ii+2];
     domain->minimum_image(delx,dely,delz);
     x[i][0] = buf_init[ii] + fraction*delx;
     x[i][1] = buf_init[ii+1] + fraction*dely;
     x[i][2] = buf_init[ii+2] + fraction*delz;
     ii += 3;
   }
 }
 
 /* ---------------------------------------------------------------------- */
 
 NEB::~NEB()
 {
   MPI_Comm_free(&roots);
   memory->destroy(all);
   delete [] rdist;
 }
 
 /* ----------------------------------------------------------------------
    perform NEB on multiple replicas
 ------------------------------------------------------------------------- */
 
 void NEB::command(int narg, char **arg)
 {
   if (domain->box_exist == 0)
     error->all(FLERR,"NEB command before simulation box is defined");
 
   if (narg < 6) error->universe_all(FLERR,"Illegal NEB command");
 
   etol = force->numeric(FLERR,arg[0]);
   ftol = force->numeric(FLERR,arg[1]);
   n1steps = force->inumeric(FLERR,arg[2]);
   n2steps = force->inumeric(FLERR,arg[3]);
   nevery = force->inumeric(FLERR,arg[4]);
 
   // error checks
 
   if (etol < 0.0) error->all(FLERR,"Illegal NEB command");
   if (ftol < 0.0) error->all(FLERR,"Illegal NEB command");
   if (nevery == 0) error->universe_all(FLERR,"Illegal NEB command");
   if (n1steps % nevery || n2steps % nevery)
     error->universe_all(FLERR,"Illegal NEB command");
 
   // replica info
 
   nreplica = universe->nworlds;
   ireplica = universe->iworld;
   me_universe = universe->me;
   uworld = universe->uworld;
   MPI_Comm_rank(world,&me);
 
   // error checks
 
   if (nreplica == 1) error->all(FLERR,"Cannot use NEB with a single replica");
   if (nreplica != universe->nprocs)
     error->all(FLERR,"Can only use NEB with 1-processor replicas");
   if (atom->sortfreq > 0)
     error->all(FLERR,"Cannot use NEB with atom_modify sort enabled");
   if (atom->map_style == 0)
     error->all(FLERR,"Cannot use NEB unless atom map exists");
 
   // process file-style setting to setup initial configs for all replicas
 
   if (strcmp(arg[5],"final") == 0) {
     if (narg != 7) error->universe_all(FLERR,"Illegal NEB command");
     infile = arg[6];
     readfile(infile,0);
   } else if (strcmp(arg[5],"each") == 0) {
     if (narg != 7) error->universe_all(FLERR,"Illegal NEB command");
     infile = arg[6];
     readfile(infile,1);
   } else if (strcmp(arg[5],"none") == 0) {
     if (narg != 6) error->universe_all(FLERR,"Illegal NEB command");
   } else error->universe_all(FLERR,"Illegal NEB command");
 
   // run the NEB calculation
 
   run();
 }
 
 /* ----------------------------------------------------------------------
    run NEB on multiple replicas
 ------------------------------------------------------------------------- */
 
 void NEB::run()
 {
   // create MPI communicator for root proc from each world
 
   int color;
   if (me == 0) color = 0;
   else color = 1;
   MPI_Comm_split(uworld,color,0,&roots);
 
   int ineb;
   for (ineb = 0; ineb < modify->nfix; ineb++)
     if (strcmp(modify->fix[ineb]->style,"neb") == 0) break;
   if (ineb == modify->nfix) error->all(FLERR,"NEB requires use of fix neb");
 
   fneb = (FixNEB *) modify->fix[ineb];
   nall = 4;
   memory->create(all,nreplica,nall,"neb:all");
   rdist = new double[nreplica];
 
   // initialize LAMMPS
 
   update->whichflag = 2;
   update->etol = etol;
   update->ftol = ftol;
   update->multireplica = 1;
 
   lmp->init();
 
   if (update->minimize->searchflag)
     error->all(FLERR,"NEB requires damped dynamics minimizer");
 
   // setup regular NEB minimization
 
   if (me_universe == 0 && universe->uscreen)
     fprintf(universe->uscreen,"Setting up regular NEB ...\n");
 
   update->beginstep = update->firststep = update->ntimestep;
   update->endstep = update->laststep = update->firststep + n1steps;
   update->nsteps = n1steps;
   update->max_eval = n1steps;
   if (update->laststep < 0 || update->laststep > MAXBIGINT)
     error->all(FLERR,"Too many timesteps for NEB");
 
   update->minimize->setup();
 
   if (me_universe == 0) {
     if (universe->uscreen)
       fprintf(universe->uscreen,"Step MaxReplicaForce MaxAtomForce "
               "GradV0 GradV1 GradVc "
               "EBF EBR RDT "
               "RD1 PE1 RD2 PE2 ... RDN PEN\n");
     if (universe->ulogfile)
       fprintf(universe->ulogfile,"Step MaxReplicaForce MaxAtomForce "
               "GradV0 GradV1 GradVc "
               "EBF EBR RDT "
               "RD1 PE1 RD2 PE2 ... RDN PEN\n");
   }
   print_status();
 
   // perform regular NEB for n1steps or until replicas converge
   // retrieve PE values from fix NEB and print every nevery iterations
   // break induced if converged
   // damped dynamic min styles insure all replicas converge together
 
   timer->init();
   timer->barrier_start();
 
   while (update->minimize->niter < n1steps) {
     update->minimize->run(nevery);
     print_status();
     if (update->minimize->stop_condition) break;
   }
 
   timer->barrier_stop();
 
   update->minimize->cleanup();
 
   Finish finish(lmp);
   finish.end(1);
 
   // switch fix NEB to climbing mode
   // top = replica that becomes hill climber
 
   double vmax = all[0][0];
   int top = 0;
   for (int m = 1; m < nreplica; m++)
     if (vmax < all[m][0]) {
       vmax = all[m][0];
       top = m;
     }
 
   // setup climbing NEB minimization
   // must reinitialize minimizer so it re-creates its fix MINIMIZE
 
   if (me_universe == 0 && universe->uscreen)
     fprintf(universe->uscreen,"Setting up climbing ...\n");
 
   if (me_universe == 0) {
     if (universe->uscreen)
       fprintf(universe->uscreen,"Climbing replica = %d\n",top+1);
     if (universe->ulogfile)
       fprintf(universe->ulogfile,"Climbing replica = %d\n",top+1);
   }
 
   update->beginstep = update->firststep = update->ntimestep;
   update->endstep = update->laststep = update->firststep + n2steps;
   update->nsteps = n2steps;
   update->max_eval = n2steps;
   if (update->laststep < 0 || update->laststep > MAXBIGINT)
     error->all(FLERR,"Too many timesteps");
 
   update->minimize->init();
   fneb->rclimber = top;
   update->minimize->setup();
 
   if (me_universe == 0) {
     if (universe->uscreen)
       fprintf(universe->uscreen,"Step MaxReplicaForce MaxAtomForce "
               "GradV0 GradV1 GradVc "
               "EBF EBR RDT "
               "RD1 PE1 RD2 PE2 ... RDN PEN\n");
     if (universe->ulogfile)
       fprintf(universe->ulogfile,"Step MaxReplicaForce MaxAtomForce "
               "GradV0 GradV1 GradVc "
               "EBF EBR RDT "
               "RD1 PE1 RD2 PE2 ... RDN PEN\n");
   }
   print_status();
 
   // perform climbing NEB for n2steps or until replicas converge
   // retrieve PE values from fix NEB and print every nevery iterations
   // break induced if converged
   // damped dynamic min styles insure all replicas converge together
 
   timer->init();
   timer->barrier_start();
 
   while (update->minimize->niter < n2steps) {
     update->minimize->run(nevery);
     print_status();
     if (update->minimize->stop_condition) break;
   }
 
   timer->barrier_stop();
 
   update->minimize->cleanup();
 
   finish.end(1);
 
   update->whichflag = 0;
   update->multireplica = 0;
   update->firststep = update->laststep = 0;
   update->beginstep = update->endstep = 0;
 }
 
 /* ----------------------------------------------------------------------
    read initial config atom coords from file
    flag = 0
      only first replica opens file and reads it
      first replica bcasts lines to all replicas
      final replica stores coords
      intermediate replicas interpolate from coords
        new coord = replica fraction between current and final state
      initial replica does nothing
    flag = 1
      each replica (except first) opens file and reads it
      each replica stores coords
      initial replica does nothing
 ------------------------------------------------------------------------- */
 
 void NEB::readfile(char *file, int flag)
 {
   int i,j,m,nchunk,eofflag,nlines;
   tagint tag;
   char *eof,*start,*next,*buf;
   char line[MAXLINE];
   double xx,yy,zz,delx,dely,delz;
 
   if (me_universe == 0 && screen)
     fprintf(screen,"Reading NEB coordinate file(s) ...\n");
 
   // flag = 0, universe root reads header of file, bcast to universe
   // flag = 1, each replica's root reads header of file, bcast to world
   //   but explicitly skip first replica
 
   if (flag == 0) {
     if (me_universe == 0) {
       open(file);
       while (1) {
         eof = fgets(line,MAXLINE,fp);
         if (eof == NULL) error->one(FLERR,"Unexpected end of neb file");
         start = &line[strspn(line," \t\n\v\f\r")];
         if (*start != '\0' && *start != '#') break;
       }
       sscanf(line,"%d",&nlines);
     }
     MPI_Bcast(&nlines,1,MPI_INT,0,uworld);
 
   } else {
     if (me == 0) {
       if (ireplica) {
         open(file);
         while (1) {
           eof = fgets(line,MAXLINE,fp);
           if (eof == NULL) error->one(FLERR,"Unexpected end of neb file");
           start = &line[strspn(line," \t\n\v\f\r")];
           if (*start != '\0' && *start != '#') break;
         }
         sscanf(line,"%d",&nlines);
       } else nlines = 0;
     }
     MPI_Bcast(&nlines,1,MPI_INT,0,world);
   }
 
   char *buffer = new char[CHUNK*MAXLINE];
   char **values = new char*[ATTRIBUTE_PERLINE];
 
   double fraction = ireplica/(nreplica-1.0);
 
   double **x = atom->x;
   int nlocal = atom->nlocal;
 
   // loop over chunks of lines read from file
   // two versions of read_lines_from_file() for world vs universe bcast
   // count # of atom coords changed so can check for invalid atom IDs in file
 
   int ncount = 0;
 
   int nread = 0;
   while (nread < nlines) {
     nchunk = MIN(nlines-nread,CHUNK);
     if (flag == 0)
       eofflag = comm->read_lines_from_file_universe(fp,nchunk,MAXLINE,buffer);
     else
       eofflag = comm->read_lines_from_file(fp,nchunk,MAXLINE,buffer);
     if (eofflag) error->all(FLERR,"Unexpected end of neb file");
 
     buf = buffer;
     next = strchr(buf,'\n');
     *next = '\0';
     int nwords = atom->count_words(buf);
     *next = '\n';
 
     if (nwords != ATTRIBUTE_PERLINE)
       error->all(FLERR,"Incorrect atom format in neb file");
 
     // loop over lines of atom coords
     // tokenize the line into values
 
     for (i = 0; i < nchunk; i++) {
       next = strchr(buf,'\n');
       
       values[0] = strtok(buf," \t\n\r\f");
       for (j = 1; j < nwords; j++)
         values[j] = strtok(NULL," \t\n\r\f");
       
       // adjust atom coord based on replica fraction
       // for flag = 0, interpolate for intermediate and final replicas
       // for flag = 1, replace existing coord with new coord
       // ignore image flags of final x
       // for interpolation:
       //   new x is displacement from old x via minimum image convention
       //   if final x is across periodic boundary:
       //     new x may be outside box
       //     will be remapped back into box when simulation starts
       //     its image flags will then be adjusted
 
       tag = ATOTAGINT(values[0]);
       m = atom->map(tag);
       if (m >= 0 && m < nlocal) {
         ncount++;
         xx = atof(values[1]);
         yy = atof(values[2]);
         zz = atof(values[3]);
 
         if (flag == 0) {
           delx = xx - x[m][0];
           dely = yy - x[m][1];
           delz = zz - x[m][2];
           domain->minimum_image(delx,dely,delz);
           x[m][0] += fraction*delx;
           x[m][1] += fraction*dely;
           x[m][2] += fraction*delz;
         } else {
           x[m][0] = xx;
           x[m][1] = yy;
           x[m][2] = zz;
         }
       }
 
       buf = next + 1;
     }
 
     nread += nchunk;
   }
 
   // check that all atom IDs in file were found by a proc
 
   if (flag == 0) {
     int ntotal;
     MPI_Allreduce(&ncount,&ntotal,1,MPI_INT,MPI_SUM,uworld);
     if (ntotal != nreplica*nlines)
       error->universe_all(FLERR,"Invalid atom IDs in neb file");
   } else {
     int ntotal;
     MPI_Allreduce(&ncount,&ntotal,1,MPI_INT,MPI_SUM,world);
     if (ntotal != nlines)
       error->all(FLERR,"Invalid atom IDs in neb file");
   }
 
   // clean up
 
   delete [] buffer;
   delete [] values;
 
   if (flag == 0) {
     if (me_universe == 0) {
       if (compressed) pclose(fp);
       else fclose(fp);
     }
   } else {
     if (me == 0 && ireplica) {
       if (compressed) pclose(fp);
       else fclose(fp);
     }
   }
 }
 
 /* ----------------------------------------------------------------------
    universe proc 0 opens NEB data file
    test if gzipped
 ------------------------------------------------------------------------- */
 
 void NEB::open(char *file)
 {
   compressed = 0;
   char *suffix = file + strlen(file) - 3;
   if (suffix > file && strcmp(suffix,".gz") == 0) compressed = 1;
   if (!compressed) fp = fopen(file,"r");
   else {
 #ifdef LAMMPS_GZIP
     char gunzip[128];
     sprintf(gunzip,"gzip -c -d %s",file);
 
 #ifdef _WIN32
     fp = _popen(gunzip,"rb");
 #else
     fp = popen(gunzip,"r");
 #endif
 
 #else
     error->one(FLERR,"Cannot open gzipped file");
 #endif
   }
 
   if (fp == NULL) {
     char str[128];
     sprintf(str,"Cannot open file %s",file);
     error->one(FLERR,str);
   }
 }
 
 /* ----------------------------------------------------------------------
    query fix NEB for info on each replica
    proc 0 prints current NEB status
 ------------------------------------------------------------------------- */
 
 void NEB::print_status()
 {
   double fnorm2 = sqrt(update->minimize->fnorm_sqr());
   double fmaxreplica;
   MPI_Allreduce(&fnorm2,&fmaxreplica,1,MPI_DOUBLE,MPI_MAX,roots);
   double fnorminf = update->minimize->fnorm_inf();
   double fmaxatom;
   MPI_Allreduce(&fnorminf,&fmaxatom,1,MPI_DOUBLE,MPI_MAX,roots);
 
   double one[4];
   one[0] = fneb->veng;
   one[1] = fneb->plen;
   one[2] = fneb->nlen;
   one[nall-1] = fneb->gradvnorm;
 
   if (output->thermo->normflag) one[0] /= atom->natoms;
   if (me == 0)
     MPI_Allgather(one,nall,MPI_DOUBLE,&all[0][0],nall,MPI_DOUBLE,roots);
 
   rdist[0] = 0.0;
   for (int i = 1; i < nreplica; i++)
     rdist[i] = rdist[i-1] + all[i][1];
   double endpt = rdist[nreplica-1] = rdist[nreplica-2] + all[nreplica-2][2];
   for (int i = 1; i < nreplica; i++)
     rdist[i] /= endpt;
 
   // look up GradV for the initial, final, and climbing replicas
   // these are identical to fnorm2, but to be safe we
   // take them straight from fix_neb
 
   double gradvnorm0, gradvnorm1, gradvnormc;
 
   int irep;
   irep = 0;
   gradvnorm0 = all[irep][3];
   irep = nreplica-1;
   gradvnorm1 = all[irep][3];
   irep = fneb->rclimber;
   if (irep > -1) {
     gradvnormc = all[irep][3];
     ebf = all[irep][0]-all[0][0];
     ebr = all[irep][0]-all[nreplica-1][0];
   } else {
     double vmax = all[0][0];
     int top = 0;
     for (int m = 1; m < nreplica; m++)
       if (vmax < all[m][0]) {
         vmax = all[m][0];
         top = m;
       }
     irep = top;
     gradvnormc = all[irep][3];
     ebf = all[irep][0]-all[0][0];
     ebr = all[irep][0]-all[nreplica-1][0];
   }
 
   if (me_universe == 0) {
     if (universe->uscreen) {
       fprintf(universe->uscreen,BIGINT_FORMAT " %12.8g %12.8g ",
               update->ntimestep,fmaxreplica,fmaxatom);
       fprintf(universe->uscreen,"%12.8g %12.8g %12.8g ",
               gradvnorm0,gradvnorm1,gradvnormc);
       fprintf(universe->uscreen,"%12.8g %12.8g %12.8g ",ebf,ebr,endpt);
       for (int i = 0; i < nreplica; i++)
         fprintf(universe->uscreen,"%12.8g %12.8g ",rdist[i],all[i][0]);
       fprintf(universe->uscreen,"\n");
     }
     if (universe->ulogfile) {
       fprintf(universe->ulogfile,BIGINT_FORMAT " %12.8g %12.8g ",
               update->ntimestep,fmaxreplica,fmaxatom);
       fprintf(universe->ulogfile,"%12.8g %12.8g %12.8g ",
               gradvnorm0,gradvnorm1,gradvnormc);
       fprintf(universe->ulogfile,"%12.8g %12.8g %12.8g ",ebf,ebr,endpt);
       for (int i = 0; i < nreplica; i++)
         fprintf(universe->ulogfile,"%12.8g %12.8g ",rdist[i],all[i][0]);
       fprintf(universe->ulogfile,"\n");
       fflush(universe->ulogfile);
     }
   }
 }
diff --git a/src/REPLICA/prd.cpp b/src/REPLICA/prd.cpp
index 383d07dfd..35fb181a7 100644
--- a/src/REPLICA/prd.cpp
+++ b/src/REPLICA/prd.cpp
@@ -1,903 +1,908 @@
 /* ----------------------------------------------------------------------
    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: Mike Brown (SNL)
 ------------------------------------------------------------------------- */
 
+// lmptype.h must be first b/c this file uses MAXBIGINT and includes mpi.h
+// due to OpenMPI bug which sets INT64_MAX via its mpi.h
+//   before lmptype.h can set flags to insure it is done correctly
+
+#include "lmptype.h" 
 #include "mpi.h"
 #include "math.h"
 #include "stdlib.h"
 #include "string.h"
 #include "prd.h"
 #include "universe.h"
 #include "update.h"
 #include "atom.h"
 #include "domain.h"
 #include "region.h"
 #include "comm.h"
 #include "velocity.h"
 #include "integrate.h"
 #include "min.h"
 #include "neighbor.h"
 #include "modify.h"
 #include "compute.h"
 #include "fix.h"
 #include "fix_event_prd.h"
 #include "force.h"
 #include "pair.h"
 #include "random_park.h"
 #include "random_mars.h"
 #include "output.h"
 #include "dump.h"
 #include "finish.h"
 #include "timer.h"
 #include "memory.h"
 #include "error.h"
 
 using namespace LAMMPS_NS;
 
 /* ---------------------------------------------------------------------- */
 
 PRD::PRD(LAMMPS *lmp) : Pointers(lmp) {}
 
 /* ----------------------------------------------------------------------
    perform PRD simulation on one or more replicas
 ------------------------------------------------------------------------- */
 
 void PRD::command(int narg, char **arg)
 {
   int ireplica;
 
   // error checks
 
   if (domain->box_exist == 0)
     error->all(FLERR,"PRD command before simulation box is defined");
   if (universe->nworlds != universe->nprocs &&
       atom->map_style == 0)
     error->all(FLERR,"Cannot use PRD with multi-processor replicas "
                "unless atom map exists");
   if (universe->nworlds == 1 && comm->me == 0)
     error->warning(FLERR,"Running PRD with only one replica");
 
   if (narg < 7) error->universe_all(FLERR,"Illegal prd command");
 
   // read as double so can cast to bigint
 
   int nsteps = force->inumeric(FLERR,arg[0]);
   t_event = force->inumeric(FLERR,arg[1]);
   n_dephase = force->inumeric(FLERR,arg[2]);
   t_dephase = force->inumeric(FLERR,arg[3]);
   t_corr = force->inumeric(FLERR,arg[4]);
 
   char *id_compute = new char[strlen(arg[5])+1];
   strcpy(id_compute,arg[5]);
   int seed = force->inumeric(FLERR,arg[6]);
 
   options(narg-7,&arg[7]);
 
   // total # of timesteps must be multiple of t_event
 
   if (t_event <= 0) error->universe_all(FLERR,"Invalid t_event in prd command");
   if (nsteps % t_event)
     error->universe_all(FLERR,"PRD nsteps must be multiple of t_event");
   if (t_corr % t_event)
     error->universe_all(FLERR,"PRD t_corr must be multiple of t_event");
 
   // local storage
 
   int me_universe = universe->me;
   int nprocs_universe = universe->nprocs;
   int nreplica = universe->nworlds;
   int iworld = universe->iworld;
 
   MPI_Comm_rank(world,&me);
   MPI_Comm_size(world,&nprocs);
 
   // comm_replica = communicator between all proc 0s across replicas
 
   int color = me;
   MPI_Comm_split(universe->uworld,color,0,&comm_replica);
 
   // equal_size_replicas = 1 if all replicas have same # of procs
   // no longer used
 
   //flag = 0;
   //if (nreplica*nprocs == nprocs_universe) flag = 1;
   //MPI_Allreduce(&flag,&equal_size_replicas,1,MPI_INT,MPI_MIN,
   //              universe->uworld);
 
   // workspace for inter-replica communication via gathers
 
   natoms = atom->natoms;
 
   displacements = NULL;
   tagall = NULL;
   xall = NULL;
   imageall = NULL;
 
   if (nreplica != nprocs_universe) {
     displacements = new int[nprocs];
     memory->create(tagall,natoms,"prd:tagall");
     memory->create(xall,natoms,3,"prd:xall");
     memory->create(imageall,natoms,"prd:imageall");
   }
 
   // random_select = same RNG for each replica, for multiple event selection
   // random_clock = same RNG for each replica, for clock updates
   // random_dephase = unique RNG for each replica, for dephasing
 
   random_select = new RanPark(lmp,seed);
   random_clock = new RanPark(lmp,seed+1000);
   random_dephase = new RanMars(lmp,seed+iworld);
 
   // create ComputeTemp class to monitor temperature
 
   char **args = new char*[3];
   args[0] = (char *) "prd_temp";
   args[1] = (char *) "all";
   args[2] = (char *) "temp";
   modify->add_compute(3,args);
   temperature = modify->compute[modify->ncompute-1];
 
   // create Velocity class for velocity creation in dephasing
   // pass it temperature compute, loop_setting, dist_setting settings
 
   atom->check_mass();
   velocity = new Velocity(lmp);
   velocity->init_external("all");
 
   args[0] = (char *) "temp";
   args[1] = (char *) "prd_temp";
   velocity->options(2,args);
   args[0] = (char *) "loop";
   args[1] = (char *) loop_setting;
   if (loop_setting) velocity->options(2,args);
   args[0] = (char *) "dist";
   args[1] = (char *) dist_setting;
   if (dist_setting) velocity->options(2,args);
 
   // create FixEventPRD class to store event and pre-quench states
 
   args[0] = (char *) "prd_event";
   args[1] = (char *) "all";
   args[2] = (char *) "EVENT/PRD";
   modify->add_fix(3,args);
   fix_event = (FixEventPRD *) modify->fix[modify->nfix-1];
 
   // create Finish for timing output
 
   finish = new Finish(lmp);
 
   // string clean-up
 
   delete [] args;
   delete [] loop_setting;
   delete [] dist_setting;
 
   // assign FixEventPRD to event-detection compute
   // necessary so it will know atom coords at last event
 
   int icompute = modify->find_compute(id_compute);
   if (icompute < 0) error->all(FLERR,"Could not find compute ID for PRD");
   compute_event = modify->compute[icompute];
   compute_event->reset_extra_compute_fix("prd_event");
 
   // reset reneighboring criteria since will perform minimizations
 
   neigh_every = neighbor->every;
   neigh_delay = neighbor->delay;
   neigh_dist_check = neighbor->dist_check;
 
   if (neigh_every != 1 || neigh_delay != 0 || neigh_dist_check != 1) {
     if (me == 0)
       error->warning(FLERR,"Resetting reneighboring criteria during PRD");
   }
 
   neighbor->every = 1;
   neighbor->delay = 0;
   neighbor->dist_check = 1;
 
   // initialize PRD as if one long dynamics run
 
   update->whichflag = 1;
   update->nsteps = nsteps;
   update->beginstep = update->firststep = update->ntimestep;
   update->endstep = update->laststep = update->firststep + nsteps;
   update->restrict_output = 1;
   if (update->laststep < 0 || update->laststep > MAXBIGINT)
     error->all(FLERR,"Too many timesteps");
 
   lmp->init();
 
   // init minimizer settings and minimizer itself
 
   update->etol = etol;
   update->ftol = ftol;
   update->max_eval = maxeval;
 
   update->minimize->init();
 
   // cannot use PRD with a changing box
 
   if (domain->box_change)
     error->all(FLERR,"Cannot use PRD with a changing box");
 
   // cannot use PRD with time-dependent fixes or regions or atom sorting
 
   for (int i = 0; i < modify->nfix; i++)
     if (modify->fix[i]->time_depend)
       error->all(FLERR,"Cannot use PRD with a time-dependent fix defined");
 
   for (int i = 0; i < domain->nregion; i++)
     if (domain->regions[i]->dynamic_check())
       error->all(FLERR,"Cannot use PRD with a time-dependent region defined");
 
   if (atom->sortfreq > 0)
     error->all(FLERR,"Cannot use PRD with atom_modify sort enabled");
 
   // perform PRD simulation
 
   if (me_universe == 0 && universe->uscreen)
     fprintf(universe->uscreen,"Setting up PRD ...\n");
 
   if (me_universe == 0) {
     if (universe->uscreen)
       fprintf(universe->uscreen,"Step CPU Clock Event "
               "Correlated Coincident Replica\n");
     if (universe->ulogfile)
       fprintf(universe->ulogfile,"Step CPU Clock Event "
               "Correlated Coincident Replica\n");
   }
 
   // store hot state and quenched event for replica 0
   // use share_event() to copy that info to all replicas
   // this insures all start from same place
 
   // need this line if quench() does only setup_minimal()
   // update->minimize->setup();
 
   fix_event->store_state_quench();
   quench();
   ncoincident = 0;
   share_event(0,0,0);
 
   timer->init();
   timer->barrier_start();
   time_start = timer->get_wall(Timer::TOTAL);
 
   log_event();
 
   // do full init/setup since are starting all replicas after event
   // replica 0 bcasts temp to all replicas if temp_dephase is not set
 
   update->whichflag = 1;
   lmp->init();
   update->integrate->setup();
 
   if (temp_flag == 0) {
     if (universe->iworld == 0) temp_dephase = temperature->compute_scalar();
     MPI_Bcast(&temp_dephase,1,MPI_DOUBLE,universe->root_proc[0],
               universe->uworld);
   }
 
   // main loop: look for events until out of time
   // (1) dephase independently on each proc after event
   // (2) loop: dynamics, store state, quench, check event, restore state
   // (3) share and record event
 
   nbuild = ndanger = 0;
   time_dephase = time_dynamics = time_quench = time_comm = time_output = 0.0;
   bigint clock = 0;
 
   timer->barrier_start();
   time_start = timer->get_wall(Timer::TOTAL);
 
   int istep = 0;
 
   while (istep < nsteps) {
     dephase();
 
     if (stepmode == 0) istep = update->ntimestep - update->beginstep;
     else istep = clock;
 
     ireplica = -1;
     while (istep < nsteps) {
       dynamics(t_event,time_dynamics);
       fix_event->store_state_quench();
       quench();
       clock = clock + t_event*universe->nworlds;
       ireplica = check_event();
       if (ireplica >= 0) break;
       fix_event->restore_state_quench();
       if (stepmode == 0) istep = update->ntimestep - update->beginstep;
       else istep = clock;
     }
     if (ireplica < 0) break;
 
     // decrement clock by random time at which 1 or more events occurred
 
     int frac_t_event = t_event;
     for (int i = 0; i <= fix_event->ncoincident; i++) {
       int frac_rand = static_cast<int> (random_clock->uniform() * t_event);
       frac_t_event = MIN(frac_t_event,frac_rand);
     }
     int decrement = frac_t_event*universe->nworlds;
     clock -= decrement;
 
     // share event across replicas
     // NOTE: would be potentially more efficient for correlated events
     //   if don't share until correlated check below has completed
     // this will complicate the dump (always on replica 0)
 
     share_event(ireplica,1,decrement);
     log_event();
 
     int restart_flag = 0;
     if (output->restart_flag && universe->iworld == 0) {
       if (output->restart_every_single &&
           fix_event->event_number % output->restart_every_single == 0)
         restart_flag = 1;
       if (output->restart_every_double &&
           fix_event->event_number % output->restart_every_double == 0)
         restart_flag = 1;
     }
 
     // correlated event loop
     // other procs could be dephasing during this time
 
     int corr_endstep = update->ntimestep + t_corr;
     while (update->ntimestep < corr_endstep) {
       if (update->ntimestep == update->endstep) {
         restart_flag = 0;
         break;
       }
       dynamics(t_event,time_dynamics);
       fix_event->store_state_quench();
       quench();
       clock += t_event;
       int corr_event_check = check_event(ireplica);
       if (corr_event_check >= 0) {
         share_event(ireplica,2,0);
         log_event();
         corr_endstep = update->ntimestep + t_corr;
       } else fix_event->restore_state_quench();
     }
 
     // full init/setup since are starting all replicas after event
     // event replica bcasts temp to all replicas if temp_dephase is not set
 
     update->whichflag = 1;
     lmp->init();
     update->integrate->setup();
 
     timer->barrier_start();
 
     if (t_corr > 0) replicate(ireplica);
     if (temp_flag == 0) {
       if (ireplica == universe->iworld)
         temp_dephase = temperature->compute_scalar();
       MPI_Bcast(&temp_dephase,1,MPI_DOUBLE,universe->root_proc[ireplica],
                       universe->uworld);
     }
 
     timer->barrier_stop();
     time_comm += timer->get_wall(Timer::TOTAL);
 
     // write restart file of hot coords
 
     if (restart_flag) {
       timer->barrier_start();
       output->write_restart(update->ntimestep);
       timer->barrier_stop();
       time_output += timer->get_wall(Timer::TOTAL);
     }
 
     if (stepmode == 0) istep = update->ntimestep - update->beginstep;
     else istep = clock;
   }
 
   if (stepmode) nsteps = update->ntimestep - update->beginstep;
 
   // set total timers and counters so Finish() will process them
 
   timer->set_wall(Timer::TOTAL, time_start);
   timer->barrier_stop();
 
   timer->set_wall(Timer::DEPHASE, time_dephase);
   timer->set_wall(Timer::DYNAMICS, time_dynamics);
   timer->set_wall(Timer::QUENCH, time_quench);
   timer->set_wall(Timer::REPCOMM, time_comm);
   timer->set_wall(Timer::REPOUT, time_output);
 
   neighbor->ncalls = nbuild;
   neighbor->ndanger = ndanger;
 
   if (me_universe == 0) {
     if (universe->uscreen)
       fprintf(universe->uscreen,
               "Loop time of %g on %d procs for %d steps with " BIGINT_FORMAT 
               " atoms\n",
               timer->get_wall(Timer::TOTAL),nprocs_universe,nsteps,atom->natoms);
     if (universe->ulogfile)
       fprintf(universe->ulogfile,
               "Loop time of %g on %d procs for %d steps with " BIGINT_FORMAT 
               " atoms\n",
               timer->get_wall(Timer::TOTAL),nprocs_universe,nsteps,atom->natoms);
   }
 
   if (me == 0) {
     if (screen) fprintf(screen,"\nPRD done\n");
     if (logfile) fprintf(logfile,"\nPRD done\n");
   }
 
   finish->end(2);
 
   update->whichflag = 0;
   update->firststep = update->laststep = 0;
   update->beginstep = update->endstep = 0;
   update->restrict_output = 0;
 
   // reset reneighboring criteria
 
   neighbor->every = neigh_every;
   neighbor->delay = neigh_delay;
   neighbor->dist_check = neigh_dist_check;
 
   // clean up
 
   delete [] displacements;
   memory->destroy(tagall);
   memory->destroy(xall);
   memory->destroy(imageall);
 
   delete [] id_compute;
   MPI_Comm_free(&comm_replica);
   delete random_select;
   delete random_clock;
   delete random_dephase;
   delete velocity;
   delete finish;
   modify->delete_compute("prd_temp");
   modify->delete_fix("prd_event");
 
   compute_event->reset_extra_compute_fix(NULL);
 }
 
 /* ----------------------------------------------------------------------
    dephasing = one or more short runs with new random velocities
 ------------------------------------------------------------------------- */
 
 void PRD::dephase()
 {
   bigint ntimestep_hold = update->ntimestep;
 
   // n_dephase iterations of dephasing, each of t_dephase steps
 
   for (int i = 0; i < n_dephase; i++) {
 
     fix_event->store_state_dephase();
 
     // do not proceed to next iteration until an event-free run occurs
 
     int done = 0;
     while (!done) {
       int seed = static_cast<int> (random_dephase->uniform() * MAXSMALLINT);
       if (seed == 0) seed = 1;
       velocity->create(temp_dephase,seed);
 
       dynamics(t_dephase,time_dephase);
       fix_event->store_state_quench();
       quench();
 
       if (compute_event->compute_scalar() > 0.0) {
         fix_event->restore_state_dephase();
         update->ntimestep -= t_dephase;
       } else {
         fix_event->restore_state_quench();
         done = 1;
       }
 
       if (temp_flag == 0) temp_dephase = temperature->compute_scalar();
     }
   }
 
   // reset timestep as if dephase did not occur
   // clear timestep storage from computes, since now invalid
 
   update->ntimestep = ntimestep_hold;
   for (int i = 0; i < modify->ncompute; i++)
     if (modify->compute[i]->timeflag) modify->compute[i]->clearstep();
 }
 
 /* ----------------------------------------------------------------------
    short dynamics run: for event search, decorrelation, or dephasing
 ------------------------------------------------------------------------- */
 
 void PRD::dynamics(int nsteps, double &time_category)
 {
   update->whichflag = 1;
   update->nsteps = nsteps;
 
   lmp->init();
   update->integrate->setup();
   // this may be needed if don't do full init
   //modify->addstep_compute_all(update->ntimestep);
   bigint ncalls = neighbor->ncalls;
 
   timer->barrier_start();
   update->integrate->run(nsteps);
   timer->barrier_stop();
   time_category += timer->get_wall(Timer::TOTAL);
 
   nbuild += neighbor->ncalls - ncalls;
   ndanger += neighbor->ndanger;
 
   update->integrate->cleanup();
   finish->end(0);
 }
 
 /* ----------------------------------------------------------------------
    quench minimization
 ------------------------------------------------------------------------- */
 
 void PRD::quench()
 {
   bigint ntimestep_hold = update->ntimestep;
   bigint endstep_hold = update->endstep;
 
   // need to change whichflag so that minimize->setup() calling
   // modify->setup() will call fix->min_setup()
 
   update->whichflag = 2;
   update->nsteps = maxiter;
   update->endstep = update->laststep = update->firststep + maxiter;
   if (update->laststep < 0 || update->laststep > MAXBIGINT)
     error->all(FLERR,"Too many iterations");
 
   // full init works
 
   lmp->init();
   update->minimize->setup();
 
   // partial init does not work
 
   //modify->addstep_compute_all(update->ntimestep);
   //update->minimize->setup_minimal(1);
 
   int ncalls = neighbor->ncalls;
 
   timer->barrier_start();
   update->minimize->run(maxiter);
   timer->barrier_stop();
   time_quench += timer->get_wall(Timer::TOTAL);
 
   if (neighbor->ncalls == ncalls) quench_reneighbor = 0;
   else quench_reneighbor = 1;
 
   update->minimize->cleanup();
   finish->end(0);
 
   // reset timestep as if quench did not occur
   // clear timestep storage from computes, since now invalid
 
   update->ntimestep = ntimestep_hold;
   update->endstep = update->laststep = endstep_hold;
   for (int i = 0; i < modify->ncompute; i++)
     if (modify->compute[i]->timeflag) modify->compute[i]->clearstep();
 }
 
 /* ----------------------------------------------------------------------
    check for an event in any replica
    if replica_num is non-negative only check for event on replica_num
    if multiple events, choose one at random
    return -1 if no event
    else return ireplica = world in which event occured
 ------------------------------------------------------------------------- */
 
 int PRD::check_event(int replica_num)
 {
   int worldflag,universeflag,scanflag,replicaflag,ireplica;
 
   worldflag = 0;
   if (compute_event->compute_scalar() > 0.0) worldflag = 1;
   if (replica_num >= 0 && replica_num != universe->iworld) worldflag = 0;
 
   timer->barrier_start();
 
   if (me == 0) MPI_Allreduce(&worldflag,&universeflag,1,
                              MPI_INT,MPI_SUM,comm_replica);
   MPI_Bcast(&universeflag,1,MPI_INT,0,world);
 
   ncoincident = universeflag;
 
   if (!universeflag) ireplica = -1;
   else {
 
     // multiple events, choose one at random
     // iwhich = random # from 1 to N, N = # of events to choose from
     // scanflag = 1 to N on replicas with an event, 0 on non-event replicas
     // exit with worldflag = 1 on chosen replica, 0 on all others
     // note worldflag is already 0 on replicas that didn't perform event
 
     if (universeflag > 1) {
       int iwhich = static_cast<int>
         (universeflag*random_select->uniform()) + 1;
 
       if (me == 0)
         MPI_Scan(&worldflag,&scanflag,1,MPI_INT,MPI_SUM,comm_replica);
       MPI_Bcast(&scanflag,1,MPI_INT,0,world);
 
       if (scanflag != iwhich) worldflag = 0;
     }
 
     if (worldflag) replicaflag = universe->iworld;
     else replicaflag = 0;
 
     if (me == 0) MPI_Allreduce(&replicaflag,&ireplica,1,
                                MPI_INT,MPI_SUM,comm_replica);
     MPI_Bcast(&ireplica,1,MPI_INT,0,world);
   }
 
   timer->barrier_stop();
   time_comm += timer->get_wall(Timer::TOTAL);
 
   return ireplica;
 }
 
 /* ----------------------------------------------------------------------
    share quenched and hot coords owned by ireplica with all replicas
    all replicas store event in fix_event
    replica 0 dumps event snapshot
    flag = 0 = called before PRD run
    flag = 1 = called during PRD run = not correlated event
    flag = 2 = called during PRD run = correlated event
 ------------------------------------------------------------------------- */
 
 void PRD::share_event(int ireplica, int flag, int decrement)
 {
   timer->barrier_start();
 
   // communicate quenched coords to all replicas and store as event
   // decrement event counter if flag = 0 since not really an event
 
   replicate(ireplica);
   timer->barrier_stop();
   time_comm += timer->get_wall(Timer::TOTAL);
 
   // adjust time for last correlated event check (not on first event)
 
   int corr_adjust = t_corr;
   if (fix_event->event_number < 1 || flag == 2) corr_adjust = 0;
 
   // delta = time since last correlated event check
 
   int delta = update->ntimestep - fix_event->event_timestep - corr_adjust;
 
   // if this is a correlated event, time elapsed only on one partition
 
   if (flag != 2) delta *= universe->nworlds;
   if (delta > 0 && flag != 2) delta -= decrement;
   delta += corr_adjust;
   
   // delta passed to store_event_prd() should make its clock update
   //   be consistent with clock in main PRD loop
   // don't change the clock or timestep if this is a restart
 
   if (flag == 0 && fix_event->event_number != 0)
     fix_event->store_event_prd(fix_event->event_timestep,0);
   else {
     fix_event->store_event_prd(update->ntimestep,delta);
     fix_event->replica_number = ireplica;
     fix_event->correlated_event = 0;
     if (flag == 2) fix_event->correlated_event = 1;
     fix_event->ncoincident = ncoincident;
   }
   if (flag == 0) fix_event->event_number--;
 
   // dump snapshot of quenched coords, only on replica 0
   // must reneighbor and compute forces before dumping
   // since replica 0 possibly has new state from another replica
   // addstep_compute_all insures eng/virial are calculated if needed
 
   if (output->ndump && universe->iworld == 0) {
     timer->barrier_start();
     modify->addstep_compute_all(update->ntimestep);
     update->integrate->setup_minimal(1);
     output->write_dump(update->ntimestep);
     timer->barrier_stop();
     time_output += timer->get_wall(Timer::TOTAL);
   }
 
   // restore and communicate hot coords to all replicas
 
   fix_event->restore_state_quench();
   timer->barrier_start();
   replicate(ireplica);
   timer->barrier_stop();
   time_comm += timer->get_wall(Timer::TOTAL);
 }
 
 /* ----------------------------------------------------------------------
    universe proc 0 prints event info
 ------------------------------------------------------------------------- */
 
 void PRD::log_event()
 {
   timer->set_wall(Timer::TOTAL, time_start);
   if (universe->me == 0) {
     if (universe->uscreen)
       fprintf(universe->uscreen,
               BIGINT_FORMAT " %.3f " BIGINT_FORMAT " %d %d %d %d\n",
               fix_event->event_timestep,
               timer->elapsed(Timer::TOTAL),
               fix_event->clock,
               fix_event->event_number,fix_event->correlated_event,
               fix_event->ncoincident,
               fix_event->replica_number);
     if (universe->ulogfile)
       fprintf(universe->ulogfile,
               BIGINT_FORMAT " %.3f " BIGINT_FORMAT " %d %d %d %d\n",
               fix_event->event_timestep,
               timer->elapsed(Timer::TOTAL),
               fix_event->clock,
               fix_event->event_number,fix_event->correlated_event,
               fix_event->ncoincident,
               fix_event->replica_number);
   }
 }
 
 /* ----------------------------------------------------------------------
   communicate atom coords and image flags in ireplica to all other replicas
   one proc per replica:
     direct overwrite via bcast
   else atoms could be stored in different order or on different procs:
     collect to root proc of event replica
     bcast to roots of other replicas
     bcast within each replica
     each proc extracts info for atoms it owns using atom IDs
 ------------------------------------------------------------------------- */
 
 void PRD::replicate(int ireplica)
 {
   int nreplica = universe->nworlds;
   int nprocs_universe = universe->nprocs;
   int i,m;
 
   if (nreplica == nprocs_universe) {
     MPI_Bcast(atom->image,atom->nlocal,MPI_INT,ireplica,comm_replica);
     MPI_Bcast(atom->x[0],3*atom->nlocal,MPI_DOUBLE,ireplica,comm_replica);
 
   } else {
     int *counts = new int[nprocs];
 
     if (universe->iworld == ireplica) {
       MPI_Gather(&atom->nlocal,1,MPI_INT,counts,1,MPI_INT,0,world);
       displacements[0] = 0;
       for (i = 0; i < nprocs-1; i++)
         displacements[i+1] = displacements[i] + counts[i];
       MPI_Gatherv(atom->tag,atom->nlocal,MPI_LMP_TAGINT,
                   tagall,counts,displacements,MPI_LMP_TAGINT,0,world);
       MPI_Gatherv(atom->image,atom->nlocal,MPI_INT,
                         imageall,counts,displacements,MPI_INT,0,world);
       for (i = 0; i < nprocs; i++) counts[i] *= 3;
       for (i = 0; i < nprocs-1; i++)
         displacements[i+1] = displacements[i] + counts[i];
       MPI_Gatherv(atom->x[0],3*atom->nlocal,MPI_DOUBLE,
                         xall[0],counts,displacements,MPI_DOUBLE,0,world);
     }
 
     if (me == 0) {
       MPI_Bcast(tagall,natoms,MPI_INT,ireplica,comm_replica);
       MPI_Bcast(imageall,natoms,MPI_INT,ireplica,comm_replica);
       MPI_Bcast(xall[0],3*natoms,MPI_DOUBLE,ireplica,comm_replica);
     }
 
     MPI_Bcast(tagall,natoms,MPI_INT,0,world);
     MPI_Bcast(imageall,natoms,MPI_INT,0,world);
     MPI_Bcast(xall[0],3*natoms,MPI_DOUBLE,0,world);
 
     double **x = atom->x;
     int nlocal = atom->nlocal;
 
     for (i = 0; i < natoms; i++) {
       m = atom->map(tagall[i]);
       if (m >= 0 && m < nlocal) {
         x[m][0] = xall[i][0];
         x[m][1] = xall[i][1];
         x[m][2] = xall[i][2];
         atom->image[m] = imageall[i];
       }
     }
 
     delete [] counts;
   }
 }
 
 /* ----------------------------------------------------------------------
    parse optional parameters at end of PRD input line
 ------------------------------------------------------------------------- */
 
 void PRD::options(int narg, char **arg)
 {
   if (narg < 0) error->all(FLERR,"Illegal prd command");
 
   // set defaults
 
   etol = 0.1;
   ftol = 0.1;
   maxiter = 40;
   maxeval = 50;
   temp_flag = 0;
   stepmode = 0;
 
   char *str = (char *) "geom";
   int n = strlen(str) + 1;
   loop_setting = new char[n];
   strcpy(loop_setting,str);
 
   str = (char *) "gaussian";
   n = strlen(str) + 1;
   dist_setting = new char[n];
   strcpy(dist_setting,str);
 
   int iarg = 0;
   while (iarg < narg) {
     if (strcmp(arg[iarg],"min") == 0) {
       if (iarg+5 > narg) error->all(FLERR,"Illegal prd command");
       etol = force->numeric(FLERR,arg[iarg+1]);
       ftol = force->numeric(FLERR,arg[iarg+2]);
       maxiter = force->inumeric(FLERR,arg[iarg+3]);
       maxeval = force->inumeric(FLERR,arg[iarg+4]);
       if (maxiter < 0) error->all(FLERR,"Illegal prd command");
       iarg += 5;
 
     } else if (strcmp(arg[iarg],"temp") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal prd command");
       temp_flag = 1;
       temp_dephase = force->numeric(FLERR,arg[iarg+1]);
       if (temp_dephase <= 0.0) error->all(FLERR,"Illegal prd command");
       iarg += 2;
 
     } else if (strcmp(arg[iarg],"vel") == 0) {
       if (iarg+3 > narg) error->all(FLERR,"Illegal prd command");
       delete [] loop_setting;
       delete [] dist_setting;
 
       if (strcmp(arg[iarg+1],"all") == 0) loop_setting = NULL;
       else if (strcmp(arg[iarg+1],"local") == 0) loop_setting = NULL;
       else if (strcmp(arg[iarg+1],"geom") == 0) loop_setting = NULL;
       else error->all(FLERR,"Illegal prd command");
       int n = strlen(arg[iarg+1]) + 1;
       loop_setting = new char[n];
       strcpy(loop_setting,arg[iarg+1]);
 
       if (strcmp(arg[iarg+2],"uniform") == 0) dist_setting = NULL;
       else if (strcmp(arg[iarg+2],"gaussian") == 0) dist_setting = NULL;
       else error->all(FLERR,"Illegal prd command");
       n = strlen(arg[iarg+2]) + 1;
       dist_setting = new char[n];
       strcpy(dist_setting,arg[iarg+2]);
 
       iarg += 3;
 
     } else if (strcmp(arg[iarg],"time") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal prd command");
       if (strcmp(arg[iarg+1],"steps") == 0) stepmode = 0;
       else if (strcmp(arg[iarg+1],"clock") == 0) stepmode = 1;
       else error->all(FLERR,"Illegal prd command");
       iarg += 2;
 
     } else error->all(FLERR,"Illegal prd command");
   }
 }
diff --git a/src/REPLICA/tad.cpp b/src/REPLICA/tad.cpp
index dfd1ea7e5..80381a7a3 100644
--- a/src/REPLICA/tad.cpp
+++ b/src/REPLICA/tad.cpp
@@ -1,1039 +1,1044 @@
 /* ----------------------------------------------------------------------
    LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
    http://lammps.sandia.gov, Sandia National Laboratories
    Steve Plimpton, sjplimp@sandia.gov
 
    Copyright (2003) Sandia Corporation.  Under the terms of Contract
    DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
    certain rights in this software.  This software is distributed under
    the GNU General Public License.
 
    See the README file in the top-level LAMMPS directory.
 ------------------------------------------------------------------------- */
 
 /* ----------------------------------------------------------------------
    Contributing author: Aidan Thompson (SNL)
 ------------------------------------------------------------------------- */
 
+// lmptype.h must be first b/c this file uses MAXBIGINT and includes mpi.h
+// due to OpenMPI bug which sets INT64_MAX via its mpi.h
+//   before lmptype.h can set flags to insure it is done correctly
+
+#include "lmptype.h" 
 #include "mpi.h"
 #include "math.h"
 #include "stdlib.h"
 #include "string.h"
 #include "tad.h"
 #include "universe.h"
 #include "update.h"
 #include "atom.h"
 #include "domain.h"
 #include "region.h"
 #include "comm.h"
 #include "velocity.h"
 #include "integrate.h"
 #include "min.h"
 #include "neighbor.h"
 #include "modify.h"
 #include "neb.h"
 #include "compute.h"
 #include "fix.h"
 #include "fix_event_tad.h"
 #include "fix_store.h"
 #include "force.h"
 #include "pair.h"
 #include "random_park.h"
 #include "random_mars.h"
 #include "output.h"
 #include "dump.h"
 #include "finish.h"
 #include "timer.h"
 #include "memory.h"
 #include "error.h"
 
 using namespace LAMMPS_NS;
 
 /* ---------------------------------------------------------------------- */
 
 TAD::TAD(LAMMPS *lmp) : Pointers(lmp) {}
 
 /* ---------------------------------------------------------------------- */
 
 TAD::~TAD()
 {
   memory->sfree(fix_event_list);
   if (neb_logfilename != NULL) delete [] neb_logfilename;
   delete [] min_style;
   delete [] min_style_neb;
 }
 
 /* ----------------------------------------------------------------------
    perform TAD simulation on root proc
    other procs only used for NEB calcs
 ------------------------------------------------------------------------- */
 
 void TAD::command(int narg, char **arg)
 {
   fix_event_list = NULL;
   n_event_list = 0;
   nmax_event_list = 0;
   nmin_event_list = 10;
 
   // error checks
 
   if (domain->box_exist == 0)
     error->all(FLERR,"Tad command before simulation box is defined");
   if (universe->nworlds == 1)
     error->all(FLERR,"Cannot use TAD with a single replica for NEB");
   if (universe->nworlds != universe->nprocs)
     error->all(FLERR,"Can only use TAD with 1-processor replicas for NEB");
   if (atom->sortfreq > 0)
     error->all(FLERR,"Cannot use TAD with atom_modify sort enabled for NEB");
   if (atom->map_style == 0)
     error->all(FLERR,"Cannot use TAD unless atom map exists for NEB");
 
   if (narg < 7) error->universe_all(FLERR,"Illegal tad command");
 
   nsteps = force->inumeric(FLERR,arg[0]);
   t_event = force->inumeric(FLERR,arg[1]);
   templo = force->numeric(FLERR,arg[2]);
   temphi = force->numeric(FLERR,arg[3]);
   delta_conf = force->numeric(FLERR,arg[4]);
   tmax = force->numeric(FLERR,arg[5]);
 
   char *id_compute = new char[strlen(arg[6])+1];
   strcpy(id_compute,arg[6]);
   
   // quench minimizer is set by min_style command
   // NEB minimizer is set by options, default = quickmin
 
   int n = strlen(update->minimize_style) + 1;
   min_style = new char[n];
   strcpy(min_style,update->minimize_style);
   
   options(narg-7,&arg[7]);
 
   // total # of timesteps must be multiple of t_event
 
   if (t_event <= 0) error->universe_all(FLERR,"Invalid t_event in tad command");
   if (nsteps % t_event)
     error->universe_all(FLERR,"TAD nsteps must be multiple of t_event");
 
   if (delta_conf <= 0.0 || delta_conf >= 1.0)
     error->universe_all(FLERR,"Invalid delta_conf in tad command");
 
   if (tmax <= 0.0)
     error->universe_all(FLERR,"Invalid tmax in tad command");
 
   // deltconf = (ln(1/delta))/freq_min (timestep units)
 
   deltconf = -log(delta_conf)*tmax/update->dt;
 
   // local storage
 
   int me_universe = universe->me;
   int nprocs_universe = universe->nprocs;
 
   MPI_Comm_rank(world,&me);
   MPI_Comm_size(world,&nprocs);
 
   delta_beta = (1.0/templo - 1.0/temphi) / force->boltz;
   ratio_beta = templo/temphi;
 
   // create FixEventTAD object to store last event
 
   int narg2 = 3;
   char **args = new char*[narg2];
   args[0] = (char *) "tad_event";
   args[1] = (char *) "all";
   args[2] = (char *) "EVENT/TAD";
   modify->add_fix(narg2,args);
   fix_event = (FixEventTAD *) modify->fix[modify->nfix-1];
   delete [] args;
 
   // create FixStore object to store revert state
 
   narg2 = 5;
   args = new char*[narg2];
   args[0] = (char *) "tad_revert";
   args[1] = (char *) "all";
   args[2] = (char *) "STORE";
   args[3] = (char *) "0";
   args[4] = (char *) "7";
   modify->add_fix(narg2,args);
   fix_revert = (FixStore *) modify->fix[modify->nfix-1];
   delete [] args;
 
   // create Finish for timing output
 
   finish = new Finish(lmp);
 
   // assign FixEventTAD to event-detection compute
   // necessary so it will know atom coords at last event
 
   int icompute = modify->find_compute(id_compute);
   if (icompute < 0) error->all(FLERR,"Could not find compute ID for TAD");
   compute_event = modify->compute[icompute];
   compute_event->reset_extra_compute_fix("tad_event");
 
   // reset reneighboring criteria since will perform minimizations
 
   neigh_every = neighbor->every;
   neigh_delay = neighbor->delay;
   neigh_dist_check = neighbor->dist_check;
 
   if (neigh_every != 1 || neigh_delay != 0 || neigh_dist_check != 1) {
     if (me_universe == 0)
       error->warning(FLERR,"Resetting reneighboring criteria during TAD");
   }
 
   neighbor->every = 1;
   neighbor->delay = 0;
   neighbor->dist_check = 1;
 
   // initialize TAD as if one long dynamics run
 
   update->whichflag = 1;
   update->nsteps = nsteps;
   update->beginstep = update->firststep = update->ntimestep;
   update->endstep = update->laststep = update->firststep + nsteps;
   update->restrict_output = 1;
   if (update->laststep < 0 || update->laststep > MAXBIGINT)
     error->all(FLERR,"Too many timesteps");
 
   lmp->init();
 
   // set minimize style for quench
 
   narg2 = 1;
   args = new char*[narg2];
   args[0] = min_style;
 
   update->create_minimize(narg2,args);
 
   delete [] args;
 
   // init minimizer settings and minimizer itself
 
   update->etol = etol;
   update->ftol = ftol;
   update->max_eval = maxeval;
 
   update->minimize->init();
 
   // perform TAD simulation
 
   if (me_universe == 0 && universe->uscreen)
     fprintf(universe->uscreen,"Setting up TAD ...\n");
 
   if (me_universe == 0) {
     if (universe->uscreen)
       fprintf(universe->uscreen,
               "Step CPU N M Status Barrier Margin t_lo delt_lo\n");
     if (universe->ulogfile)
       fprintf(universe->ulogfile,
               "Step CPU N M Status Barrier Margin t_lo delt_lo\n");
   }
 
   ulogfile_lammps = universe->ulogfile;
   uscreen_lammps = universe->uscreen;
   ulogfile_neb = NULL;
   uscreen_neb = NULL;
   if (me_universe == 0 && neb_logfilename)
     ulogfile_neb = fopen(neb_logfilename,"w");
 
   // store hot state and quenched event, only on replica 0
 
   // need this line if quench() does only setup_minimal()
   // update->minimize->setup();
 
   // This should work with if uncommented, but does not
   // if (universe->iworld == 0) {
 
   fix_event->store_state_quench();
   quench();
 
   timer->init();
   timer->barrier_start();
   time_start = timer->get_wall(Timer::TOTAL);
   fix_event->store_event_tad(update->ntimestep);
   log_event(0);
   fix_event->restore_state_quench();
 
   // do full init/setup
 
   update->whichflag = 1;
   lmp->init();
   update->integrate->setup();
 
   // main loop: look for events until out of time
   // (1) dynamics, store state, quench, check event, restore state
   // (2) if event, perform NEB, record in fix_event_list
   // (3) if confident, pick earliest event
 
   nbuild = ndanger = 0;
   time_neb = time_dynamics = time_quench = time_comm = time_output = 0.0;
 
   timer->barrier_start();
   time_start = timer->get_wall(Timer::TOTAL);
 
   int confident_flag, event_flag;
 
   if (universe->iworld == 0) {
     while (update->ntimestep < update->endstep) {
 
       // initialize list of possible events
 
       initialize_event_list();
       confident_flag = 0;
 
       while (update->ntimestep < update->endstep) {
         event_flag = 0;
         while (update->ntimestep < update->endstep) {
 
           dynamics();
           fix_event->store_state_quench();
           quench();
 
           event_flag = check_event();
           MPI_Bcast(&event_flag,1,MPI_INT,0,universe->uworld);
 
           if (event_flag) break;
 
           // restore hot state
 
           fix_event->restore_state_quench();
 
           // store hot state in revert
 
           store_state();
         }
         if (!event_flag) break;
 
         add_event();
 
         perform_neb(n_event_list-1);
         compute_tlo(n_event_list-1);
         confident_flag = check_confidence();
         MPI_Bcast(&confident_flag,1,MPI_INT,0,universe->uworld);
         if (confident_flag) break;
         if (universe->iworld == 0) revert_state();
       }
       if (!confident_flag) break;
 
       perform_event(event_first);
 
       // need to sync timestep with TAD
 
       MPI_Bcast(&(update->ntimestep),1,MPI_INT,0,universe->uworld);
 
       int restart_flag = 0;
       if (output->restart_flag && universe->iworld == 0) {
         if (output->restart_every_single &&
             fix_event->event_number % output->restart_every_single == 0)
           restart_flag = 1;
         if (output->restart_every_double &&
             fix_event->event_number % output->restart_every_double == 0)
           restart_flag = 1;
       }
 
       // full init/setup since are starting after event
 
       update->whichflag = 1;
       lmp->init();
       update->integrate->setup();
 
     // write restart file of hot coords
 
       if (restart_flag) {
         timer->barrier_start();
         output->write_restart(update->ntimestep);
         timer->barrier_stop();
         time_output += timer->get_wall(Timer::TOTAL);
       }
     }
 
   } else {
 
     while (update->ntimestep < update->endstep) {
       confident_flag = 0;
       while (update->ntimestep < update->endstep) {
         event_flag = 0;
         while (update->ntimestep < update->endstep) {
           update->ntimestep += t_event;
           MPI_Bcast(&event_flag,1,MPI_INT,0,universe->uworld);
 
           if (event_flag) break;
         }
         if (!event_flag) break;
         perform_neb(-1);
         MPI_Bcast(&confident_flag,1,MPI_INT,0,universe->uworld);
         if (confident_flag) break;
       }
       if (!confident_flag) break;
 
       // need to sync timestep with TAD
 
       MPI_Bcast(&(update->ntimestep),1,MPI_INT,0,universe->uworld);
     }
   }
 
   // set total timers and counters so Finish() will process them
 
   timer->set_wall(Timer::TOTAL, time_start);
   timer->barrier_stop();
 
   timer->set_wall(Timer::NEB, time_neb);
   timer->set_wall(Timer::DYNAMICS, time_dynamics);
   timer->set_wall(Timer::QUENCH, time_quench);
   timer->set_wall(Timer::REPCOMM, time_comm);
   timer->set_wall(Timer::REPOUT, time_output);
 
   neighbor->ncalls = nbuild;
   neighbor->ndanger = ndanger;
 
   if (me_universe == 0) {
     if (universe->uscreen)
       fprintf(universe->uscreen,
               "Loop time of %g on %d procs for %d steps with " BIGINT_FORMAT 
               " atoms\n",
               timer->get_wall(Timer::TOTAL),nprocs_universe,nsteps,atom->natoms);
     if (universe->ulogfile) 
       fprintf(universe->ulogfile,
               "Loop time of %g on %d procs for %d steps with " BIGINT_FORMAT 
               " atoms\n",
               timer->get_wall(Timer::TOTAL),nprocs_universe,nsteps,atom->natoms);
   }
 
   if (me_universe == 0) fclose(ulogfile_neb);
 
   if (me == 0) {
     if (screen) fprintf(screen,"\nTAD done\n");
     if (logfile) fprintf(logfile,"\nTAD done\n");
   }
 
   finish->end(3);
 
   update->whichflag = 0;
   update->firststep = update->laststep = 0;
   update->beginstep = update->endstep = 0;
   update->restrict_output = 0;
 
   // reset reneighboring criteria
 
   neighbor->every = neigh_every;
   neighbor->delay = neigh_delay;
   neighbor->dist_check = neigh_dist_check;
 
 
   delete [] id_compute;
   delete finish;
   modify->delete_fix("tad_event");
   modify->delete_fix("tad_revert");
   delete_event_list();
 
   compute_event->reset_extra_compute_fix(NULL);
 }
 
 /* ----------------------------------------------------------------------
    single short dynamics run
 ------------------------------------------------------------------------- */
 
 void TAD::dynamics()
 {
   update->whichflag = 1;
   update->nsteps = t_event;
 
   lmp->init();
   update->integrate->setup();
   // this may be needed if don't do full init
   //modify->addstep_compute_all(update->ntimestep);
   int ncalls = neighbor->ncalls;
 
   timer->barrier_start();
   update->integrate->run(t_event);
   timer->barrier_stop();
   time_dynamics += timer->get_wall(Timer::TOTAL);
 
   nbuild += neighbor->ncalls - ncalls;
   ndanger += neighbor->ndanger;
 
   update->integrate->cleanup();
   finish->end(0);
 }
 
 /* ----------------------------------------------------------------------
    quench minimization
 ------------------------------------------------------------------------- */
 
 void TAD::quench()
 {
   bigint ntimestep_hold = update->ntimestep;
   bigint endstep_hold = update->endstep;
 
   // need to change whichflag so that minimize->setup() calling
   // modify->setup() will call fix->min_setup()
 
   update->whichflag = 2;
   update->nsteps = maxiter;
   update->endstep = update->laststep = update->firststep + maxiter;
   if (update->laststep < 0 || update->laststep > MAXBIGINT)
     error->all(FLERR,"Too many iterations");
 
   // full init works
 
   lmp->init();
   update->minimize->setup();
 
   // partial init does not work
 
   //modify->addstep_compute_all(update->ntimestep);
   //update->minimize->setup_minimal(1);
 
   int ncalls = neighbor->ncalls;
 
   timer->barrier_start();
   update->minimize->run(maxiter);
   timer->barrier_stop();
   time_quench += timer->get_wall(Timer::TOTAL);
 
   if (neighbor->ncalls == ncalls) quench_reneighbor = 0;
   else quench_reneighbor = 1;
 
   update->minimize->cleanup();
   finish->end(1);
 
   // reset timestep as if quench did not occur
   // clear timestep storage from computes, since now invalid
 
   update->ntimestep = ntimestep_hold;
   update->endstep = update->laststep = endstep_hold;
   for (int i = 0; i < modify->ncompute; i++)
     if (modify->compute[i]->timeflag) modify->compute[i]->clearstep();
 }
 
 /* ----------------------------------------------------------------------
    check for an event
    return 0 if no event
    return 1 if event
 ------------------------------------------------------------------------- */
 
 int TAD::check_event()
 {
   int flag;
 
   flag = 0;
   if (compute_event->compute_scalar() > 0.0) flag = 1;
 
   return flag;
 }
 
 /* ----------------------------------------------------------------------
    universe proc 0 prints event info
 ------------------------------------------------------------------------- */
 
 void TAD::log_event(int ievent)
 {
   timer->set_wall(Timer::TOTAL, time_start);
   if (universe->me == 0) {
     double tfrac = 0.0;
     if (universe->uscreen)
       fprintf(universe->uscreen,
               BIGINT_FORMAT " %.3f %d %d %s %.3f %.3f %.3f %.3f\n",
               fix_event->event_timestep,
               timer->elapsed(Timer::TOTAL),
               fix_event->event_number,ievent,
               "E ",
               fix_event->ebarrier,tfrac,
               fix_event->tlo,deltfirst);
     if (universe->ulogfile)
       fprintf(universe->ulogfile,
               BIGINT_FORMAT " %.3f %d %d %s %.3f %.3f %.3f %.3f\n",
               fix_event->event_timestep,
               timer->elapsed(Timer::TOTAL),
               fix_event->event_number,ievent,
               "E ",
               fix_event->ebarrier,tfrac,
               fix_event->tlo,deltfirst);
   }
 
   // dump snapshot of quenched coords
   // must reneighbor and compute forces before dumping
   // addstep_compute_all insures eng/virial are calculated if needed
 
   if (output->ndump && universe->iworld == 0) {
     timer->barrier_start();
     modify->addstep_compute_all(update->ntimestep);
     update->integrate->setup_minimal(1);
     output->write_dump(update->ntimestep);
     timer->barrier_stop();
     time_output += timer->get_wall(Timer::TOTAL);
   }
 
 }
 
 /* ----------------------------------------------------------------------
    parse optional parameters at end of TAD input line
 ------------------------------------------------------------------------- */
 
 void TAD::options(int narg, char **arg)
 {
   if (narg < 0) error->all(FLERR,"Illegal tad command");
 
   // set defaults
 
   etol = 0.1;
   ftol = 0.1;
   maxiter = 40;
   maxeval = 50;
 
   etol_neb = 0.01;
   ftol_neb = 0.01;
   n1steps_neb = 100;
   n2steps_neb = 100;
   nevery_neb = 10;
 
   int n = strlen("quickmin") + 1;
   min_style_neb = new char[n];
   strcpy(min_style_neb,"quickmin");
   dt_neb = update->dt;
   neb_logfilename = NULL;
 
   int iarg = 0;
   while (iarg < narg) {
     if (strcmp(arg[iarg],"min") == 0) {
       if (iarg+5 > narg) error->all(FLERR,"Illegal tad command");
       etol = force->numeric(FLERR,arg[iarg+1]);
       ftol = force->numeric(FLERR,arg[iarg+2]);
       maxiter = force->inumeric(FLERR,arg[iarg+3]);
       maxeval = force->inumeric(FLERR,arg[iarg+4]);
       if (maxiter < 0 || maxeval < 0 ||
           etol < 0.0 || ftol < 0.0 )
         error->all(FLERR,"Illegal tad command");
       iarg += 5;
 
     } else if (strcmp(arg[iarg],"neb") == 0) {
       if (iarg+6 > narg) error->all(FLERR,"Illegal tad command");
       etol_neb = force->numeric(FLERR,arg[iarg+1]);
       ftol_neb = force->numeric(FLERR,arg[iarg+2]);
       n1steps_neb = force->inumeric(FLERR,arg[iarg+3]);
       n2steps_neb = force->inumeric(FLERR,arg[iarg+4]);
       nevery_neb = force->inumeric(FLERR,arg[iarg+5]);
       if (etol_neb < 0.0 || ftol_neb < 0.0 ||
           n1steps_neb < 0 || n2steps_neb < 0 ||
           nevery_neb < 0) error->all(FLERR,"Illegal tad command");
       iarg += 6;
 
     } else if (strcmp(arg[iarg],"neb_style") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal tad command");
       delete [] min_style_neb;
       int n = strlen(arg[iarg+1]) + 1;
       min_style_neb = new char[n];
       strcpy(min_style_neb,arg[iarg+1]);
       iarg += 2;
 
     } else if (strcmp(arg[iarg],"neb_step") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal tad command");
       dt_neb = force->numeric(FLERR,arg[iarg+1]);
       if (dt_neb <= 0.0) error->all(FLERR,"Illegal tad command");
       iarg += 2;
 
     } else if (strcmp(arg[iarg],"neb_log") == 0) {
       delete [] neb_logfilename;
       if (iarg+2 > narg) error->all(FLERR,"Illegal tad command");
       if (strcmp(arg[iarg+1],"none") == 0) neb_logfilename = NULL;
       else {
         int n = strlen(arg[iarg+1]) + 1;
         neb_logfilename = new char[n];
         strcpy(neb_logfilename,arg[iarg+1]);
       }
       iarg += 2;
     } else error->all(FLERR,"Illegal tad command");
   }
 }
 
 /* ----------------------------------------------------------------------
    perform NEB calculation
 ------------------------------------------------------------------------- */
 
 void TAD::perform_neb(int ievent)
 {
 
   double **x = atom->x;
   int nlocal = atom->nlocal;
 
   double *buf_final;
   memory->create(buf_final,3*nlocal,"tad:buffinal");
 
   // set system to quenched state of event ievent
 
   if (universe->iworld == 0) {
 
     fix_event_list[ievent]->restore_event();
 
     int ii = 0;
     for (int i = 0; i < nlocal; i++) {
       buf_final[ii++] = x[i][0];
       buf_final[ii++] = x[i][1];
       buf_final[ii++] = x[i][2];
     }
   }
 
   MPI_Bcast(buf_final,3*nlocal,MPI_DOUBLE,universe->root_proc[0],
             universe->uworld);
 
   double *buf_init;
   memory->create(buf_init,3*nlocal,"tad:bufinit");
 
   // set system to quenched state of fix_event
 
   if (universe->iworld == 0) {
 
     fix_event->restore_event();
 
     int ii = 0;
     for (int i = 0; i < nlocal; i++) {
       buf_init[ii++] = x[i][0];
       buf_init[ii++] = x[i][1];
       buf_init[ii++] = x[i][2];
     }
   }
 
   MPI_Bcast(buf_init,3*nlocal,MPI_DOUBLE,universe->root_proc[0],
             universe->uworld);
 
   // create FixNEB object to support NEB
 
   int narg2 = 4;
   char **args = new char*[narg2];
   args[0] = (char *) "neb";
   args[1] = (char *) "all";
   args[2] = (char *) "neb";
   char str[128];
   args[3] = str;
   double kspring = 1.0;
   sprintf(args[3],"%f",kspring);
   modify->add_fix(narg2,args);
   fix_neb = (Fix *) modify->fix[modify->nfix-1];
   delete [] args;
 
   // switch minimize style to quickmin for NEB
 
   narg2 = 1;
   args = new char*[narg2];
   args[0] = min_style_neb;
 
   update->create_minimize(narg2,args);
 
   delete [] args;
 
   // create NEB object
 
   neb = new NEB(lmp,etol_neb,ftol_neb,n1steps_neb,
                 n2steps_neb,nevery_neb,buf_init,buf_final);
 
   // free up temporary arrays
 
   memory->destroy(buf_init);
   memory->destroy(buf_final);
 
   // run NEB with NEB timestep
 
   int beginstep_hold = update->beginstep;
   int endstep_hold = update->endstep;
   int ntimestep_hold = update->ntimestep;
   int nsteps_hold = update->nsteps;
 
   if (universe->me == 0) {
     universe->ulogfile = ulogfile_neb;
     universe->uscreen = uscreen_neb;
   }
 
   // had to bypass timer interface
   // because timer->array is reset inside neb->run()
 
   //    timer->barrier_start();
   //    neb->run();
   //    timer->barrier_stop();
   //    time_neb += timer->get_wall(Timer::TOTAL);
 
   MPI_Barrier(world);
   double time_tmp = MPI_Wtime();
 
   double dt_hold = update->dt;
   update->dt = dt_neb;
   neb->run();
   update->dt = dt_hold;
 
   MPI_Barrier(world);
   time_neb += MPI_Wtime() - time_tmp;
 
   if (universe->me == 0) {
     universe->ulogfile = ulogfile_lammps;
     universe->uscreen = uscreen_lammps;
   }
 
   // extract barrier energy from NEB
 
   if (universe->iworld == 0)
     fix_event_list[ievent]->ebarrier = neb->ebf;
 
   update->beginstep = update->firststep = beginstep_hold;
   update->endstep = update->laststep = endstep_hold;
   update->ntimestep = ntimestep_hold;
   update->nsteps = nsteps_hold;
 
   // switch minimize style back for quench
 
   narg2 = 1;
   args = new char*[narg2];
   args[0] = min_style;
 
   update->create_minimize(narg2,args);
 
   update->etol = etol;
   update->ftol = ftol;
 
   delete [] args;
 
   // clean up
 
   modify->delete_fix("neb");
   delete neb;
 }
 
 /* ----------------------------------------------------------------------
    check if confidence criterion for tstop is satisfied
    return 0 if not satisfied
    return 1 if satisfied
 ------------------------------------------------------------------------- */
 
 int TAD::check_confidence()
 {
   int flag;
 
   // update stopping time
 
   deltstop = deltconf*pow(deltfirst/deltconf, ratio_beta);
 
   flag = 0;
   if (deltstop < update->ntimestep - fix_event->event_timestep) flag = 1;
 
   return flag;
 }
 
 /* ----------------------------------------------------------------------
    store state in fix_revert
 ------------------------------------------------------------------------- */
 
 void TAD::store_state()
 {
   double **x = atom->x;
   double **v = atom->v;
   imageint *image = atom->image;
   int nlocal = atom->nlocal;
 
   double **astore = fix_revert->astore;
 
   for (int i = 0; i < nlocal; i++) {
     astore[i][0] = x[i][0];
     astore[i][1] = x[i][1];
     astore[i][2] = x[i][2];
     astore[i][3] = v[i][0];
     astore[i][4] = v[i][1];
     astore[i][5] = v[i][2];
     *((imageint *) &astore[i][6]) = image[i];
   }
 }
 
 /* ----------------------------------------------------------------------
    restore state archived in fix_revert
    flip sign of velocities to reflect back to starting state
 ------------------------------------------------------------------------- */
 
 void TAD::revert_state()
 {
   double **x = atom->x;
   double **v = atom->v;
   imageint *image = atom->image;
   int nlocal = atom->nlocal;
 
   double **astore = fix_revert->astore;
 
   for (int i = 0; i < nlocal; i++) {
     x[i][0] = astore[i][0];
     x[i][1] = astore[i][1];
     x[i][2] = astore[i][2];
     v[i][0] = -astore[i][3];
     v[i][1] = -astore[i][4];
     v[i][2] = -astore[i][5];
     image[i] = *((imageint *) &astore[i][6]);
   }
 }
 
 /* ----------------------------------------------------------------------
    Initialize list of possible events
 ------------------------------------------------------------------------- */
 
 void TAD::initialize_event_list() {
 
   // First delete old events, if any
 
   delete_event_list();
 
   // Create new list
 
   n_event_list = 0;
   grow_event_list(nmin_event_list);
 }
 
 /* ----------------------------------------------------------------------
    Delete list of possible events
 ------------------------------------------------------------------------- */
 
 void TAD::delete_event_list() {
 
   for (int i = 0; i < n_event_list; i++) {
     char str[128];
     sprintf(str,"tad_event_%d",i);
     modify->delete_fix(str);
   }
   memory->sfree(fix_event_list);
   fix_event_list = NULL;
   n_event_list = 0;
   nmax_event_list = 0;
 
 }
 
 /* ----------------------------------------------------------------------
    add event
 ------------------------------------------------------------------------- */
 
 void TAD::add_event()
 {
 
   // create FixEventTAD object to store possible event
 
   int narg = 3;
   char **args = new char*[narg];
 
   char str[128];
   sprintf(str,"tad_event_%d",n_event_list);
 
   args[0] = str;
   args[1] = (char *) "all";
   args[2] = (char *) "EVENT/TAD";
   modify->add_fix(narg,args);
 
   if (n_event_list == nmax_event_list)
     grow_event_list(nmax_event_list+nmin_event_list);
   n_event_list += 1;
   int ievent = n_event_list-1;
   fix_event_list[ievent] = (FixEventTAD *) modify->fix[modify->nfix-1];
 
   // store quenched state for new event
 
   fix_event_list[ievent]->store_event_tad(update->ntimestep);
 
   // store hot state for new event
 
   fix_event->restore_state_quench();
   fix_event_list[ievent]->store_state_quench();
 
   // string clean-up
 
   delete [] args;
 
 }
 
 /* ----------------------------------------------------------------------
    compute cold time for event ievent
 ------------------------------------------------------------------------- */
 
 void TAD::compute_tlo(int ievent)
 {
   double deltlo,delthi,ebarrier;
 
   ebarrier = fix_event_list[ievent]->ebarrier;
   delthi = fix_event_list[ievent]->event_timestep
     - fix_event->event_timestep;
   deltlo = delthi*exp(ebarrier*delta_beta);
   fix_event_list[ievent]->tlo = fix_event->tlo + deltlo;
 
   // update first event
 
   char* statstr = (char *) "D ";
 
   if (ievent == 0) {
     deltfirst = deltlo;
     event_first = ievent;
     statstr = (char *) "DF";
   } else if (deltlo < deltfirst) {
     deltfirst = deltlo;
     event_first = ievent;
     statstr = (char *) "DF";
   }
 
   // first-replica output about each event
 
   timer->set_wall(Timer::TOTAL, time_start);
   if (universe->me == 0) {
     double tfrac = 0.0;
     if (ievent > 0) tfrac = delthi/deltstop;
 
     if (universe->uscreen)
       fprintf(universe->uscreen,
               BIGINT_FORMAT " %.3f %d %d %s %.3f %.3f %.3f %.3f\n",
               fix_event_list[ievent]->event_timestep,
               timer->elapsed(Timer::TOTAL),
               fix_event->event_number,
               ievent,statstr,ebarrier,tfrac,
               fix_event->tlo,deltlo);
 
     if (universe->ulogfile)
       fprintf(universe->ulogfile,
               BIGINT_FORMAT " %.3f %d %d %s %.3f %.3f %.3f %.3f\n",
               fix_event_list[ievent]->event_timestep,
               timer->elapsed(Timer::TOTAL),
               fix_event->event_number,
               ievent,statstr,ebarrier,tfrac,
               fix_event->tlo,deltlo);
   }
 
 }
 
 /* ----------------------------------------------------------------------
    perform event
 ------------------------------------------------------------------------- */
 
 void TAD::perform_event(int ievent)
 {
   // reset timestep to that of event
 
   update->ntimestep = fix_event_list[ievent]->event_timestep;
 
   // Copy event to current event
   // Should really use copy constructor for this
   fix_event->tlo = fix_event_list[ievent]->tlo;
   fix_event->ebarrier = fix_event_list[ievent]->ebarrier;
   fix_event->event_number++;
   fix_event->event_timestep = update->ntimestep;
   fix_event_list[ievent]->restore_event();
   fix_event->store_event_tad(fix_event_list[ievent]->event_timestep);
 
   // output stats and dump for quenched state
 
   log_event(ievent);
 
   // load and store hot state
 
   fix_event_list[ievent]->restore_state_quench();
   fix_event->store_state_quench();
 }
 
 /* ----------------------------------------------------------------------
    Allocate list of pointers to events
 ------------------------------------------------------------------------- */
 
 void TAD::grow_event_list(int nmax) {
   if (nmax_event_list > nmax) return;
   fix_event_list = (FixEventTAD **)
     memory->srealloc(fix_event_list,nmax*sizeof(FixEventTAD *),"tad:eventlist");
   nmax_event_list = nmax;
 }
diff --git a/src/read_data.cpp b/src/read_data.cpp
index 43c290a8b..cf87b2773 100644
--- a/src/read_data.cpp
+++ b/src/read_data.cpp
@@ -1,1662 +1,1667 @@
 /* ----------------------------------------------------------------------
    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.
 ------------------------------------------------------------------------- */
 
+// lmptype.h must be first b/c this file uses MAXBIGINT and includes mpi.h
+// due to OpenMPI bug which sets INT64_MAX via its mpi.h
+//   before lmptype.h can set flags to insure it is done correctly
+
+#include "lmptype.h" 
 #include "mpi.h"
 #include "math.h"
 #include "string.h"
 #include "stdlib.h"
 #include "ctype.h"
 #include "read_data.h"
 #include "atom.h"
 #include "atom_vec.h"
 #include "atom_vec_ellipsoid.h"
 #include "atom_vec_line.h"
 #include "atom_vec_tri.h"
 #include "force.h"
 #include "molecule.h"
 #include "comm.h"
 #include "update.h"
 #include "modify.h"
 #include "fix.h"
 #include "force.h"
 #include "pair.h"
 #include "domain.h"
 #include "bond.h"
 #include "angle.h"
 #include "dihedral.h"
 #include "improper.h"
 #include "special.h"
 #include "error.h"
 #include "memory.h"
 
 using namespace LAMMPS_NS;
 
 #define MAXLINE 256
 #define LB_FACTOR 1.1
 #define CHUNK 1024
 #define DELTA 4            // must be 2 or larger
 #define MAXBODY 20         // max # of lines in one body, also in Atom class
 
                            // customize for new sections
 #define NSECTIONS 25       // change when add to header::section_keywords
 
 // pair style suffixes to ignore
 // when matching Pair Coeffs comment to currently-defined pair style
 
 const char *suffixes[] = {"/cuda","/gpu","/opt","/omp","/kk",
                           "/coul/cut","/coul/long","/coul/msm",
                           "/coul/dsf","/coul/debye","/coul/charmm",
                           NULL};
 
 /* ---------------------------------------------------------------------- */
 
 ReadData::ReadData(LAMMPS *lmp) : Pointers(lmp)
 {
   MPI_Comm_rank(world,&me);
   line = new char[MAXLINE];
   keyword = new char[MAXLINE];
   style = new char[MAXLINE];
   buffer = new char[CHUNK*MAXLINE];
   narg = maxarg = 0;
   arg = NULL;
 
   // customize for new sections
   // pointers to atom styles that store extra info
 
   nellipsoids = 0;
   avec_ellipsoid = (AtomVecEllipsoid *) atom->style_match("ellipsoid");
   nlines = 0;
   avec_line = (AtomVecLine *) atom->style_match("line");
   ntris = 0;
   avec_tri = (AtomVecTri *) atom->style_match("tri");
   nbodies = 0;
   avec_body = (AtomVecBody *) atom->style_match("body");
 }
 
 /* ---------------------------------------------------------------------- */
 
 ReadData::~ReadData()
 {
   delete [] line;
   delete [] keyword;
   delete [] style;
   delete [] buffer;
   memory->sfree(arg);
 
   for (int i = 0; i < nfix; i++) {
     delete [] fix_header[i];
     delete [] fix_section[i];
   }
   memory->destroy(fix_index);
   memory->sfree(fix_header);
   memory->sfree(fix_section);
 }
 
 /* ---------------------------------------------------------------------- */
 
 void ReadData::command(int narg, char **arg)
 {
   if (narg < 1) error->all(FLERR,"Illegal read_data command");
 
   // optional args
 
   addflag = mergeflag = 0;
   offset[0] = offset[1] = offset[2] = 0.0;
   nfix = 0;
   fix_index = NULL;
   fix_header = NULL;
   fix_section = NULL;
 
   int iarg = 1;
   while (iarg < narg) {
     if (strcmp(arg[iarg],"add") == 0) {
       addflag = 1;
       iarg++;
     } else if (strcmp(arg[iarg],"merge") == 0) {
       mergeflag = 1;
       iarg++;
     } else if (strcmp(arg[iarg],"offset") == 0) {
       if (iarg+4 > narg)
         error->all(FLERR,"Illegal read_data command");
       offset[0] = force->numeric(FLERR,arg[iarg+1]);
       offset[1] = force->numeric(FLERR,arg[iarg+2]);
       offset[2] = force->numeric(FLERR,arg[iarg+3]);
       iarg += 4;
     } else if (strcmp(arg[iarg],"fix") == 0) {
       if (iarg+4 > narg)
         error->all(FLERR,"Illegal read_data command");
       memory->grow(fix_index,nfix+1,"read_data:fix_index");
       fix_header = (char **)
         memory->srealloc(fix_header,(nfix+1)*sizeof(char *),
                          "read_data:fix_header");
       fix_section = (char **)
         memory->srealloc(fix_section,(nfix+1)*sizeof(char *),
                          "read_data:fix_section");
       fix_index[nfix] = modify->find_fix(arg[iarg+1]);
       if (fix_index[nfix] < 0)
         error->all(FLERR,"Fix ID for read_data does not exist");
       if (strcmp(arg[iarg+2],"NULL") == 0) fix_header[nfix] = NULL;
       else {
         int n = strlen(arg[iarg+2]) + 1;
         fix_header[nfix] = new char[n];
         strcpy(fix_header[nfix],arg[iarg+2]);
       }
       int n = strlen(arg[iarg+3]) + 1;
       fix_section[nfix] = new char[n];
       strcpy(fix_section[nfix],arg[iarg+3]);
       nfix++;
       iarg += 4;
     } else error->all(FLERR,"Illegal read_data command");
   }
 
   // error checks
 
   if (domain->box_exist && !addflag && !mergeflag)
     error->all(FLERR,"Cannot read_data after simulation box is defined");
   if (addflag && mergeflag) error->all(FLERR,"Cannot read_data add and merge");
   if (domain->dimension == 2 && offset[2] != 0.0)
     error->all(FLERR,"Cannot use non-zero z offset in read_data "
                "for 2d simulation");
 
   if (domain->dimension == 2 && domain->zperiodic == 0)
     error->all(FLERR,"Cannot run 2d simulation with nonperiodic Z dimension");
 
   // perform 1-pass read if no molecular topoogy in file
   // perform 2-pass read if molecular topology,
   //   first pass calculates max topology/atom
 
   int atomflag,topoflag;
   int bondflag,angleflag,dihedralflag,improperflag;
   int ellipsoidflag,lineflag,triflag,bodyflag;
 
   atomflag = topoflag = 0;
   bondflag = angleflag = dihedralflag = improperflag = 0;
   ellipsoidflag = lineflag = triflag = bodyflag = 0;
 
   int firstpass = 1;
 
   while (1) {
 
     // open file on proc 0
 
     if (me == 0) {
       if (firstpass && screen) fprintf(screen,"Reading data file ...\n");
       open(arg[0]);
     } else fp = NULL;
     
     // read header info
     
     header();
 
     // problem setup using info from header
     // 1st pass only
 
     if (firstpass) {
       domain->box_exist = 1;
       update->ntimestep = 0;
     
       // apply extra settings before grow(), even if no topology in file
       // deallocate() insures new settings are used for topology arrays
       // if per-atom topology is in file, another grow() is done below
 
       atom->bond_per_atom = atom->extra_bond_per_atom;
       atom->angle_per_atom = atom->extra_angle_per_atom;
       atom->dihedral_per_atom = atom->extra_dihedral_per_atom;
       atom->improper_per_atom = atom->extra_improper_per_atom;
 
       int n;
       if (comm->nprocs == 1) n = static_cast<int> (atom->natoms);
       else n = static_cast<int> (LB_FACTOR * atom->natoms / comm->nprocs);
 
       atom->allocate_type_arrays();
       atom->deallocate_topology();
       atom->avec->grow(n);
 
       domain->print_box("  ");
       domain->set_initial_box();
       domain->set_global_box();
       comm->set_proc_grid();
       domain->set_local_box();
     }
 
     // customize for new sections
     // read rest of file in free format
 
     while (strlen(keyword)) {
 
       // if special fix matches, it processes section
 
       if (nfix) {
         int i;
         for (i = 0; i < nfix; i++)
           if (strcmp(keyword,fix_section[i]) == 0) {
             if (firstpass) fix(fix_index[i],keyword);
             else skip_lines(modify->fix[fix_index[i]]->
                             read_data_skip_lines(keyword));
             parse_keyword(0);
             break;
           }
         if (i < nfix) continue;
       }
 
       if (strcmp(keyword,"Atoms") == 0) {
         atomflag = 1;
         if (firstpass) {
           if (me == 0 && !style_match(style,atom->atom_style))
             error->warning(FLERR,"Atom style in data file differs "
                            "from currently defined atom style");
           atoms();
         } else skip_lines(atom->natoms);
       } else if (strcmp(keyword,"Velocities") == 0) {
         if (atomflag == 0) 
           error->all(FLERR,"Must read Atoms before Velocities");
         if (firstpass) velocities();
         else skip_lines(atom->natoms);
 
       } else if (strcmp(keyword,"Bonds") == 0) {
         topoflag = bondflag = 1;
         if (atom->nbonds == 0)
           error->all(FLERR,"Invalid data file section: Bonds");
         if (atomflag == 0) error->all(FLERR,"Must read Atoms before Bonds");
         bonds(firstpass);
       } else if (strcmp(keyword,"Angles") == 0) {
         topoflag = angleflag = 1;
         if (atom->nangles == 0)
           error->all(FLERR,"Invalid data file section: Angles");
         if (atomflag == 0) error->all(FLERR,"Must read Atoms before Angles");
         angles(firstpass);
       } else if (strcmp(keyword,"Dihedrals") == 0) {
         topoflag = dihedralflag = 1;
         if (atom->ndihedrals == 0)
           error->all(FLERR,"Invalid data file section: Dihedrals");
         if (atomflag == 0) error->all(FLERR,"Must read Atoms before Dihedrals");
         dihedrals(firstpass);
       } else if (strcmp(keyword,"Impropers") == 0) {
         topoflag = improperflag = 1;
         if (atom->nimpropers == 0)
           error->all(FLERR,"Invalid data file section: Impropers");
         if (atomflag == 0) error->all(FLERR,"Must read Atoms before Impropers");
         impropers(firstpass);
         
       } else if (strcmp(keyword,"Ellipsoids") == 0) {
         ellipsoidflag = 1;
         if (!avec_ellipsoid)
           error->all(FLERR,"Invalid data file section: Ellipsoids");
         if (atomflag == 0) 
           error->all(FLERR,"Must read Atoms before Ellipsoids");
         if (firstpass) 
           bonus(nellipsoids,(AtomVec *) avec_ellipsoid,"ellipsoids");
         else skip_lines(nellipsoids);
       } else if (strcmp(keyword,"Lines") == 0) {
         lineflag = 1;
         if (!avec_line)
           error->all(FLERR,"Invalid data file section: Lines");
         if (atomflag == 0) error->all(FLERR,"Must read Atoms before Lines");
         if (firstpass) bonus(nlines,(AtomVec *) avec_line,"lines");
         else skip_lines(nlines);
       } else if (strcmp(keyword,"Triangles") == 0) {
         triflag = 1;
         if (!avec_tri)
           error->all(FLERR,"Invalid data file section: Triangles");
         if (atomflag == 0) error->all(FLERR,"Must read Atoms before Triangles");
         if (firstpass) bonus(ntris,(AtomVec *) avec_tri,"triangles");
         else skip_lines(ntris);
       } else if (strcmp(keyword,"Bodies") == 0) {
         bodyflag = 1;
         if (!avec_body)
           error->all(FLERR,"Invalid data file section: Bodies");
         if (atomflag == 0) error->all(FLERR,"Must read Atoms before Bodies");
         bodies(firstpass);
 
       } else if (strcmp(keyword,"Masses") == 0) {
         if (firstpass) mass();
         else skip_lines(atom->ntypes);
       } else if (strcmp(keyword,"Pair Coeffs") == 0) {
         if (force->pair == NULL)
           error->all(FLERR,"Must define pair_style before Pair Coeffs");
         if (firstpass) {
           if (me == 0 && !style_match(style,force->pair_style))
             error->warning(FLERR,"Pair style in data file differs "
                            "from currently defined pair style");
           paircoeffs();
         } else skip_lines(atom->ntypes);
       } else if (strcmp(keyword,"PairIJ Coeffs") == 0) {
         if (force->pair == NULL)
           error->all(FLERR,"Must define pair_style before PairIJ Coeffs");
         if (firstpass) {
           if (me == 0 && !style_match(style,force->pair_style))
             error->warning(FLERR,"Pair style in data file differs "
                            "from currently defined pair style");
           pairIJcoeffs();
         } else skip_lines(atom->ntypes*(atom->ntypes+1)/2);
       } else if (strcmp(keyword,"Bond Coeffs") == 0) {
         if (atom->avec->bonds_allow == 0)
           error->all(FLERR,"Invalid data file section: Bond Coeffs");
         if (force->bond == NULL)
           error->all(FLERR,"Must define bond_style before Bond Coeffs");
         if (firstpass) {
           if (me == 0 && !style_match(style,force->bond_style))
             error->warning(FLERR,"Bond style in data file differs "
                            "from currently defined bond style");
           bondcoeffs();
         } else skip_lines(atom->nbondtypes);
       } else if (strcmp(keyword,"Angle Coeffs") == 0) {
         if (atom->avec->angles_allow == 0)
           error->all(FLERR,"Invalid data file section: Angle Coeffs");
         if (force->angle == NULL)
           error->all(FLERR,"Must define angle_style before Angle Coeffs");
         if (firstpass) {
           if (me == 0 && !style_match(style,force->angle_style))
             error->warning(FLERR,"Angle style in data file differs "
                            "from currently defined angle style");
           anglecoeffs(0);
         } else skip_lines(atom->nangletypes);
       } else if (strcmp(keyword,"Dihedral Coeffs") == 0) {
         if (atom->avec->dihedrals_allow == 0)
           error->all(FLERR,"Invalid data file section: Dihedral Coeffs");
         if (force->dihedral == NULL)
           error->all(FLERR,"Must define dihedral_style before Dihedral Coeffs");
         if (firstpass) {
           if (me == 0 && !style_match(style,force->dihedral_style))
             error->warning(FLERR,"Dihedral style in data file differs "
                            "from currently defined dihedral style");
           dihedralcoeffs(0);
         } else skip_lines(atom->ndihedraltypes);
       } else if (strcmp(keyword,"Improper Coeffs") == 0) {
         if (atom->avec->impropers_allow == 0)
           error->all(FLERR,"Invalid data file section: Improper Coeffs");
         if (force->improper == NULL)
           error->all(FLERR,"Must define improper_style before Improper Coeffs");
         if (firstpass) {
           if (me == 0 && !style_match(style,force->improper_style))
             error->warning(FLERR,"Improper style in data file differs "
                            "from currently defined improper style");
           impropercoeffs(0);
         } else skip_lines(atom->nimpropertypes);
 
       } else if (strcmp(keyword,"BondBond Coeffs") == 0) {
         if (atom->avec->angles_allow == 0)
           error->all(FLERR,"Invalid data file section: BondBond Coeffs");
         if (force->angle == NULL)
           error->all(FLERR,"Must define angle_style before BondBond Coeffs");
         if (firstpass) anglecoeffs(1);
         else skip_lines(atom->nangletypes);
       } else if (strcmp(keyword,"BondAngle Coeffs") == 0) {
         if (atom->avec->angles_allow == 0)
           error->all(FLERR,"Invalid data file section: BondAngle Coeffs");
         if (force->angle == NULL)
           error->all(FLERR,"Must define angle_style before BondAngle Coeffs");
         if (firstpass) anglecoeffs(2);
         else skip_lines(atom->nangletypes);
 
       } else if (strcmp(keyword,"MiddleBondTorsion Coeffs") == 0) {
         if (atom->avec->dihedrals_allow == 0)
           error->all(FLERR,
                      "Invalid data file section: MiddleBondTorsion Coeffs");
         if (force->dihedral == NULL)
           error->all(FLERR,
                      "Must define dihedral_style before "
                      "MiddleBondTorsion Coeffs");
         if (firstpass) dihedralcoeffs(1);
         else skip_lines(atom->ndihedraltypes);
       } else if (strcmp(keyword,"EndBondTorsion Coeffs") == 0) {
         if (atom->avec->dihedrals_allow == 0)
           error->all(FLERR,"Invalid data file section: EndBondTorsion Coeffs");
         if (force->dihedral == NULL)
           error->all(FLERR,
                      "Must define dihedral_style before EndBondTorsion Coeffs");
         if (firstpass) dihedralcoeffs(2);
         else skip_lines(atom->ndihedraltypes);
       } else if (strcmp(keyword,"AngleTorsion Coeffs") == 0) {
         if (atom->avec->dihedrals_allow == 0)
           error->all(FLERR,"Invalid data file section: AngleTorsion Coeffs");
         if (force->dihedral == NULL)
           error->all(FLERR,
                      "Must define dihedral_style before AngleTorsion Coeffs");
         if (firstpass) dihedralcoeffs(3);
         else skip_lines(atom->ndihedraltypes);
       } else if (strcmp(keyword,"AngleAngleTorsion Coeffs") == 0) {
         if (atom->avec->dihedrals_allow == 0)
           error->all(FLERR,
                      "Invalid data file section: AngleAngleTorsion Coeffs");
         if (force->dihedral == NULL)
           error->all(FLERR,
                      "Must define dihedral_style before "
                      "AngleAngleTorsion Coeffs");
         if (firstpass) dihedralcoeffs(4);
         else skip_lines(atom->ndihedraltypes);
       } else if (strcmp(keyword,"BondBond13 Coeffs") == 0) {
         if (atom->avec->dihedrals_allow == 0)
           error->all(FLERR,"Invalid data file section: BondBond13 Coeffs");
         if (force->dihedral == NULL)
           error->all(FLERR,
                      "Must define dihedral_style before BondBond13 Coeffs");
         if (firstpass) dihedralcoeffs(5);
         else skip_lines(atom->ndihedraltypes);
         
       } else if (strcmp(keyword,"AngleAngle Coeffs") == 0) {
         if (atom->avec->impropers_allow == 0)
           error->all(FLERR,"Invalid data file section: AngleAngle Coeffs");
         if (force->improper == NULL)
           error->all(FLERR,
                      "Must define improper_style before AngleAngle Coeffs");
         if (firstpass) impropercoeffs(1);
         else skip_lines(atom->nimpropertypes);
 
       } else {
         char str[128];
         sprintf(str,"Unknown identifier in data file: %s",keyword);
         error->all(FLERR,str);
       }
       
       parse_keyword(0);
     }
 
     // error if natoms > 0 yet no atoms were read
 
     if (atom->natoms > 0 && atomflag == 0)
       error->all(FLERR,"No atoms in data file");
     
     // close file
     
     if (me == 0) {
       if (compressed) pclose(fp);
       else fclose(fp);
     }
 
     // done if this was 2nd pass
 
     if (!firstpass) break;
 
     // at end of 1st pass, error check for required sections
     // customize for new sections
 
     if ((atom->nbonds && !bondflag) || (atom->nangles && !angleflag) ||
         (atom->ndihedrals && !dihedralflag) ||
         (atom->nimpropers && !improperflag))
       error->one(FLERR,"Needed molecular topology not in data file");
 
     if ((nellipsoids && !ellipsoidflag) || (nlines && !lineflag) ||
         (ntris && !triflag) || (nbodies && !bodyflag))
       error->one(FLERR,"Needed bonus data not in data file");
 
     // break out of loop if no molecular topology in file
     // else make 2nd pass
     
     if (!topoflag) break;
     firstpass = 0;
 
     // reallocate bond,angle,diehdral,improper arrays via grow()
     // will use new bond,angle,dihedral,improper per-atom values from 1st pass
     // will also observe extra settings even if bond/etc topology not in file
     // leaves other atom arrays unchanged, since already nmax in length
 
     atom->deallocate_topology();
     atom->avec->grow(atom->nmax);
   }
 
   // create special bond lists for molecular systems
 
   if (atom->molecular == 1) {
     Special special(lmp);
     special.build();
   }
 
   // for atom style template systems, count total bonds,angles,etc 
 
   if (atom->molecular == 2) {
     Molecule **onemols = atom->avec->onemols;
     int *molindex = atom->molindex;
     int *molatom = atom->molatom;
     int nlocal = atom->nlocal;
 
     int imol,iatom;
     bigint nbonds,nangles,ndihedrals,nimpropers;
     nbonds = nangles = ndihedrals = nimpropers = 0;
 
     for (int i = 0; i < nlocal; i++) {
       imol = molindex[i];
       iatom = molatom[i];
       nbonds += onemols[imol]->num_bond[iatom];
       nangles += onemols[imol]->num_angle[iatom];
       ndihedrals += onemols[imol]->num_dihedral[iatom];
       nimpropers += onemols[imol]->num_improper[iatom];
     }
 
     MPI_Allreduce(&nbonds,&atom->nbonds,1,MPI_LMP_BIGINT,MPI_SUM,world);
     MPI_Allreduce(&nangles,&atom->nangles,1,MPI_LMP_BIGINT,MPI_SUM,world);
     MPI_Allreduce(&ndihedrals,&atom->ndihedrals,1,MPI_LMP_BIGINT,MPI_SUM,world);
     MPI_Allreduce(&nimpropers,&atom->nimpropers,1,MPI_LMP_BIGINT,MPI_SUM,world);
 
     if (!force->newton_bond) {
       atom->nbonds /= 2;
       atom->nangles /= 3;
       atom->ndihedrals /= 4;
       atom->nimpropers /= 4;
     }
 
     if (me == 0) {
       if (atom->nbonds) {
         if (screen)
           fprintf(screen,"  " BIGINT_FORMAT " template bonds\n",atom->nbonds);
         if (logfile)
           fprintf(logfile,"  " BIGINT_FORMAT " template bonds\n",atom->nbonds);
       }
       if (atom->nangles) {
         if (screen)
           fprintf(screen,"  " BIGINT_FORMAT " template angles\n",
                   atom->nangles);
         if (logfile)
           fprintf(logfile,"  " BIGINT_FORMAT " template angles\n",
                   atom->nangles);
       }
       if (atom->ndihedrals) {
         if (screen)
           fprintf(screen,"  " BIGINT_FORMAT " template dihedrals\n",
                   atom->nbonds);
         if (logfile)
           fprintf(logfile,"  " BIGINT_FORMAT " template bonds\n",
                   atom->ndihedrals);
       }
       if (atom->nimpropers) {
         if (screen)
           fprintf(screen,"  " BIGINT_FORMAT " template impropers\n",
                   atom->nimpropers);
         if (logfile)
           fprintf(logfile,"  " BIGINT_FORMAT " template impropers\n",
                   atom->nimpropers);
       }
     }
   }
 
   // for atom style template systems
   // insure nbondtypes,etc are still consistent with template molecules,
   //   in case data file re-defined them
 
   if (atom->molecular == 2) atom->avec->onemols[0]->check_attributes(1);
 }
 
 /* ----------------------------------------------------------------------
    read free-format header of data file
    1st line and blank lines are skipped
    non-blank lines are checked for header keywords and leading value is read
    header ends with EOF or non-blank line containing no header keyword
      if EOF, line is set to blank line
      else line has first keyword line for rest of file
 ------------------------------------------------------------------------- */
 
 void ReadData::header()
 {
   int n;
   char *ptr;
 
   // customize for new sections
 
   const char *section_keywords[NSECTIONS] =
     {"Atoms","Velocities","Ellipsoids","Lines","Triangles","Bodies",
      "Bonds","Angles","Dihedrals","Impropers",
      "Masses","Pair Coeffs","PairIJ Coeffs","Bond Coeffs","Angle Coeffs",
      "Dihedral Coeffs","Improper Coeffs",
      "BondBond Coeffs","BondAngle Coeffs","MiddleBondTorsion Coeffs",
      "EndBondTorsion Coeffs","AngleTorsion Coeffs",
      "AngleAngleTorsion Coeffs","BondBond13 Coeffs","AngleAngle Coeffs"};
 
   // skip 1st line of file
 
   if (me == 0) {
     char *eof = fgets(line,MAXLINE,fp);
     if (eof == NULL) error->one(FLERR,"Unexpected end of data file");
   }
 
   while (1) {
 
     // read a line and bcast length if flag is set
 
     if (me == 0) {
       if (fgets(line,MAXLINE,fp) == NULL) n = 0;
       else n = strlen(line) + 1;
     }
     MPI_Bcast(&n,1,MPI_INT,0,world);
 
     // if n = 0 then end-of-file so return with blank line
 
     if (n == 0) {
       line[0] = '\0';
       return;
     }
 
     MPI_Bcast(line,n,MPI_CHAR,0,world);
 
     // trim anything from '#' onward
     // if line is blank, continue
 
     if ((ptr = strchr(line,'#'))) *ptr = '\0';
     if (strspn(line," \t\n\r") == strlen(line)) continue;
 
     // allow special fixes first chance to match and process the line
     // if fix matches, continue to next header line
 
     if (nfix) {
       for (n = 0; n < nfix; n++) {
         if (!fix_header[n]) continue;
         if (strstr(line,fix_header[n])) {
           modify->fix[fix_index[n]]->read_data_header(line);
           break;
         }
       }
       if (n < nfix) continue;
     }
 
     // search line for header keyword and set corresponding variable
     // customize for new header lines
 
     if (strstr(line,"atoms")) {
       sscanf(line,BIGINT_FORMAT,&atom->natoms);
 
     // check for these first
     // otherwise "triangles" will be matched as "angles"
 
     } else if (strstr(line,"ellipsoids")) {
       if (!avec_ellipsoid)
         error->all(FLERR,"No ellipsoids allowed with this atom style");
       sscanf(line,BIGINT_FORMAT,&nellipsoids);
     } else if (strstr(line,"lines")) {
       if (!avec_line)
         error->all(FLERR,"No lines allowed with this atom style");
       sscanf(line,BIGINT_FORMAT,&nlines);
     } else if (strstr(line,"triangles")) {
       if (!avec_tri)
         error->all(FLERR,"No triangles allowed with this atom style");
       sscanf(line,BIGINT_FORMAT,&ntris);
     } else if (strstr(line,"bodies")) {
       if (!avec_body)
         error->all(FLERR,"No bodies allowed with this atom style");
       sscanf(line,BIGINT_FORMAT,&nbodies);
     }
 
     else if (strstr(line,"bonds")) sscanf(line,BIGINT_FORMAT,&atom->nbonds);
     else if (strstr(line,"angles")) sscanf(line,BIGINT_FORMAT,&atom->nangles);
     else if (strstr(line,"dihedrals")) sscanf(line,BIGINT_FORMAT,
                                               &atom->ndihedrals);
     else if (strstr(line,"impropers")) sscanf(line,BIGINT_FORMAT,
                                               &atom->nimpropers);
 
     else if (strstr(line,"atom types")) sscanf(line,"%d",&atom->ntypes);
     else if (strstr(line,"bond types")) sscanf(line,"%d",&atom->nbondtypes);
     else if (strstr(line,"angle types")) sscanf(line,"%d",&atom->nangletypes);
     else if (strstr(line,"dihedral types"))
       sscanf(line,"%d",&atom->ndihedraltypes);
     else if (strstr(line,"improper types"))
       sscanf(line,"%d",&atom->nimpropertypes);
 
     else if (strstr(line,"extra bond per atom"))
       sscanf(line,"%d",&atom->extra_bond_per_atom);
     else if (strstr(line,"extra angle per atom"))
       sscanf(line,"%d",&atom->extra_angle_per_atom);
     else if (strstr(line,"extra dihedral per atom"))
       sscanf(line,"%d",&atom->extra_dihedral_per_atom);
     else if (strstr(line,"extra improper per atom"))
       sscanf(line,"%d",&atom->extra_improper_per_atom);
     else if (strstr(line,"extra special per atom"))
       sscanf(line,"%d",&force->special_extra);
 
     else if (strstr(line,"extra bonds per atom"))
       sscanf(line,"%d",&atom->extra_bond_per_atom);
     else if (strstr(line,"extra angles per atom"))
       sscanf(line,"%d",&atom->extra_angle_per_atom);
     else if (strstr(line,"extra dihedrals per atom"))
       sscanf(line,"%d",&atom->extra_dihedral_per_atom);
     else if (strstr(line,"extra impropers per atom"))
       sscanf(line,"%d",&atom->extra_improper_per_atom);
 
     else if (strstr(line,"xlo xhi"))
       sscanf(line,"%lg %lg",&domain->boxlo[0],&domain->boxhi[0]);
     else if (strstr(line,"ylo yhi"))
       sscanf(line,"%lg %lg",&domain->boxlo[1],&domain->boxhi[1]);
     else if (strstr(line,"zlo zhi"))
       sscanf(line,"%lg %lg",&domain->boxlo[2],&domain->boxhi[2]);
     else if (strstr(line,"xy xz yz")) {
       domain->triclinic = 1;
       sscanf(line,"%lg %lg %lg",&domain->xy,&domain->xz,&domain->yz);
     } else break;
   }
 
   // error check on total system size
 
   if (atom->natoms < 0 || atom->natoms >= MAXBIGINT ||
       atom->nbonds < 0 || atom->nbonds >= MAXBIGINT ||
       atom->nangles < 0 || atom->nangles >= MAXBIGINT ||
       atom->ndihedrals < 0 || atom->ndihedrals >= MAXBIGINT ||
       atom->nimpropers < 0 || atom->nimpropers >= MAXBIGINT)
     error->all(FLERR,"System in data file is too big");
 
   // check that exiting string is a valid section keyword
 
   parse_keyword(1);
   for (n = 0; n < NSECTIONS; n++)
     if (strcmp(keyword,section_keywords[n]) == 0) break;
   if (n == NSECTIONS) {
     char str[128];
     sprintf(str,"Unknown identifier in data file: %s",keyword);
     error->all(FLERR,str);
   }
 
   // error checks on header values
   // must be consistent with atom style and other header values
 
   if ((atom->nbonds || atom->nbondtypes) &&
       atom->avec->bonds_allow == 0)
     error->all(FLERR,"No bonds allowed with this atom style");
   if ((atom->nangles || atom->nangletypes) &&
       atom->avec->angles_allow == 0)
     error->all(FLERR,"No angles allowed with this atom style");
   if ((atom->ndihedrals || atom->ndihedraltypes) &&
       atom->avec->dihedrals_allow == 0)
     error->all(FLERR,"No dihedrals allowed with this atom style");
   if ((atom->nimpropers || atom->nimpropertypes) &&
       atom->avec->impropers_allow == 0)
     error->all(FLERR,"No impropers allowed with this atom style");
   
   if (atom->nbonds > 0 && atom->nbondtypes <= 0)
     error->all(FLERR,"Bonds defined but no bond types");
   if (atom->nangles > 0 && atom->nangletypes <= 0)
     error->all(FLERR,"Angles defined but no angle types");
   if (atom->ndihedrals > 0 && atom->ndihedraltypes <= 0)
     error->all(FLERR,"Dihedrals defined but no dihedral types");
   if (atom->nimpropers > 0 && atom->nimpropertypes <= 0)
     error->all(FLERR,"Impropers defined but no improper types");
 
   if (atom->molecular == 2) {
     if (atom->nbonds || atom->nangles || atom->ndihedrals || atom->nimpropers)
       error->all(FLERR,"No molecule topology allowed with atom style template");
   }
 }
 
 /* ----------------------------------------------------------------------
    read all atoms
 ------------------------------------------------------------------------- */
 
 void ReadData::atoms()
 {
   int nchunk,eof;
 
   if (me == 0) {
     if (screen) fprintf(screen,"  reading atoms ...\n");
     if (logfile) fprintf(logfile,"  reading atoms ...\n");
   }
 
   bigint nread = 0;
   bigint natoms = atom->natoms;
 
   while (nread < natoms) {
     nchunk = MIN(natoms-nread,CHUNK);
     eof = comm->read_lines_from_file(fp,nchunk,MAXLINE,buffer);
     if (eof) error->all(FLERR,"Unexpected end of data file");
     atom->data_atoms(nchunk,buffer);
     nread += nchunk;
   }
 
   // check that all atoms were assigned correctly
 
   bigint tmp = atom->nlocal;
   MPI_Allreduce(&tmp,&natoms,1,MPI_LMP_BIGINT,MPI_SUM,world);
 
   if (me == 0) {
     if (screen) fprintf(screen,"  " BIGINT_FORMAT " atoms\n",natoms);
     if (logfile) fprintf(logfile,"  " BIGINT_FORMAT " atoms\n",natoms);
   }
 
   if (natoms != atom->natoms)
     error->all(FLERR,"Did not assign all atoms correctly");
   
   // check that atom IDs are valid
 
   atom->tag_check();
 
   // create global mapping of atoms
 
   if (atom->map_style) {
     atom->map_init();
     atom->map_set();
   }
 }
 
 /* ----------------------------------------------------------------------
    read all velocities
    to find atoms, must build atom map if not a molecular system
 ------------------------------------------------------------------------- */
 
 void ReadData::velocities()
 {
   int nchunk,eof;
 
   if (me == 0) {
     if (screen) fprintf(screen,"  reading velocities ...\n");
     if (logfile) fprintf(logfile,"  reading velocities ...\n");
   }
 
   int mapflag = 0;
   if (atom->map_style == 0) {
     mapflag = 1;
     atom->map_init();
     atom->map_set();
   }
 
   bigint nread = 0;
   bigint natoms = atom->natoms;
 
   while (nread < natoms) {
     nchunk = MIN(natoms-nread,CHUNK);
     eof = comm->read_lines_from_file(fp,nchunk,MAXLINE,buffer);
     if (eof) error->all(FLERR,"Unexpected end of data file");
     atom->data_vels(nchunk,buffer);
     nread += nchunk;
   }
 
   if (mapflag) {
     atom->map_delete();
     atom->map_style = 0;
   }
 
   if (me == 0) {
     if (screen) fprintf(screen,"  " BIGINT_FORMAT " velocities\n",natoms);
     if (logfile) fprintf(logfile,"  " BIGINT_FORMAT " velocities\n",natoms);
   }
 }
 
 /* ----------------------------------------------------------------------
    scan or read all bonds
 ------------------------------------------------------------------------- */
 
 void ReadData::bonds(int firstpass)
 {
   if (me == 0) {
     if (firstpass) {
       if (screen) fprintf(screen,"  scanning bonds ...\n");
       if (logfile) fprintf(logfile,"  scanning bonds ...\n");
     } else {
       if (screen) fprintf(screen,"  reading bonds ...\n");
       if (logfile) fprintf(logfile,"  reading bonds ...\n");
     }
   }
 
   // allocate count if firstpass
 
   int nlocal = atom->nlocal;
   int *count = NULL;
   if (firstpass) {
     memory->create(count,nlocal,"read_data:count");
     for (int i = 0; i < nlocal; i++) count[i] = 0;
   }
 
   // read and process bonds
 
   int nchunk,eof;
   bigint nread = 0;
   bigint nbonds = atom->nbonds;
 
   while (nread < nbonds) {
     nchunk = MIN(nbonds-nread,CHUNK);
     eof = comm->read_lines_from_file(fp,nchunk,MAXLINE,buffer);
     if (eof) error->all(FLERR,"Unexpected end of data file");
     atom->data_bonds(nchunk,buffer,count);
     nread += nchunk;
   }
 
   // if firstpass: tally max bond/atom and return
 
   if (firstpass) {
     int max = 0;
     for (int i = 0; i < nlocal; i++) max = MAX(max,count[i]);
     int maxall;
     MPI_Allreduce(&max,&maxall,1,MPI_INT,MPI_MAX,world);
     maxall += atom->extra_bond_per_atom;
 
     if (me == 0) {
       if (screen) fprintf(screen,"  %d = max bonds/atom\n",maxall);
       if (logfile) fprintf(logfile,"  %d = max bonds/atom\n",maxall);
     }
     atom->bond_per_atom = maxall;
     memory->destroy(count);
     return;
   }
 
   // if 2nd pass: check that bonds were assigned correctly
 
   bigint n = 0;
   for (int i = 0; i < nlocal; i++) n += atom->num_bond[i];
   bigint sum;
   MPI_Allreduce(&n,&sum,1,MPI_LMP_BIGINT,MPI_SUM,world);
   int factor = 1;
   if (!force->newton_bond) factor = 2;
 
   if (me == 0) {
     if (screen) fprintf(screen,"  " BIGINT_FORMAT " bonds\n",sum/factor);
     if (logfile) fprintf(logfile,"  " BIGINT_FORMAT " bonds\n",sum/factor);
   }
 
   if (sum != factor*atom->nbonds)
     error->all(FLERR,"Bonds assigned incorrectly");
 }
 
 /* ----------------------------------------------------------------------
    scan or read all angles
 ------------------------------------------------------------------------- */
 
 void ReadData::angles(int firstpass)
 {
   if (me == 0) {
     if (firstpass) {
       if (screen) fprintf(screen,"  scanning angles ...\n");
       if (logfile) fprintf(logfile,"  scanning angles ...\n");
     } else {
       if (screen) fprintf(screen,"  reading angles ...\n");
       if (logfile) fprintf(logfile,"  reading angles ...\n");
     }
   }
 
   // allocate count if firstpass
 
   int nlocal = atom->nlocal;
   int *count = NULL;
   if (firstpass) {
     memory->create(count,nlocal,"read_data:count");
     for (int i = 0; i < nlocal; i++) count[i] = 0;
   }
 
   // read and process angles
 
   int nchunk,eof;
   bigint nread = 0;
   bigint nangles = atom->nangles;
 
   while (nread < nangles) {
     nchunk = MIN(nangles-nread,CHUNK);
     eof = comm->read_lines_from_file(fp,nchunk,MAXLINE,buffer);
     if (eof) error->all(FLERR,"Unexpected end of data file");
     atom->data_angles(nchunk,buffer,count);
     nread += nchunk;
   }
 
   // if firstpass: tally max angle/atom and return
 
   if (firstpass) {
     int max = 0;
     for (int i = 0; i < nlocal; i++) max = MAX(max,count[i]);
     int maxall;
     MPI_Allreduce(&max,&maxall,1,MPI_INT,MPI_MAX,world);
     maxall += atom->extra_angle_per_atom;
 
     if (me == 0) {
       if (screen) fprintf(screen,"  %d = max angles/atom\n",maxall);
       if (logfile) fprintf(logfile,"  %d = max angles/atom\n",maxall);
     }
     atom->angle_per_atom = maxall;
     memory->destroy(count);
     return;
   }
 
   // if 2nd pass: check that angles were assigned correctly
 
   bigint n = 0;
   for (int i = 0; i < nlocal; i++) n += atom->num_angle[i];
   bigint sum;
   MPI_Allreduce(&n,&sum,1,MPI_LMP_BIGINT,MPI_SUM,world);
   int factor = 1;
   if (!force->newton_bond) factor = 3;
 
   if (me == 0) {
     if (screen) fprintf(screen,"  " BIGINT_FORMAT " angles\n",sum/factor);
     if (logfile) fprintf(logfile,"  " BIGINT_FORMAT " angles\n",sum/factor);
   }
 
   if (sum != factor*atom->nangles)
     error->all(FLERR,"Angles assigned incorrectly");
 }
 
 /* ----------------------------------------------------------------------
    scan or read all dihedrals
 ------------------------------------------------------------------------- */
 
 void ReadData::dihedrals(int firstpass)
 {
   if (me == 0) {
     if (firstpass) {
       if (screen) fprintf(screen,"  scanning dihedrals ...\n");
       if (logfile) fprintf(logfile,"  scanning dihedrals ...\n");
     } else {
       if (screen) fprintf(screen,"  reading dihedrals ...\n");
       if (logfile) fprintf(logfile,"  reading dihedrals ...\n");
     }
   }
 
   // allocate count if firstpass
 
   int nlocal = atom->nlocal;
   int *count = NULL;
   if (firstpass) {
     memory->create(count,nlocal,"read_data:count");
     for (int i = 0; i < nlocal; i++) count[i] = 0;
   }
 
   // read and process dihedrals
 
   int nchunk,eof;
   bigint nread = 0;
   bigint ndihedrals = atom->ndihedrals;
 
   while (nread < ndihedrals) {
     nchunk = MIN(ndihedrals-nread,CHUNK);
     eof = comm->read_lines_from_file(fp,nchunk,MAXLINE,buffer);
     if (eof) error->all(FLERR,"Unexpected end of data file");
     atom->data_dihedrals(nchunk,buffer,count);
     nread += nchunk;
   }
 
   // if firstpass: tally max dihedral/atom and return
 
   if (firstpass) {
     int max = 0;
     for (int i = 0; i < nlocal; i++) max = MAX(max,count[i]);
     int maxall;
     MPI_Allreduce(&max,&maxall,1,MPI_INT,MPI_MAX,world);
     maxall += atom->extra_dihedral_per_atom;
 
     if (me == 0) {
       if (screen) fprintf(screen,"  %d = max dihedrals/atom\n",maxall);
       if (logfile) fprintf(logfile,"  %d = max dihedrals/atom\n",maxall);
     }
     atom->dihedral_per_atom = maxall;
     memory->destroy(count);
     return;
   }
 
   // if 2nd pass: check that dihedrals were assigned correctly
 
   bigint n = 0;
   for (int i = 0; i < nlocal; i++) n += atom->num_dihedral[i];
   bigint sum;
   MPI_Allreduce(&n,&sum,1,MPI_LMP_BIGINT,MPI_SUM,world);
   int factor = 1;
   if (!force->newton_bond) factor = 4;
 
   if (me == 0) {
     if (screen) fprintf(screen,"  " BIGINT_FORMAT " dihedrals\n",sum/factor);
     if (logfile) fprintf(logfile,"  " BIGINT_FORMAT " dihedrals\n",sum/factor);
   }
 
   if (sum != factor*atom->ndihedrals)
     error->all(FLERR,"Dihedrals assigned incorrectly");
 }
 
 /* ----------------------------------------------------------------------
    scan or read all impropers
 ------------------------------------------------------------------------- */
 
 void ReadData::impropers(int firstpass)
 {
   if (me == 0) {
     if (firstpass) {
       if (screen) fprintf(screen,"  scanning impropers ...\n");
       if (logfile) fprintf(logfile,"  scanning impropers ...\n");
     } else {
       if (screen) fprintf(screen,"  reading impropers ...\n");
       if (logfile) fprintf(logfile,"  reading impropers ...\n");
     }
   }
 
   // allocate count if firstpass
 
   int nlocal = atom->nlocal;
   int *count = NULL;
   if (firstpass) {
     memory->create(count,nlocal,"read_data:count");
     for (int i = 0; i < nlocal; i++) count[i] = 0;
   }
 
   // read and process impropers
 
   int nchunk,eof;
   bigint nread = 0;
   bigint nimpropers = atom->nimpropers;
 
   while (nread < nimpropers) {
     nchunk = MIN(nimpropers-nread,CHUNK);
     eof = comm->read_lines_from_file(fp,nchunk,MAXLINE,buffer);
     if (eof) error->all(FLERR,"Unexpected end of data file");
     atom->data_impropers(nchunk,buffer,count);
     nread += nchunk;
   }
 
   // if firstpass: tally max improper/atom and return
 
   if (firstpass) {
     int max = 0;
     for (int i = 0; i < nlocal; i++) max = MAX(max,count[i]);
     int maxall;
     MPI_Allreduce(&max,&maxall,1,MPI_INT,MPI_MAX,world);
     maxall += atom->extra_improper_per_atom;
 
     if (me == 0) {
       if (screen) fprintf(screen,"  %d = max impropers/atom\n",maxall);
       if (logfile) fprintf(logfile,"  %d = max impropers/atom\n",maxall);
     }
     atom->improper_per_atom = maxall;
     memory->destroy(count);
     return;
   }
 
   // if 2nd pass: check that impropers were assigned correctly
 
   bigint n = 0;
   for (int i = 0; i < nlocal; i++) n += atom->num_improper[i];
   bigint sum;
   MPI_Allreduce(&n,&sum,1,MPI_LMP_BIGINT,MPI_SUM,world);
   int factor = 1;
   if (!force->newton_bond) factor = 4;
 
   if (me == 0) {
     if (screen) fprintf(screen,"  " BIGINT_FORMAT " impropers\n",sum/factor);
     if (logfile) fprintf(logfile,"  " BIGINT_FORMAT " impropers\n",sum/factor);
   }
 
   if (sum != factor*atom->nimpropers)
     error->all(FLERR,"Impropers assigned incorrectly");
 }
 
 /* ----------------------------------------------------------------------
    read all bonus data
    to find atoms, must build atom map if not a molecular system
 ------------------------------------------------------------------------- */
 
 void ReadData::bonus(bigint nbonus, AtomVec *ptr, const char *type)
 {
   int nchunk,eof;
 
   int mapflag = 0;
   if (atom->map_style == 0) {
     mapflag = 1;
     atom->map_init();
     atom->map_set();
   }
 
   bigint nread = 0;
   bigint natoms = nbonus;
 
   while (nread < natoms) {
     nchunk = MIN(natoms-nread,CHUNK);
     eof = comm->read_lines_from_file(fp,nchunk,MAXLINE,buffer);
     if (eof) error->all(FLERR,"Unexpected end of data file");
     atom->data_bonus(nchunk,buffer,ptr);
     nread += nchunk;
   }
 
   if (mapflag) {
     atom->map_delete();
     atom->map_style = 0;
   }
 
   if (me == 0) {
     if (screen) fprintf(screen,"  " BIGINT_FORMAT " %s\n",natoms,type);
     if (logfile) fprintf(logfile,"  " BIGINT_FORMAT " %s\n",natoms,type);
   }
 }
 
 /* ----------------------------------------------------------------------
    read all body data
    variable amount of info per body, described by ninteger and ndouble
    to find atoms, must build atom map if not a molecular system
    if not firstpass, just read but no processing of data
 ------------------------------------------------------------------------- */
 
 void ReadData::bodies(int firstpass)
 {
   int i,m,nchunk,nline,nmax,ninteger,ndouble,tmp,onebody;
   char *eof;
 
   int mapflag = 0;
   if (atom->map_style == 0 && firstpass) {
     mapflag = 1;
     atom->map_init();
     atom->map_set();
   }
 
   // nmax = max # of bodies to read in this chunk
   // nchunk = actual # read
 
   bigint nread = 0;
   bigint natoms = nbodies;
 
   while (nread < natoms) {
     if (natoms-nread > CHUNK) nmax = CHUNK;
     else nmax = natoms-nread;
 
     if (me == 0) {
       nchunk = 0;
       nline = 0;
       m = 0;
 
       while (nchunk < nmax && nline <= CHUNK-MAXBODY) {
         eof = fgets(&buffer[m],MAXLINE,fp);
         if (eof == NULL) error->one(FLERR,"Unexpected end of data file");
         sscanf(&buffer[m],"%d %d %d",&tmp,&ninteger,&ndouble);
         m += strlen(&buffer[m]);
 
         onebody = 0;
         if (ninteger) onebody += (ninteger-1)/10 + 1;
         if (ndouble) onebody += (ndouble-1)/10 + 1;
         if (onebody+1 > MAXBODY)
           error->one(FLERR,
                      "Too many lines in one body in data file - boost MAXBODY");
 
         for (i = 0; i < onebody; i++) {
           eof = fgets(&buffer[m],MAXLINE,fp);
           if (eof == NULL) error->one(FLERR,"Unexpected end of data file");
           m += strlen(&buffer[m]);
         }
 
         nchunk++;
         nline += onebody+1;
       }
 
       if (buffer[m-1] != '\n') strcpy(&buffer[m++],"\n");
       m++;
     }
 
     MPI_Bcast(&nchunk,1,MPI_INT,0,world);
     MPI_Bcast(&m,1,MPI_INT,0,world);
     MPI_Bcast(buffer,m,MPI_CHAR,0,world);
 
     if (firstpass) atom->data_bodies(nchunk,buffer,avec_body);
     nread += nchunk;
   }
 
   if (mapflag && firstpass) {
     atom->map_delete();
     atom->map_style = 0;
   }
 
   if (me == 0 && firstpass) {
     if (screen) fprintf(screen,"  " BIGINT_FORMAT " bodies\n",natoms);
     if (logfile) fprintf(logfile,"  " BIGINT_FORMAT " bodies\n",natoms);
   }
 }
 
 /* ---------------------------------------------------------------------- */
 
 void ReadData::mass()
 {
   char *next;
   char *buf = new char[atom->ntypes*MAXLINE];
 
   int eof = comm->read_lines_from_file(fp,atom->ntypes,MAXLINE,buf);
   if (eof) error->all(FLERR,"Unexpected end of data file");
 
   char *original = buf;
   for (int i = 0; i < atom->ntypes; i++) {
     next = strchr(buf,'\n');
     *next = '\0';
     atom->set_mass(buf);
     buf = next + 1;
   }
   delete [] original;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void ReadData::paircoeffs()
 {
   char *next;
   char *buf = new char[atom->ntypes*MAXLINE];
 
   int eof = comm->read_lines_from_file(fp,atom->ntypes,MAXLINE,buf);
   if (eof) error->all(FLERR,"Unexpected end of data file");
 
   char *original = buf;
   for (int i = 0; i < atom->ntypes; i++) {
     next = strchr(buf,'\n');
     *next = '\0';
     parse_coeffs(buf,NULL,1);
     if (narg == 0) error->all(FLERR,"Unexpected end of PairCoeffs section");
     force->pair->coeff(narg,arg);
     buf = next + 1;
   }
   delete [] original;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void ReadData::pairIJcoeffs()
 {
   int i,j;
   char *next;
   
   int nsq = atom->ntypes* (atom->ntypes+1) / 2;
   char *buf = new char[nsq * MAXLINE];
 
   int eof = comm->read_lines_from_file(fp,nsq,MAXLINE,buf);
   if (eof) error->all(FLERR,"Unexpected end of data file");
 
   char *original = buf;
   for (i = 0; i < atom->ntypes; i++)
     for (j = i; j < atom->ntypes; j++) {
       next = strchr(buf,'\n');
       *next = '\0';
       parse_coeffs(buf,NULL,0);
       if (narg == 0) error->all(FLERR,"Unexpected end of PairCoeffs section");
       force->pair->coeff(narg,arg);
       buf = next + 1;
     }
   delete [] original;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void ReadData::bondcoeffs()
 {
   char *next;
   char *buf = new char[atom->nbondtypes*MAXLINE];
 
   int eof = comm->read_lines_from_file(fp,atom->nbondtypes,MAXLINE,buf);
   if (eof) error->all(FLERR,"Unexpected end of data file");
 
   char *original = buf;
   for (int i = 0; i < atom->nbondtypes; i++) {
     next = strchr(buf,'\n');
     *next = '\0';
     parse_coeffs(buf,NULL,0);
     if (narg == 0) error->all(FLERR,"Unexpected end of BondCoeffs section");
     force->bond->coeff(narg,arg);
     buf = next + 1;
   }
   delete [] original;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void ReadData::anglecoeffs(int which)
 {
   char *next;
   char *buf = new char[atom->nangletypes*MAXLINE];
 
   int eof = comm->read_lines_from_file(fp,atom->nangletypes,MAXLINE,buf);
   if (eof) error->all(FLERR,"Unexpected end of data file");
 
   char *original = buf;
   for (int i = 0; i < atom->nangletypes; i++) {
     next = strchr(buf,'\n');
     *next = '\0';
     if (which == 0) parse_coeffs(buf,NULL,0);
     else if (which == 1) parse_coeffs(buf,"bb",0);
     else if (which == 2) parse_coeffs(buf,"ba",0);
     if (narg == 0) error->all(FLERR,"Unexpected end of AngleCoeffs section");
     force->angle->coeff(narg,arg);
     buf = next + 1;
   }
   delete [] original;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void ReadData::dihedralcoeffs(int which)
 {
   char *next;
   char *buf = new char[atom->ndihedraltypes*MAXLINE];
 
   int eof = comm->read_lines_from_file(fp,atom->ndihedraltypes,MAXLINE,buf);
   if (eof) error->all(FLERR,"Unexpected end of data file");
 
   char *original = buf;
   for (int i = 0; i < atom->ndihedraltypes; i++) {
     next = strchr(buf,'\n');
     *next = '\0';
     if (which == 0) parse_coeffs(buf,NULL,0);
     else if (which == 1) parse_coeffs(buf,"mbt",0);
     else if (which == 2) parse_coeffs(buf,"ebt",0);
     else if (which == 3) parse_coeffs(buf,"at",0);
     else if (which == 4) parse_coeffs(buf,"aat",0);
     else if (which == 5) parse_coeffs(buf,"bb13",0);
     if (narg == 0) error->all(FLERR,"Unexpected end of DihedralCoeffs section");
     force->dihedral->coeff(narg,arg);
     buf = next + 1;
   }
   delete [] original;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void ReadData::impropercoeffs(int which)
 {
   char *next;
   char *buf = new char[atom->nimpropertypes*MAXLINE];
 
   int eof = comm->read_lines_from_file(fp,atom->nimpropertypes,MAXLINE,buf);
   if (eof) error->all(FLERR,"Unexpected end of data file");
 
   char *original = buf;
   for (int i = 0; i < atom->nimpropertypes; i++) {
     next = strchr(buf,'\n');
     *next = '\0';
     if (which == 0) parse_coeffs(buf,NULL,0);
     else if (which == 1) parse_coeffs(buf,"aa",0);
     if (narg == 0) error->all(FLERR,"Unexpected end of ImproperCoeffs section");
     force->improper->coeff(narg,arg);
     buf = next + 1;
   }
   delete [] original;
 }
 
 /* ----------------------------------------------------------------------
    read fix section, pass lines to fix to process
    n = index of fix
 ------------------------------------------------------------------------- */
 
 void ReadData::fix(int ifix, char *keyword)
 {
   int nchunk,eof;
 
   bigint nline = modify->fix[ifix]->read_data_skip_lines(keyword);
 
   bigint nread = 0;
   while (nread < nline) {
     nchunk = MIN(nline-nread,CHUNK);
     eof = comm->read_lines_from_file(fp,nchunk,MAXLINE,buffer);
     if (eof) error->all(FLERR,"Unexpected end of data file");
     modify->fix[ifix]->read_data_section(keyword,nchunk,buffer);
     nread += nchunk;
   }
 }
 
 /* ----------------------------------------------------------------------
    reallocate the count vector from cmax to amax+1 and return new length
    zero new locations
 ------------------------------------------------------------------------- */
 
 int ReadData::reallocate(int **pcount, int cmax, int amax)
 {
   int *count = *pcount;
   memory->grow(count,amax+1,"read_data:count");
   for (int i = cmax; i <= amax; i++) count[i] = 0;
   *pcount = count;
   return amax+1;
 }
 
 /* ----------------------------------------------------------------------
    proc 0 opens data file
    test if gzipped
 ------------------------------------------------------------------------- */
 
 void ReadData::open(char *file)
 {
   compressed = 0;
   char *suffix = file + strlen(file) - 3;
   if (suffix > file && strcmp(suffix,".gz") == 0) compressed = 1;
   if (!compressed) fp = fopen(file,"r");
   else {
 #ifdef LAMMPS_GZIP
     char gunzip[128];
     sprintf(gunzip,"gzip -c -d %s",file);
 
 #ifdef _WIN32
     fp = _popen(gunzip,"rb");
 #else
     fp = popen(gunzip,"r");
 #endif
 
 #else
     error->one(FLERR,"Cannot open gzipped file");
 #endif
   }
 
   if (fp == NULL) {
     char str[128];
     sprintf(str,"Cannot open file %s",file);
     error->one(FLERR,str);
   }
 }
 
 /* ----------------------------------------------------------------------
    grab next keyword
    read lines until one is non-blank
    keyword is all text on line w/out leading & trailing white space
    optional style can be appended after comment char '#'
    read one additional line (assumed blank)
    if any read hits EOF, set keyword to empty
    if first = 1, line variable holds non-blank line that ended header
 ------------------------------------------------------------------------- */
 
 void ReadData::parse_keyword(int first)
 {
   int eof = 0;
 
   // proc 0 reads upto non-blank line plus 1 following line
   // eof is set to 1 if any read hits end-of-file
 
   if (me == 0) {
     if (!first) {
       if (fgets(line,MAXLINE,fp) == NULL) eof = 1;
     }
     while (eof == 0 && strspn(line," \t\n\r") == strlen(line)) {
       if (fgets(line,MAXLINE,fp) == NULL) eof = 1;
     }
     if (fgets(buffer,MAXLINE,fp) == NULL) eof = 1;
   }
 
   // if eof, set keyword empty and return
 
   MPI_Bcast(&eof,1,MPI_INT,0,world);
   if (eof) {
     keyword[0] = '\0';
     return;
   }
 
   // bcast keyword line to all procs
 
   int n;
   if (me == 0) n = strlen(line) + 1;
   MPI_Bcast(&n,1,MPI_INT,0,world);
   MPI_Bcast(line,n,MPI_CHAR,0,world);
 
   // store optional "style" following comment char '#' after keyword
 
   char *ptr;
   if ((ptr = strchr(line,'#'))) {
     *ptr++ = '\0';
     while (*ptr == ' ' || *ptr == '\t') ptr++;
     int stop = strlen(ptr) - 1;
     while (ptr[stop] == ' ' || ptr[stop] == '\t'
            || ptr[stop] == '\n' || ptr[stop] == '\r') stop--;
     ptr[stop+1] = '\0';
     strcpy(style,ptr);
   } else style[0] = '\0';
 
   // copy non-whitespace portion of line into keyword
 
   int start = strspn(line," \t\n\r");
   int stop = strlen(line) - 1;
   while (line[stop] == ' ' || line[stop] == '\t'
          || line[stop] == '\n' || line[stop] == '\r') stop--;
   line[stop+1] = '\0';
   strcpy(keyword,&line[start]);
 }
 
 /* ----------------------------------------------------------------------
    proc 0 reads N lines from file
    could be skipping Natoms lines, so use bigints
 ------------------------------------------------------------------------- */
 
 void ReadData::skip_lines(bigint n)
 {
   if (me) return;
   char *eof;
   for (bigint i = 0; i < n; i++) eof = fgets(line,MAXLINE,fp);
   if (eof == NULL) error->one(FLERR,"Unexpected end of data file");
 }
 
 /* ----------------------------------------------------------------------
    parse a line of coeffs into words, storing them in narg,arg
    trim anything from '#' onward
    word strings remain in line, are not copied
    if addstr != NULL, add addstr as extra arg for class2 angle/dihedral/improper
      if 2nd word starts with letter, then is hybrid style, add addstr after it
      else add addstr before 2nd word
    if dupflag, duplicate 1st word, so pair_coeff "2" becomes "2 2"
 ------------------------------------------------------------------------- */
 
 void ReadData::parse_coeffs(char *line, const char *addstr, int dupflag)
 {
   char *ptr;
   if ((ptr = strchr(line,'#'))) *ptr = '\0';
 
   narg = 0;
   char *word = strtok(line," \t\n\r\f");
   while (word) {
     if (narg == maxarg) {
       maxarg += DELTA;
       arg = (char **)
         memory->srealloc(arg,maxarg*sizeof(char *),"read_data:arg");
     }
     if (addstr && narg == 1 && !islower(word[0])) arg[narg++] = (char *) addstr;
     arg[narg++] = word;
     if (addstr && narg == 2 && islower(word[0])) arg[narg++] = (char *) addstr;
     if (dupflag && narg == 1) arg[narg++] = word;
     word = strtok(NULL," \t\n\r\f");
   }
 }
 
 /* ----------------------------------------------------------------------
    compare two style strings if they both exist
    one = comment in data file section, two = currently-defined style
    ignore suffixes listed in suffixes array at top of file
 ------------------------------------------------------------------------- */
 
 int ReadData::style_match(const char *one, const char *two)
 {
   int i,delta,len,len1,len2;
 
   if ((one == NULL) || (two == NULL)) return 1;
 
   len1 = strlen(one);
   len2 = strlen(two);
 
   for (i = 0; suffixes[i] != NULL; i++) {
     len = strlen(suffixes[i]);
     if ((delta = len1 - len) > 0)
       if (strcmp(one+delta,suffixes[i]) == 0) len1 = delta;
     if ((delta = len2 - len) > 0)
       if (strcmp(two+delta,suffixes[i]) == 0) len2 = delta;
   }
 
   if ((len1 == 0) || (len1 == len2) || (strncmp(one,two,len1) == 0)) return 1;
   return 0;
 }
diff --git a/src/read_dump.cpp b/src/read_dump.cpp
index 14b208e99..45ff1f81b 100644
--- a/src/read_dump.cpp
+++ b/src/read_dump.cpp
@@ -1,960 +1,965 @@
 /* ----------------------------------------------------------------------
    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: Timothy Sirk (ARL)
 ------------------------------------------------------------------------- */
 
+// lmptype.h must be first b/c this file uses MAXBIGINT and includes mpi.h
+// due to OpenMPI bug which sets INT64_MAX via its mpi.h
+//   before lmptype.h can set flags to insure it is done correctly
+
+#include "lmptype.h" 
 #include "mpi.h"
 #include "string.h"
 #include "stdlib.h"
 #include "read_dump.h"
 #include "reader.h"
 #include "style_reader.h"
 #include "atom.h"
 #include "atom_vec.h"
 #include "update.h"
 #include "modify.h"
 #include "fix.h"
 #include "domain.h"
 #include "comm.h"
 #include "irregular.h"
 #include "error.h"
 #include "memory.h"
 
 using namespace LAMMPS_NS;
 
 #define CHUNK 1024
 #define EPSILON 1.0e-6
 
 // also in reader_native.cpp
 
 enum{ID,TYPE,X,Y,Z,VX,VY,VZ,Q,IX,IY,IZ};
 enum{UNSET,NOSCALE_NOWRAP,NOSCALE_WRAP,SCALE_NOWRAP,SCALE_WRAP};
 
 /* ---------------------------------------------------------------------- */
 
 ReadDump::ReadDump(LAMMPS *lmp) : Pointers(lmp)
 {
   MPI_Comm_rank(world,&me);
   MPI_Comm_size(world,&nprocs);
 
   dimension = domain->dimension;
   triclinic = domain->triclinic;
 
   nfile = 0;
   files = NULL;
 
   nfield = 0;
   fieldtype = NULL;
   fieldlabel = NULL;
   fields = NULL;
 
   int n = strlen("native") + 1;
   readerstyle = new char[n];
   strcpy(readerstyle,"native");
 
   reader = NULL;
   fp = NULL;
 }
 
 /* ---------------------------------------------------------------------- */
 
 ReadDump::~ReadDump()
 {
   for (int i = 0; i < nfile; i++) delete [] files[i];
   delete [] files;
   for (int i = 0; i < nfield; i++) delete [] fieldlabel[i];
   delete [] fieldlabel;
   delete [] fieldtype;
   delete [] readerstyle;
 
   memory->destroy(fields);
   delete reader;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void ReadDump::command(int narg, char **arg)
 {
   if (domain->box_exist == 0)
     error->all(FLERR,"Read_dump command before simulation box is defined");
 
   if (narg < 2) error->all(FLERR,"Illegal read_dump command");
 
   store_files(1,&arg[0]);
   bigint nstep = ATOBIGINT(arg[1]);
 
   int nremain = narg - 2;
   if (nremain) nremain = fields_and_keywords(nremain,&arg[narg-nremain]);
   else nremain = fields_and_keywords(0,NULL);
   if (nremain) setup_reader(nremain,&arg[narg-nremain]);
   else setup_reader(0,NULL);
 
   // find the snapshot and read/bcast/process header info
 
   if (me == 0 && screen) fprintf(screen,"Scanning dump file ...\n");
 
   bigint ntimestep = seek(nstep,1);
   if (ntimestep < 0)
     error->all(FLERR,"Dump file does not contain requested snapshot");
   header(1);
 
   // reset timestep to nstep
 
   update->reset_timestep(nstep);
 
   // counters
 
   // read in the snapshot and reset system
 
   if (me == 0 && screen)
     fprintf(screen,"Reading snapshot from dump file ...\n");
 
   bigint natoms_prev = atom->natoms;
   atoms();
 
   if (me == 0) reader->close_file();
 
   // print out stats
 
   bigint npurge_all,nreplace_all,ntrim_all,nadd_all;
 
   bigint tmp;
   tmp = npurge;
   MPI_Allreduce(&tmp,&npurge_all,1,MPI_LMP_BIGINT,MPI_SUM,world);
   tmp = nreplace;
   MPI_Allreduce(&tmp,&nreplace_all,1,MPI_LMP_BIGINT,MPI_SUM,world);
   tmp = ntrim;
   MPI_Allreduce(&tmp,&ntrim_all,1,MPI_LMP_BIGINT,MPI_SUM,world);
   tmp = nadd;
   MPI_Allreduce(&tmp,&nadd_all,1,MPI_LMP_BIGINT,MPI_SUM,world);
 
   domain->print_box("  ");
 
   if (me == 0) {
     if (screen) {
       fprintf(screen,"  " BIGINT_FORMAT " atoms before read\n",natoms_prev);
       fprintf(screen,"  " BIGINT_FORMAT " atoms in snapshot\n",nsnapatoms);
       fprintf(screen,"  " BIGINT_FORMAT " atoms purged\n",npurge_all);
       fprintf(screen,"  " BIGINT_FORMAT " atoms replaced\n",nreplace_all);
       fprintf(screen,"  " BIGINT_FORMAT " atoms trimmed\n",ntrim_all);
       fprintf(screen,"  " BIGINT_FORMAT " atoms added\n",nadd_all);
       fprintf(screen,"  " BIGINT_FORMAT " atoms after read\n",atom->natoms);
     }
     if (logfile) {
       fprintf(logfile,"  " BIGINT_FORMAT " atoms before read\n",natoms_prev);
       fprintf(logfile,"  " BIGINT_FORMAT " atoms in snapshot\n",nsnapatoms);
       fprintf(logfile,"  " BIGINT_FORMAT " atoms purged\n",npurge_all);
       fprintf(logfile,"  " BIGINT_FORMAT " atoms replaced\n",nreplace_all);
       fprintf(logfile,"  " BIGINT_FORMAT " atoms trimmed\n",ntrim_all);
       fprintf(logfile,"  " BIGINT_FORMAT " atoms added\n",nadd_all);
       fprintf(logfile,"  " BIGINT_FORMAT " atoms after read\n",atom->natoms);
     }
   }
 }
 
 /* ---------------------------------------------------------------------- */
 
 void ReadDump::store_files(int nstr, char **str)
 {
   nfile = nstr;
   files = new char*[nfile];
 
   for (int i = 0; i < nfile; i++) {
     int n = strlen(str[i]) + 1;
     files[i] = new char[n];
     strcpy(files[i],str[i]);
   }
 }
 
 /* ---------------------------------------------------------------------- */
 
 void ReadDump::setup_reader(int narg, char **arg)
 {
   // allocate snapshot field buffer
 
   memory->create(fields,CHUNK,nfield,"read_dump:fields");
 
   // create reader class
   // match readerstyle to options in style_reader.h
 
   if (0) return;        // dummy line to enable else-if macro expansion
 
 #define READER_CLASS
 #define ReaderStyle(key,Class) \
   else if (strcmp(readerstyle,#key) == 0) reader = new Class(lmp);
 #include "style_reader.h"
 #undef READER_CLASS
 
   // unrecognized style
 
   else error->all(FLERR,"Unknown dump reader style");
 
   // pass any arguments to reader
 
   if (narg > 0) reader->settings(narg,arg);
 }
 
 /* ----------------------------------------------------------------------
    seek Nrequest timestep in one or more dump files
    if exact = 1, must find exactly Nrequest
    if exact = 0, find first step >= Nrequest
    return matching ntimestep or -1 if did not find a match
 ------------------------------------------------------------------------- */
 
 bigint ReadDump::seek(bigint nrequest, int exact)
 {
   int ifile,eofflag;
   bigint ntimestep;
 
   if (me == 0) {
 
     // exit file loop when dump timestep >= nrequest
     // or files exhausted
 
     for (ifile = 0; ifile < nfile; ifile++) {
       ntimestep = -1;
       reader->open_file(files[ifile]);
       while (1) {
         eofflag = reader->read_time(ntimestep);
         if (eofflag) break;
         if (ntimestep >= nrequest) break;
         reader->skip();
       }
       if (ntimestep >= nrequest) break;
       reader->close_file();
     }
 
     currentfile = ifile;
     if (ntimestep < nrequest) ntimestep = -1;
     if (exact && ntimestep != nrequest) ntimestep = -1;
     if (ntimestep < 0) reader->close_file();
   }
 
   MPI_Bcast(&ntimestep,1,MPI_LMP_BIGINT,0,world);
   return ntimestep;
 }
 
 /* ----------------------------------------------------------------------
    find next matching snapshot in one or more dump files
    Ncurrent = current timestep from last snapshot
    Nlast = match no timestep bigger than Nlast
    Nevery = only match timesteps that are a multiple of Nevery
    Nskip = skip every this many timesteps
    return matching ntimestep or -1 if did not find a match
 ------------------------------------------------------------------------- */
 
 bigint ReadDump::next(bigint ncurrent, bigint nlast, int nevery, int nskip)
 {
   int ifile,eofflag;
   bigint ntimestep;
 
   if (me == 0) {
 
     // exit file loop when dump timestep matches all criteria
     // or files exhausted
 
     int iskip = 0;
 
     for (ifile = currentfile; ifile < nfile; ifile++) {
       ntimestep = -1;
       if (ifile != currentfile) reader->open_file(files[ifile]);
       while (1) {
         eofflag = reader->read_time(ntimestep);
         if (iskip == nskip) iskip = 0;
         iskip++;
         if (eofflag) break;
         if (ntimestep <= ncurrent) break;
         if (ntimestep > nlast) break;
         if (nevery && ntimestep % nevery) reader->skip();
         else if (iskip < nskip) reader->skip();
         else break;
       }
       if (eofflag) reader->close_file();
       else break;
     }
 
     currentfile = ifile;
     if (eofflag) ntimestep = -1;
     if (ntimestep <= ncurrent) ntimestep = -1;
     if (ntimestep > nlast) ntimestep = -1;
     if (ntimestep < 0) reader->close_file();
   }
 
   MPI_Bcast(&ntimestep,1,MPI_LMP_BIGINT,0,world);
   return ntimestep;
 }
 
 /* ----------------------------------------------------------------------
    read and broadcast and store snapshot header info
    set nsnapatoms = # of atoms in snapshot
 ------------------------------------------------------------------------- */
 
 void ReadDump::header(int fieldinfo)
 {
   int triclinic_snap;
   int fieldflag,xflag,yflag,zflag;
 
   if (me == 0)
     nsnapatoms = reader->read_header(box,triclinic_snap,
                                      fieldinfo,nfield,fieldtype,fieldlabel,
                                      scaleflag,wrapflag,fieldflag,
                                      xflag,yflag,zflag);
 
   MPI_Bcast(&nsnapatoms,1,MPI_LMP_BIGINT,0,world);
   MPI_Bcast(&triclinic_snap,1,MPI_INT,0,world);
   MPI_Bcast(&box[0][0],9,MPI_DOUBLE,0,world);
 
   // local copy of snapshot box parameters
   // used in xfield,yfield,zfield when converting dump atom to absolute coords
 
   xlo = box[0][0];
   xhi = box[0][1];
   ylo = box[1][0];
   yhi = box[1][1];
   zlo = box[2][0];
   zhi = box[2][1];
   if (triclinic_snap) {
     xy = box[0][2];
     xz = box[1][2];
     yz = box[2][2];
     double xdelta = MIN(0.0,xy);
     xdelta = MIN(xdelta,xz);
     xdelta = MIN(xdelta,xy+xz);
     xlo = xlo - xdelta;
     xdelta = MAX(0.0,xy);
     xdelta = MAX(xdelta,xz);
     xdelta = MAX(xdelta,xy+xz);
     xhi = xhi - xdelta;
     ylo = ylo - MIN(0.0,yz);
     yhi = yhi - MAX(0.0,yz);
   }
   xprd = xhi - xlo;
   yprd = yhi - ylo;
   zprd = zhi - zlo;
 
   // done if not checking fields
 
   if (!fieldinfo) return;
 
   MPI_Bcast(&fieldflag,1,MPI_INT,0,world);
   MPI_Bcast(&xflag,1,MPI_INT,0,world);
   MPI_Bcast(&yflag,1,MPI_INT,0,world);
   MPI_Bcast(&zflag,1,MPI_INT,0,world);
 
   // error check on current vs new box and fields
   // triclinic_snap < 0 means no box info in file
 
   if (triclinic_snap < 0 && boxflag > 0)
     error->all(FLERR,"No box information in dump. You have to use 'box no'");
   if (triclinic_snap >= 0) {
     if ((triclinic_snap && !triclinic) ||
         (!triclinic_snap && triclinic))
       error->one(FLERR,"Read_dump triclinic status does not match simulation");
   }
 
   // error check on requested fields exisiting in dump file
 
   if (fieldflag < 0)
     error->one(FLERR,"Read_dump field not found in dump file");
 
   // all explicitly requested x,y,z must have consistent scaling & wrapping
 
   int value = MAX(xflag,yflag);
   value = MAX(zflag,value);
   if ((xflag != UNSET && xflag != value) ||
       (yflag != UNSET && yflag != value) ||
       (zflag != UNSET && zflag != value))
     error->one(FLERR,
                "Read_dump xyz fields do not have consistent scaling/wrapping");
 
   // set scaled/wrapped based on xyz flags
 
   value = UNSET;
   if (xflag != UNSET) value = xflag;
   if (yflag != UNSET) value = yflag;
   if (zflag != UNSET) value = zflag;
 
   if (value == UNSET) {
     scaled = wrapped = 0;
   } else if (value == NOSCALE_NOWRAP) {
     scaled = wrapped = 0;
   } else if (value == NOSCALE_WRAP) {
     scaled = 0;
     wrapped = 1;
   } else if (value == SCALE_NOWRAP) {
     scaled = 1;
     wrapped = 0;
   } else if (value == SCALE_WRAP) {
     scaled = wrapped = 1;
   }
 
   // scaled, triclinic coords require all 3 x,y,z fields, to perform unscaling
   // set yindex,zindex = column index of Y and Z fields in fields array
   // needed for unscaling to absolute coords in xfield(), yfield(), zfield()
 
   if (scaled && triclinic == 1) {
     int flag = 0;
     if (xflag == UNSET) flag = 1;
     if (yflag == UNSET) flag = 1;
     if (dimension == 3 && zflag == UNSET) flag = 1;
     if (flag)
       error->one(FLERR,"All read_dump x,y,z fields must be specified for "
                  "scaled, triclinic coords");
 
     for (int i = 0; i < nfield; i++) {
       if (fieldtype[i] == Y) yindex = i;
       if (fieldtype[i] == Z) zindex = i;
     }
   }
 }
 
 /* ---------------------------------------------------------------------- */
 
 void ReadDump::atoms()
 {
   // initialize counters
 
   npurge = nreplace = ntrim = nadd = 0;
 
   // if purgeflag set, delete all current atoms
 
   if (purgeflag) {
     if (atom->map_style) atom->map_clear();
     npurge = atom->nlocal;
     atom->nlocal = atom->nghost = 0;
     atom->natoms = 0;
   }
 
   // to match existing atoms to dump atoms:
   // must build map if not a molecular system
 
   int mapflag = 0;
   if (atom->map_style == 0) {
     mapflag = 1;
     atom->map_init();
     atom->map_set();
   }
 
   // uflag[i] = 1 for each owned atom appearing in dump
   // ucflag = similar flag for each chunk atom, used in process_atoms()
 
   int nlocal = atom->nlocal;
   memory->create(uflag,nlocal,"read_dump:uflag");
   for (int i = 0; i < nlocal; i++) uflag[i] = 0;
   memory->create(ucflag,CHUNK,"read_dump:ucflag");
   memory->create(ucflag_all,CHUNK,"read_dump:ucflag");
 
   // read, broadcast, and process atoms from snapshot in chunks
 
   addproc = -1;
 
   int nchunk;
   bigint nread = 0;
   while (nread < nsnapatoms) {
     nchunk = MIN(nsnapatoms-nread,CHUNK);
     if (me == 0) reader->read_atoms(nchunk,nfield,fields);
     MPI_Bcast(&fields[0][0],nchunk*nfield,MPI_DOUBLE,0,world);
     process_atoms(nchunk);
     nread += nchunk;
   }
 
   // if addflag set, add tags to new atoms if possible
 
   if (addflag) {
     bigint nblocal = atom->nlocal;
     MPI_Allreduce(&nblocal,&atom->natoms,1,MPI_LMP_BIGINT,MPI_SUM,world);
     if (atom->natoms < 0 || atom->natoms >= MAXBIGINT)
       error->all(FLERR,"Too many total atoms");
     if (atom->tag_enable) atom->tag_extend();
   }
 
   // if trimflag set, delete atoms not replaced by snapshot atoms
 
   if (trimflag) {
     delete_atoms();
     bigint nblocal = atom->nlocal;
     MPI_Allreduce(&nblocal,&atom->natoms,1,MPI_LMP_BIGINT,MPI_SUM,world);
   }
 
   // can now delete uflag arrays
 
   memory->destroy(uflag);
   memory->destroy(ucflag);
   memory->destroy(ucflag_all);
 
   // delete atom map if created it above
   // else reinitialize map for current atoms
   // do this before migrating atoms to new procs via Irregular
 
   if (mapflag) {
     atom->map_delete();
     atom->map_style = 0;
   } else {
     atom->nghost = 0;
     atom->map_init();
     atom->map_set();
   }
 
   // overwrite simulation box with dump snapshot box if requested
   // reallocate processors to box
 
   if (boxflag) {
     domain->boxlo[0] = xlo;
     domain->boxhi[0] = xhi;
     domain->boxlo[1] = ylo;
     domain->boxhi[1] = yhi;
     if (dimension == 3) {
       domain->boxlo[2] = zlo;
       domain->boxhi[2] = zhi;
     }
     if (triclinic) {
       domain->xy = xy;
       if (dimension == 3) {
         domain->xz = xz;
         domain->yz = yz;
       }
     }
 
     domain->set_initial_box();
     domain->set_global_box();
     comm->set_proc_grid(0);
     domain->set_local_box();
   }
 
   // move atoms back inside simulation box and to new processors
   // use remap() instead of pbc() in case atoms moved a long distance
   // adjust image flags of all atoms (old and new) based on current box
   // use irregular() in case atoms moved a long distance
 
   double **x = atom->x;
   imageint *image = atom->image;
   nlocal = atom->nlocal;
   for (int i = 0; i < nlocal; i++) domain->remap(x[i],image[i]);
 
   if (triclinic) domain->x2lamda(atom->nlocal);
   domain->reset_box();
   Irregular *irregular = new Irregular(lmp);
   irregular->migrate_atoms(1);
   delete irregular;
   if (triclinic) domain->lamda2x(atom->nlocal);
 
   // check that atom IDs are valid
 
   atom->tag_check();
 }
 
 /* ----------------------------------------------------------------------
    process arg list for dump file fields and optional keywords
 ------------------------------------------------------------------------- */
 
 int ReadDump::fields_and_keywords(int narg, char **arg)
 {
   // per-field vectors, leave space for ID and TYPE
 
   fieldtype = new int[narg+2];
   fieldlabel = new char*[narg+2];
 
   // add id and type fields as needed
   // scan ahead to see if "add yes" keyword/value is used
   // requires extra "type" field from from dump file
 
   int iarg;
   for (iarg = 0; iarg < narg; iarg++)
     if (strcmp(arg[iarg],"add") == 0)
       if (iarg < narg-1 && strcmp(arg[iarg+1],"yes") == 0) break;
 
   nfield = 0;
   fieldtype[nfield++] = ID;
   if (iarg < narg) fieldtype[nfield++] = TYPE;
 
   // parse fields
 
   iarg = 0;
   while (iarg < narg) {
     int type = whichtype(arg[iarg]);
     if (type < 0) break;
     if (type == Q && !atom->q_flag)
       error->all(FLERR,"Read dump of atom property that isn't allocated");
     fieldtype[nfield++] = type;
     iarg++;
   }
 
   // check for no fields
 
   if (fieldtype[nfield-1] == ID || fieldtype[nfield-1] == TYPE)
     error->all(FLERR,"Illegal read_dump command");
 
   if (dimension == 2) {
     for (int i = 0; i < nfield; i++)
       if (fieldtype[i] == Z || fieldtype[i] == VZ || fieldtype[i] == IZ)
         error->all(FLERR,"Illegal read_dump command");
   }
 
   for (int i = 0; i < nfield; i++)
     for (int j = i+1; j < nfield; j++)
       if (fieldtype[i] == fieldtype[j])
         error->all(FLERR,"Duplicate fields in read_dump command");
 
   // parse optional args
 
   boxflag = 1;
   replaceflag = 1;
   purgeflag = 0;
   trimflag = 0;
   addflag = 0;
   for (int i = 0; i < nfield; i++) fieldlabel[i] = NULL;
   scaleflag = 0;
   wrapflag = 1;
 
   while (iarg < narg) {
     if (strcmp(arg[iarg],"box") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal read_dump command");
       if (strcmp(arg[iarg+1],"yes") == 0) boxflag = 1;
       else if (strcmp(arg[iarg+1],"no") == 0) boxflag = 0;
       else error->all(FLERR,"Illegal read_dump command");
       iarg += 2;
     } else if (strcmp(arg[iarg],"replace") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal read_dump command");
       if (strcmp(arg[iarg+1],"yes") == 0) replaceflag = 1;
       else if (strcmp(arg[iarg+1],"no") == 0) replaceflag = 0;
       else error->all(FLERR,"Illegal read_dump command");
       iarg += 2;
     } else if (strcmp(arg[iarg],"purge") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal read_dump command");
       if (strcmp(arg[iarg+1],"yes") == 0) purgeflag = 1;
       else if (strcmp(arg[iarg+1],"no") == 0) purgeflag = 0;
       else error->all(FLERR,"Illegal read_dump command");
       iarg += 2;
     } else if (strcmp(arg[iarg],"trim") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal read_dump command");
       if (strcmp(arg[iarg+1],"yes") == 0) trimflag = 1;
       else if (strcmp(arg[iarg+1],"no") == 0) trimflag = 0;
       else error->all(FLERR,"Illegal read_dump command");
       iarg += 2;
     } else if (strcmp(arg[iarg],"add") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal read_dump command");
       if (strcmp(arg[iarg+1],"yes") == 0) addflag = 1;
       else if (strcmp(arg[iarg+1],"no") == 0) addflag = 0;
       else error->all(FLERR,"Illegal read_dump command");
       iarg += 2;
     } else if (strcmp(arg[iarg],"label") == 0) {
       if (iarg+3 > narg) error->all(FLERR,"Illegal read_dump command");
       int type = whichtype(arg[iarg+1]);
       int i;
       for (i = 0; i < nfield; i++)
         if (type == fieldtype[i]) break;
       if (i == nfield) error->all(FLERR,"Illegal read_dump command");
       int n = strlen(arg[iarg+2]) + 1;
       fieldlabel[i] = new char[n];
       strcpy(fieldlabel[i],arg[iarg+2]);
       iarg += 3;
     } else if (strcmp(arg[iarg],"scaled") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal read_dump command");
       if (strcmp(arg[iarg+1],"yes") == 0) scaleflag = 1;
       else if (strcmp(arg[iarg+1],"no") == 0) scaleflag = 0;
       else error->all(FLERR,"Illegal read_dump command");
       iarg += 2;
     } else if (strcmp(arg[iarg],"wrapped") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal read_dump command");
       if (strcmp(arg[iarg+1],"yes") == 0) wrapflag = 1;
       else if (strcmp(arg[iarg+1],"no") == 0) wrapflag = 0;
       else error->all(FLERR,"Illegal read_dump command");
       iarg += 2;
     } else if (strcmp(arg[iarg],"format") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal read_dump command");
       delete [] readerstyle;
       int n = strlen(arg[iarg+1]) + 1;
       readerstyle = new char[n];
       strcpy(readerstyle,arg[iarg+1]);
       iarg += 2;
       break;
     } else error->all(FLERR,"Illegal read_dump command");
   }
 
   if (purgeflag && (replaceflag || trimflag))
     error->all(FLERR,"If read_dump purges it cannot replace or trim");
 
   return narg-iarg;
 }
 
 /* ----------------------------------------------------------------------
    check if str is a field argument
    if yes, return index of which
    if not, return -1
 ------------------------------------------------------------------------- */
 
 int ReadDump::whichtype(char *str)
 {
   int type = -1;
   if (strcmp(str,"x") == 0) type = X;
   else if (strcmp(str,"y") == 0) type = Y;
   else if (strcmp(str,"z") == 0) type = Z;
   else if (strcmp(str,"vx") == 0) type = VX;
   else if (strcmp(str,"vy") == 0) type = VY;
   else if (strcmp(str,"vz") == 0) type = VZ;
   else if (strcmp(str,"q") == 0) type = Q;
   else if (strcmp(str,"ix") == 0) type = IX;
   else if (strcmp(str,"iy") == 0) type = IY;
   else if (strcmp(str,"iz") == 0) type = IZ;
   return type;
 }
 
 /* ----------------------------------------------------------------------
    process each of N atoms in chunk read from dump file
    if in replace mode and atom ID matches current atom,
      overwrite atom info with fields from dump file
    if in add mode and atom ID does not match any current atom,
      create new atom with dump file field values,
      and assign to a proc in round-robin manner
    use round-robin method, b/c atom coords may not be inside simulation box
 ------------------------------------------------------------------------- */
 
 void ReadDump::process_atoms(int n)
 {
   int i,m,ifield,itype;
   int xbox,ybox,zbox;
   tagint tag;
 
   double **x = atom->x;
   double **v = atom->v;
   double *q = atom->q;
   imageint *image = atom->image;
   int nlocal = atom->nlocal;
   tagint map_tag_max = atom->map_tag_max;
 
   for (i = 0; i < n; i++) {
     ucflag[i] = 0;
 
     // check if new atom matches one I own
     // setting m = -1 forces new atom not to match
     // NOTE: atom ID in fields is stored as double, not as ubuf
     //       so can only cast it to tagint, thus cannot be full 64-bit ID
 
     tag = static_cast<tagint> (fields[i][0]);
     if (tag <= map_tag_max) m = atom->map(tag);
     else m = -1;
     if (m < 0 || m >= nlocal) continue;
 
     ucflag[i] = 1;
     uflag[m] = 1;
 
     if (replaceflag) {
       nreplace++;
 
       // current image flags
 
       xbox = (image[m] & IMGMASK) - IMGMAX;
       ybox = (image[m] >> IMGBITS & IMGMASK) - IMGMAX;
       zbox = (image[m] >> IMG2BITS) - IMGMAX;
 
       // overwrite atom attributes with field info
       // start from field 1 since 0 = id, 1 will be skipped if type
 
       for (ifield = 1; ifield < nfield; ifield++) {
         switch (fieldtype[ifield]) {
         case X:
           x[m][0] = xfield(i,ifield);
           break;
         case Y:
           x[m][1] = yfield(i,ifield);
           break;
         case Z:
           x[m][2] = zfield(i,ifield);
           break;
         case VX:
           v[m][0] = fields[i][ifield];
           break;
         case Q:
           q[m] = fields[i][ifield];
           break;
         case VY:
           v[m][1] = fields[i][ifield];
           break;
         case VZ:
           v[m][2] = fields[i][ifield];
           break;
         case IX:
           xbox = static_cast<int> (fields[i][ifield]);
           break;
         case IY:
           ybox = static_cast<int> (fields[i][ifield]);
           break;
         case IZ:
           zbox = static_cast<int> (fields[i][ifield]);
           break;
         }
       }
 
       // replace image flag in case changed by ix,iy,iz fields or unwrapping
 
       if (!wrapped) xbox = ybox = zbox = 0;
 
       image[m] = ((imageint) (xbox + IMGMAX) & IMGMASK) | 
         (((imageint) (ybox + IMGMAX) & IMGMASK) << IMGBITS) | 
         (((imageint) (zbox + IMGMAX) & IMGMASK) << IMG2BITS);
     }
   }
 
   // create any atoms in chunk that no processor owned
   // add atoms in round-robin sequence on processors
   // cannot do it geometrically b/c dump coords may not be in simulation box
 
   if (!addflag) return;
 
   MPI_Allreduce(ucflag,ucflag_all,n,MPI_INT,MPI_SUM,world);
 
   int nlocal_previous = atom->nlocal;
   double one[3];
 
   for (i = 0; i < n; i++) {
     if (ucflag_all[i]) continue;
 
     // each processor adds every Pth atom
 
     addproc++;
     if (addproc == nprocs) addproc = 0;
     if (addproc != me) continue;
 
     // create type and coord fields from dump file
     // coord = 0.0 unless corresponding dump file field was specified
 
     one[0] = one[1] = one[2] = 0.0;
     for (ifield = 1; ifield < nfield; ifield++) {
       switch (fieldtype[ifield]) {
       case TYPE:
         itype = static_cast<int> (fields[i][ifield]);
         break;
       case X:
         one[0] = xfield(i,ifield);
         break;
       case Y:
         one[1] = yfield(i,ifield);
         break;
       case Z:
         one[2] = zfield(i,ifield);
         break;
       }
     }
 
     // create the atom on proc that owns it
     // reset v,image ptrs in case they are reallocated
 
     m = atom->nlocal;
     atom->avec->create_atom(itype,one);
     nadd++;
 
     v = atom->v;
     q = atom->q;
     image = atom->image;
 
     // set atom attributes from other dump file fields
 
     xbox = ybox = zbox = 0;
 
     for (ifield = 1; ifield < nfield; ifield++) {
       switch (fieldtype[ifield]) {
       case VX:
         v[m][0] = fields[i][ifield];
         break;
       case VY:
         v[m][1] = fields[i][ifield];
         break;
       case VZ:
         v[m][2] = fields[i][ifield];
         break;
       case Q:
         q[m] = fields[i][ifield];
         break;
       case IX:
         xbox = static_cast<int> (fields[i][ifield]);
         break;
       case IY:
         ybox = static_cast<int> (fields[i][ifield]);
         break;
       case IZ:
         zbox = static_cast<int> (fields[i][ifield]);
         break;
       }
 
       // replace image flag in case changed by ix,iy,iz fields
 
       image[m] = ((imageint) (xbox + IMGMAX) & IMGMASK) | 
         (((imageint) (ybox + IMGMAX) & IMGMASK) << IMGBITS) | 
         (((imageint) (zbox + IMGMAX) & IMGMASK) << IMG2BITS);
     }
   }
 
   // invoke set_arrays() for fixes that need initialization of new atoms
   // same as in CreateAtoms
 
   nlocal = atom->nlocal;
   for (m = 0; m < modify->nfix; m++) {
     Fix *fix = modify->fix[m];
     if (fix->create_attribute)
       for (i = nlocal_previous; i < nlocal; i++)
         fix->set_arrays(i);
   }
 }
 
 /* ----------------------------------------------------------------------
    delete atoms not flagged as replaced by dump atoms
 ------------------------------------------------------------------------- */
 
 void ReadDump::delete_atoms()
 {
   AtomVec *avec = atom->avec;
   int nlocal = atom->nlocal;
 
   int i = 0;
   while (i < nlocal) {
     if (uflag[i] == 0) {
       avec->copy(nlocal-1,i,1);
       uflag[i] = uflag[nlocal-1];
       nlocal--;
       ntrim++;
     } else i++;
   }
 
   atom->nlocal = nlocal;
 }
 
 /* ----------------------------------------------------------------------
    convert XYZ fields in dump file into absolute, unscaled coordinates
    depends on scaled vs unscaled and triclinic vs orthogonal
    does not depend on wrapped vs unwrapped
 ------------------------------------------------------------------------- */
 
 double ReadDump::xfield(int i, int j)
 {
   if (!scaled) return fields[i][j];
   else if (!triclinic) return fields[i][j]*xprd + xlo;
   else if (dimension == 2)
     return xprd*fields[i][j] + xy*fields[i][yindex] + xlo;
   return xprd*fields[i][j] + xy*fields[i][yindex] + xz*fields[i][zindex] + xlo;
 }
 
 double ReadDump::yfield(int i, int j)
 {
   if (!scaled) return fields[i][j];
   else if (!triclinic) return fields[i][j]*yprd + ylo;
   else if (dimension == 2) return yprd*fields[i][j] + ylo;
   return yprd*fields[i][j] + yz*fields[i][zindex] + ylo;
 }
 
 double ReadDump::zfield(int i, int j)
 {
   if (!scaled) return fields[i][j];
   return fields[i][j]*zprd + zlo;
 }
diff --git a/src/thermo.cpp b/src/thermo.cpp
index 1a31a1847..e2d131f5b 100644
--- a/src/thermo.cpp
+++ b/src/thermo.cpp
@@ -1,2083 +1,2088 @@
 /* ----------------------------------------------------------------------
    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.
 ------------------------------------------------------------------------- */
 
+// lmptype.h must be first b/c this file uses MAXBIGINT and includes mpi.h
+// due to OpenMPI bug which sets INT64_MAX via its mpi.h
+//   before lmptype.h can set flags to insure it is done correctly
+
+#include "lmptype.h" 
 #include "mpi.h"
 #include "math.h"
 #include "stdlib.h"
 #include "string.h"
 #include "thermo.h"
 #include "atom.h"
 #include "update.h"
 #include "comm.h"
 #include "domain.h"
 #include "universe.h"
 #include "lattice.h"
 #include "group.h"
 #include "modify.h"
 #include "fix.h"
 #include "compute.h"
 #include "input.h"
 #include "variable.h"
 #include "neighbor.h"
 #include "force.h"
 #include "pair.h"
 #include "bond.h"
 #include "angle.h"
 #include "dihedral.h"
 #include "improper.h"
 #include "kspace.h"
 #include "output.h"
 #include "timer.h"
 #include "math_const.h"
 #include "memory.h"
 #include "error.h"
 #include "universe.h"
 
 #include "math_const.h"
 
 using namespace LAMMPS_NS;
 using namespace MathConst;
 
 // customize a new keyword by adding to this list:
 
 // step, elapsed, elaplong, dt, time, cpu, tpcpu, spcpu, cpuremain, part
 // atoms, temp, press, pe, ke, etotal, enthalpy
 // evdwl, ecoul, epair, ebond, eangle, edihed, eimp, emol, elong, etail
 // vol, density, lx, ly, lz, xlo, xhi, ylo, yhi, zlo, zhi, xy, xz, yz,
 // xlat, ylat, zlat
 // bonds, angles, dihedrals, impropers,
 // pxx, pyy, pzz, pxy, pxz, pyz
 // fmax, fnorm, nbuild, ndanger,
 // cella, cellb, cellc, cellalpha, cellbeta, cellgamma
 
 // customize a new thermo style by adding a DEFINE to this list
 // also insure allocation of line string is correct in constructor
 
 #define ONE "step temp epair emol etotal press"
 #define MULTI "etotal ke temp pe ebond eangle edihed eimp evdwl ecoul elong press"
 
 enum{IGNORE,WARN,ERROR};           // same as several files
 enum{ONELINE,MULTILINE};
 enum{INT,FLOAT,BIGINT};
 enum{SCALAR,VECTOR,ARRAY};
 
 #define INVOKED_SCALAR 1
 #define INVOKED_VECTOR 2
 #define INVOKED_ARRAY 4
 
 #define DELTA 8
 
 /* ---------------------------------------------------------------------- */
 
 Thermo::Thermo(LAMMPS *lmp, int narg, char **arg) : Pointers(lmp)
 {
   MPI_Comm_rank(world,&me);
 
   int n = strlen(arg[0]) + 1;
   style = new char[n];
   strcpy(style,arg[0]);
 
   // set thermo_modify defaults
 
   modified = 0;
   normuserflag = 0;
   lineflag = ONELINE;
   lostflag = lostbond = ERROR;
   lostbefore = 0;
   flushflag = 0;
 
   // set style and corresponding lineflag
   // custom style builds its own line of keywords
   // customize a new thermo style by adding to if statement
   // allocate line string used for 3 tasks
   //   concat of custom style args
   //   one-time thermo output of header line
   //   each line of numeric thermo output
   //   256 = extra for ONE or MULTI string or multi formatting
   //   64 = max per-arg chars in header or numeric output
 
   if (strcmp(style,"one") == 0) {
     line = new char[256+6*64];
     strcpy(line,ONE);
   } else if (strcmp(style,"multi") == 0) {
     line = new char[256+12*64];
     strcpy(line,MULTI);
     lineflag = MULTILINE;
 
   } else if (strcmp(style,"custom") == 0) {
     if (narg == 1) error->all(FLERR,"Illegal thermo style custom command");
     line = new char[256+narg*64];
     line[0] = '\0';
     for (int iarg = 1; iarg < narg; iarg++) {
       strcat(line,arg[iarg]);
       strcat(line," ");
     }
     line[strlen(line)-1] = '\0';
 
   } else error->all(FLERR,"Illegal thermo style command");
 
   // ptrs, flags, IDs for compute objects thermo may use or create
 
   temperature = NULL;
   pressure = NULL;
   pe = NULL;
 
   index_temp = index_press_scalar = index_press_vector = index_pe = -1;
 
   id_temp = (char *) "thermo_temp";
   id_press = (char *) "thermo_press";
   id_pe = (char *) "thermo_pe";
 
   // count fields in line
   // allocate per-field memory
   // process line of keywords
 
   nfield_initial = atom->count_words(line);
   allocate();
   parse_fields(line);
 
   // format strings
 
   char *bigint_format = (char *) BIGINT_FORMAT;
   char *fformat_multi = (char *) "---------------- Step %%8%s ----- "
     "CPU = %%11.4f (sec) ----------------";
 
   sprintf(format_multi,fformat_multi,&bigint_format[1]);
   format_float_one_def = (char *) "%12.8g";
   format_float_multi_def = (char *) "%14.4f";
   format_int_one_def = (char *) "%8d";
   format_int_multi_def = (char *) "%14d";
   sprintf(format_bigint_one_def,"%%8%s",&bigint_format[1]);
   sprintf(format_bigint_multi_def,"%%14%s",&bigint_format[1]);
 
   format_float_user = NULL;
   format_int_user = NULL;
   format_bigint_user = NULL;
 }
 
 /* ---------------------------------------------------------------------- */
 
 Thermo::~Thermo()
 {
   delete [] style;
   delete [] line;
 
   deallocate();
 
   // format strings
 
   delete [] format_float_user;
   delete [] format_int_user;
   delete [] format_bigint_user;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::init()
 {
   int i,n;
 
   // set normvalue to default setting unless user has specified it
 
   if (normuserflag) normvalue = normuser;
   else if (strcmp(update->unit_style,"lj") == 0) normvalue = 1;
   else normvalue = 0;
 
   // add Volume field if volume changes and not style = custom
   // this check must come after domain init, so box_change is set
 
   nfield = nfield_initial;
   if (domain->box_change && strcmp(style,"custom") != 0)
     addfield("Volume",&Thermo::compute_vol,FLOAT);
 
   // set format string for each field
   // include keyword if lineflag = MULTILINE
   // add '/n' every 3 values if lineflag = MULTILINE
   // add trailing '/n' to last value
 
   char *ptr;
   for (i = 0; i < nfield; i++) {
     format[i][0] = '\0';
     if (lineflag == MULTILINE && i % 3 == 0) strcat(format[i],"\n");
 
     if (format_user[i]) ptr = format_user[i];
     else if (vtype[i] == FLOAT) {
       if (format_float_user) ptr = format_float_user;
       else if (lineflag == ONELINE) ptr = format_float_one_def;
       else if (lineflag == MULTILINE) ptr = format_float_multi_def;
     } else if (vtype[i] == INT) {
       if (format_int_user) ptr = format_int_user;
       else if (lineflag == ONELINE) ptr = format_int_one_def;
       else if (lineflag == MULTILINE) ptr = format_int_multi_def;
     } else if (vtype[i] == BIGINT) {
       if (format_bigint_user) ptr = format_bigint_user;
       else if (lineflag == ONELINE) ptr = format_bigint_one_def;
       else if (lineflag == MULTILINE) ptr = format_bigint_multi_def;
     }
 
     n = strlen(format[i]);
     if (lineflag == ONELINE) sprintf(&format[i][n],"%s ",ptr);
     else sprintf(&format[i][n],"%-8s = %s ",keyword[i],ptr);
 
     if (i == nfield-1) strcat(format[i],"\n");
   }
 
   // find current ptr for each Compute ID
   // cudable = 0 if any compute used by Thermo is non-CUDA
 
   cudable = 1;
 
   int icompute;
   for (i = 0; i < ncompute; i++) {
     icompute = modify->find_compute(id_compute[i]);
     if (icompute < 0) error->all(FLERR,"Could not find thermo compute ID");
     computes[i] = modify->compute[icompute];
     cudable = cudable && computes[i]->cudable;
   }
 
   // find current ptr for each Fix ID
   // check that fix frequency is acceptable with thermo output frequency
 
   int ifix;
   for (i = 0; i < nfix; i++) {
     ifix = modify->find_fix(id_fix[i]);
     if (ifix < 0) error->all(FLERR,"Could not find thermo fix ID");
     fixes[i] = modify->fix[ifix];
     if (output->thermo_every % fixes[i]->global_freq)
       error->all(FLERR,"Thermo and fix not computed at compatible times");
   }
 
   // find current ptr for each Variable ID
 
   int ivariable;
   for (i = 0; i < nvariable; i++) {
     ivariable = input->variable->find(id_variable[i]);
     if (ivariable < 0)
       error->all(FLERR,"Could not find thermo variable name");
     variables[i] = ivariable;
   }
 
   // set ptrs to keyword-specific Compute objects
 
   if (index_temp >= 0) temperature = computes[index_temp];
   if (index_press_scalar >= 0) pressure = computes[index_press_scalar];
   if (index_press_vector >= 0) pressure = computes[index_press_vector];
   if (index_pe >= 0) pe = computes[index_pe];
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::header()
 {
   if (lineflag == MULTILINE) return;
 
   int loc = 0;
   for (int i = 0; i < nfield; i++)
     loc += sprintf(&line[loc],"%s ",keyword[i]);
   sprintf(&line[loc],"\n");
 
   if (me == 0) {
     if (screen) fprintf(screen,"%s",line);
     if (logfile) fprintf(logfile,"%s",line);
   }
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute(int flag)
 {
   int i;
 
   firststep = flag;
   bigint ntimestep = update->ntimestep;
 
   // check for lost atoms
   // turn off normflag if natoms = 0 to avoid divide by 0
 
   natoms = lost_check();
   if (natoms == 0) normflag = 0;
   else normflag = normvalue;
 
   // invoke Compute methods needed for thermo keywords
 
   for (i = 0; i < ncompute; i++)
     if (compute_which[i] == SCALAR) {
       if (!(computes[i]->invoked_flag & INVOKED_SCALAR)) {
         computes[i]->compute_scalar();
         computes[i]->invoked_flag |= INVOKED_SCALAR;
       }
     } else if (compute_which[i] == VECTOR) {
       if (!(computes[i]->invoked_flag & INVOKED_VECTOR)) {
         computes[i]->compute_vector();
         computes[i]->invoked_flag |= INVOKED_VECTOR;
       }
     } else if (compute_which[i] == ARRAY) {
       if (!(computes[i]->invoked_flag & INVOKED_ARRAY)) {
         computes[i]->compute_array();
         computes[i]->invoked_flag |= INVOKED_ARRAY;
       }
     }
 
   // if lineflag = MULTILINE, prepend step/cpu header line
 
   int loc = 0;
   if (lineflag == MULTILINE) {
     double cpu;
     if (flag) cpu = timer->elapsed(Timer::TOTAL);
     else cpu = 0.0;
     loc = sprintf(&line[loc],format_multi,ntimestep,cpu);
   }
 
   // add each thermo value to line with its specific format
 
   for (ifield = 0; ifield < nfield; ifield++) {
     (this->*vfunc[ifield])();
     if (vtype[ifield] == FLOAT)
       loc += sprintf(&line[loc],format[ifield],dvalue);
     else if (vtype[ifield] == INT)
       loc += sprintf(&line[loc],format[ifield],ivalue);
     else if (vtype[ifield] == BIGINT) {
       loc += sprintf(&line[loc],format[ifield],bivalue);
     }
   }
 
   // print line to screen and logfile
 
   if (me == 0) {
     if (screen) fprintf(screen,"%s",line);
     if (logfile) {
       fprintf(logfile,"%s",line);
       if (flushflag) fflush(logfile);
     }
   }
 }
 
 /* ----------------------------------------------------------------------
    check for lost atoms, return current number of atoms
 ------------------------------------------------------------------------- */
 
 bigint Thermo::lost_check()
 {
   // ntotal = current # of atoms
 
   bigint ntotal;
   bigint nblocal = atom->nlocal;
   MPI_Allreduce(&nblocal,&ntotal,1,MPI_LMP_BIGINT,MPI_SUM,world);
   if (ntotal < 0 || ntotal > MAXBIGINT)
     error->all(FLERR,"Too many total atoms");
   if (ntotal == atom->natoms) return ntotal;
 
   // if not checking or already warned, just return
   // reset total atom count
 
   if (lostflag == IGNORE) return ntotal;
   if (lostflag == WARN && lostbefore == 1) {
     atom->natoms = ntotal;
     return ntotal;
   }
 
   // error message
 
   if (lostflag == ERROR) {
     char str[64];
     sprintf(str,
             "Lost atoms: original " BIGINT_FORMAT " current " BIGINT_FORMAT,
             atom->natoms,ntotal);
     error->all(FLERR,str);
   }
 
   // warning message
 
   char str[64];
   sprintf(str,
           "Lost atoms: original " BIGINT_FORMAT " current " BIGINT_FORMAT,
           atom->natoms,ntotal);
   if (me == 0) error->warning(FLERR,str,0);
 
   // reset total atom count
 
   atom->natoms = ntotal;
   lostbefore = 1;
   return ntotal;
 }
 
 /* ----------------------------------------------------------------------
    modify thermo parameters
 ------------------------------------------------------------------------- */
 
 void Thermo::modify_params(int narg, char **arg)
 {
   if (narg == 0) error->all(FLERR,"Illegal thermo_modify command");
 
   modified = 1;
 
   int iarg = 0;
   while (iarg < narg) {
     if (strcmp(arg[iarg],"temp") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal thermo_modify command");
       if (index_temp < 0) error->all(FLERR,"Thermo style does not use temp");
       delete [] id_compute[index_temp];
       int n = strlen(arg[iarg+1]) + 1;
       id_compute[index_temp] = new char[n];
       strcpy(id_compute[index_temp],arg[iarg+1]);
 
       int icompute = modify->find_compute(arg[iarg+1]);
       if (icompute < 0)
         error->all(FLERR,"Could not find thermo_modify temperature ID");
       temperature = modify->compute[icompute];
 
       if (temperature->tempflag == 0)
         error->all(FLERR,"Thermo_modify temperature ID does not "
                    "compute temperature");
       if (temperature->igroup != 0 && comm->me == 0)
         error->warning(FLERR,
                        "Temperature for thermo pressure is not for group all");
 
       // reset id_temp of pressure to new temperature ID
       // either pressure currently being used by thermo or "thermo_press"
 
       if (index_press_scalar >= 0) {
         icompute = modify->find_compute(id_compute[index_press_scalar]);
         if (icompute < 0) error->all(FLERR,
                                      "Pressure ID for thermo does not exist");
       } else if (index_press_vector >= 0) {
         icompute = modify->find_compute(id_compute[index_press_vector]);
         if (icompute < 0) error->all(FLERR,
                                      "Pressure ID for thermo does not exist");
       } else icompute = modify->find_compute((char *) "thermo_press");
 
       modify->compute[icompute]->reset_extra_compute_fix(arg[iarg+1]);
 
       iarg += 2;
 
     } else if (strcmp(arg[iarg],"press") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal thermo_modify command");
       if (index_press_scalar < 0 && index_press_vector < 0)
         error->all(FLERR,"Thermo style does not use press");
 
       if (index_press_scalar >= 0) {
         delete [] id_compute[index_press_scalar];
         int n = strlen(arg[iarg+1]) + 1;
         id_compute[index_press_scalar] = new char[n];
         strcpy(id_compute[index_press_scalar],arg[iarg+1]);
       }
       if (index_press_vector >= 0) {
         delete [] id_compute[index_press_vector];
         int n = strlen(arg[iarg+1]) + 1;
         id_compute[index_press_vector] = new char[n];
         strcpy(id_compute[index_press_vector],arg[iarg+1]);
       }
 
       int icompute = modify->find_compute(arg[iarg+1]);
       if (icompute < 0) error->all(FLERR,
                                    "Could not find thermo_modify pressure ID");
       pressure = modify->compute[icompute];
 
       if (pressure->pressflag == 0)
         error->all(FLERR,"Thermo_modify pressure ID does not compute pressure");
 
       iarg += 2;
 
     } else if (strcmp(arg[iarg],"lost") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal thermo_modify command");
       if (strcmp(arg[iarg+1],"ignore") == 0) lostflag = IGNORE;
       else if (strcmp(arg[iarg+1],"warn") == 0) lostflag = WARN;
       else if (strcmp(arg[iarg+1],"error") == 0) lostflag = ERROR;
       else error->all(FLERR,"Illegal thermo_modify command");
       iarg += 2;
 
     } else if (strcmp(arg[iarg],"lost/bond") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal thermo_modify command");
       if (strcmp(arg[iarg+1],"ignore") == 0) lostbond = IGNORE;
       else if (strcmp(arg[iarg+1],"warn") == 0) lostbond = WARN;
       else if (strcmp(arg[iarg+1],"error") == 0) lostbond = ERROR;
       else error->all(FLERR,"Illegal thermo_modify command");
       iarg += 2;
 
     } else if (strcmp(arg[iarg],"norm") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal thermo_modify command");
       normuserflag = 1;
       if (strcmp(arg[iarg+1],"no") == 0) normuser = 0;
       else if (strcmp(arg[iarg+1],"yes") == 0) normuser = 1;
       else error->all(FLERR,"Illegal thermo_modify command");
       iarg += 2;
 
     } else if (strcmp(arg[iarg],"flush") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal thermo_modify command");
       if (strcmp(arg[iarg+1],"no") == 0) flushflag = 0;
       else if (strcmp(arg[iarg+1],"yes") == 0) flushflag = 1;
       else error->all(FLERR,"Illegal thermo_modify command");
       iarg += 2;
 
     } else if (strcmp(arg[iarg],"line") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal thermo_modify command");
       if (strcmp(arg[iarg+1],"one") == 0) lineflag = ONELINE;
       else if (strcmp(arg[iarg+1],"multi") == 0) lineflag = MULTILINE;
       else error->all(FLERR,"Illegal thermo_modify command");
       iarg += 2;
 
     } else if (strcmp(arg[iarg],"format") == 0) {
       if (iarg+3 > narg) error->all(FLERR,"Illegal thermo_modify command");
       if (strcmp(arg[iarg+1],"int") == 0) {
         if (format_int_user) delete [] format_int_user;
         int n = strlen(arg[iarg+2]) + 1;
         format_int_user = new char[n];
         strcpy(format_int_user,arg[iarg+2]);
         if (format_bigint_user) delete [] format_bigint_user;
         n = strlen(format_int_user) + 3;
         format_bigint_user = new char[n];
         char *ptr = strchr(format_int_user,'d');
         if (ptr == NULL)
           error->all(FLERR,
                      "Thermo_modify int format does not contain d character");
         *ptr = '\0';
         sprintf(format_bigint_user,"%s%s%s",format_int_user,
                 BIGINT_FORMAT,ptr+1);
         *ptr = 'd';
       } else if (strcmp(arg[iarg+1],"float") == 0) {
         if (format_float_user) delete [] format_float_user;
         int n = strlen(arg[iarg+2]) + 1;
         format_float_user = new char[n];
         strcpy(format_float_user,arg[iarg+2]);
       } else {
         int i = force->inumeric(FLERR,arg[iarg+1]) - 1;
         if (i < 0 || i >= nfield_initial)
           error->all(FLERR,"Illegal thermo_modify command");
         if (format_user[i]) delete [] format_user[i];
         int n = strlen(arg[iarg+2]) + 1;
         format_user[i] = new char[n];
         strcpy(format_user[i],arg[iarg+2]);
       }
       iarg += 3;
 
     } else error->all(FLERR,"Illegal thermo_modify command");
   }
 }
 
 /* ----------------------------------------------------------------------
    allocate all per-field memory
 ------------------------------------------------------------------------- */
 
 void Thermo::allocate()
 {
   // n = specified fields + Volume field (added at run time)
 
   int n = nfield_initial + 1;
 
   keyword = new char*[n];
   for (int i = 0; i < n; i++) keyword[i] = new char[32];
   vfunc = new FnPtr[n];
   vtype = new int[n];
 
   format = new char*[n];
   for (int i = 0; i < n; i++) format[i] = new char[32];
   format_user = new char*[n];
   for (int i = 0; i < n; i++) format_user[i] = NULL;
 
   field2index = new int[n];
   argindex1 = new int[n];
   argindex2 = new int[n];
 
   // factor of 3 is max number of computes a single field can add
 
   ncompute = 0;
   id_compute = new char*[3*n];
   compute_which = new int[3*n];
   computes = new Compute*[3*n];
 
   nfix = 0;
   id_fix = new char*[n];
   fixes = new Fix*[n];
 
   nvariable = 0;
   id_variable = new char*[n];
   variables = new int[n];
 }
 
 /* ----------------------------------------------------------------------
    deallocate all per-field memory
 ------------------------------------------------------------------------- */
 
 void Thermo::deallocate()
 {
   int n = nfield_initial + 1;
 
   for (int i = 0; i < n; i++) delete [] keyword[i];
   delete [] keyword;
   delete [] vfunc;
   delete [] vtype;
 
   for (int i = 0; i < n; i++) delete [] format[i];
   delete [] format;
   for (int i = 0; i < n; i++) delete [] format_user[i];
   delete [] format_user;
 
   delete [] field2index;
   delete [] argindex1;
   delete [] argindex2;
 
   for (int i = 0; i < ncompute; i++) delete [] id_compute[i];
   delete [] id_compute;
   delete [] compute_which;
   delete [] computes;
 
   for (int i = 0; i < nfix; i++) delete [] id_fix[i];
   delete [] id_fix;
   delete [] fixes;
 
   for (int i = 0; i < nvariable; i++) delete [] id_variable[i];
   delete [] id_variable;
   delete [] variables;
 }
 
 /* ----------------------------------------------------------------------
    parse list of thermo keywords from str
    set compute flags (temp, press, pe, etc)
 ------------------------------------------------------------------------- */
 
 void Thermo::parse_fields(char *str)
 {
   nfield = 0;
 
   // customize a new keyword by adding to if statement
 
   char *word = strtok(str," \0");
   while (word) {
 
     if (strcmp(word,"step") == 0) {
       addfield("Step",&Thermo::compute_step,BIGINT);
     } else if (strcmp(word,"elapsed") == 0) {
       addfield("Elapsed",&Thermo::compute_elapsed,BIGINT);
     } else if (strcmp(word,"elaplong") == 0) {
       addfield("Elaplong",&Thermo::compute_elapsed_long,BIGINT);
     } else if (strcmp(word,"dt") == 0) {
       addfield("Dt",&Thermo::compute_dt,FLOAT);
     } else if (strcmp(word,"time") == 0) {
       addfield("Time",&Thermo::compute_time,FLOAT);
     } else if (strcmp(word,"cpu") == 0) {
       addfield("CPU",&Thermo::compute_cpu,FLOAT);
     } else if (strcmp(word,"tpcpu") == 0) {
       addfield("T/CPU",&Thermo::compute_tpcpu,FLOAT);
     } else if (strcmp(word,"spcpu") == 0) {
       addfield("S/CPU",&Thermo::compute_spcpu,FLOAT);
     } else if (strcmp(word,"cpuremain") == 0) {
       addfield("CPULeft",&Thermo::compute_cpuremain,FLOAT);
     } else if (strcmp(word,"part") == 0) {
       addfield("Part",&Thermo::compute_part,INT);
 
     } else if (strcmp(word,"atoms") == 0) {
       addfield("Atoms",&Thermo::compute_atoms,BIGINT);
     } else if (strcmp(word,"temp") == 0) {
       addfield("Temp",&Thermo::compute_temp,FLOAT);
       index_temp = add_compute(id_temp,SCALAR);
     } else if (strcmp(word,"press") == 0) {
       addfield("Press",&Thermo::compute_press,FLOAT);
       index_press_scalar = add_compute(id_press,SCALAR);
     } else if (strcmp(word,"pe") == 0) {
       addfield("PotEng",&Thermo::compute_pe,FLOAT);
       index_pe = add_compute(id_pe,SCALAR);
     } else if (strcmp(word,"ke") == 0) {
       addfield("KinEng",&Thermo::compute_ke,FLOAT);
       index_temp = add_compute(id_temp,SCALAR);
     } else if (strcmp(word,"etotal") == 0) {
       addfield("TotEng",&Thermo::compute_etotal,FLOAT);
       index_temp = add_compute(id_temp,SCALAR);
       index_pe = add_compute(id_pe,SCALAR);
     } else if (strcmp(word,"enthalpy") == 0) {
       addfield("Enthalpy",&Thermo::compute_enthalpy,FLOAT);
       index_temp = add_compute(id_temp,SCALAR);
       index_press_scalar = add_compute(id_press,SCALAR);
       index_pe = add_compute(id_pe,SCALAR);
 
     } else if (strcmp(word,"evdwl") == 0) {
       addfield("E_vdwl",&Thermo::compute_evdwl,FLOAT);
       index_pe = add_compute(id_pe,SCALAR);
     } else if (strcmp(word,"ecoul") == 0) {
       addfield("E_coul",&Thermo::compute_ecoul,FLOAT);
       index_pe = add_compute(id_pe,SCALAR);
     } else if (strcmp(word,"epair") == 0) {
       addfield("E_pair",&Thermo::compute_epair,FLOAT);
       index_pe = add_compute(id_pe,SCALAR);
     } else if (strcmp(word,"ebond") == 0) {
       addfield("E_bond",&Thermo::compute_ebond,FLOAT);
       index_pe = add_compute(id_pe,SCALAR);
     } else if (strcmp(word,"eangle") == 0) {
       addfield("E_angle",&Thermo::compute_eangle,FLOAT);
       index_pe = add_compute(id_pe,SCALAR);
     } else if (strcmp(word,"edihed") == 0) {
       addfield("E_dihed",&Thermo::compute_edihed,FLOAT);
       index_pe = add_compute(id_pe,SCALAR);
     } else if (strcmp(word,"eimp") == 0) {
       addfield("E_impro",&Thermo::compute_eimp,FLOAT);
       index_pe = add_compute(id_pe,SCALAR);
     } else if (strcmp(word,"emol") == 0) {
       addfield("E_mol",&Thermo::compute_emol,FLOAT);
       index_pe = add_compute(id_pe,SCALAR);
     } else if (strcmp(word,"elong") == 0) {
       addfield("E_long",&Thermo::compute_elong,FLOAT);
       index_pe = add_compute(id_pe,SCALAR);
     } else if (strcmp(word,"etail") == 0) {
       addfield("E_tail",&Thermo::compute_etail,FLOAT);
       index_pe = add_compute(id_pe,SCALAR);
 
     } else if (strcmp(word,"vol") == 0) {
       addfield("Volume",&Thermo::compute_vol,FLOAT);
     } else if (strcmp(word,"density") == 0) {
       addfield("Density",&Thermo::compute_density,FLOAT);
     } else if (strcmp(word,"lx") == 0) {
       addfield("Lx",&Thermo::compute_lx,FLOAT);
     } else if (strcmp(word,"ly") == 0) {
       addfield("Ly",&Thermo::compute_ly,FLOAT);
     } else if (strcmp(word,"lz") == 0) {
       addfield("Lz",&Thermo::compute_lz,FLOAT);
 
     } else if (strcmp(word,"xlo") == 0) {
       addfield("Xlo",&Thermo::compute_xlo,FLOAT);
     } else if (strcmp(word,"xhi") == 0) {
       addfield("Xhi",&Thermo::compute_xhi,FLOAT);
     } else if (strcmp(word,"ylo") == 0) {
       addfield("Ylo",&Thermo::compute_ylo,FLOAT);
     } else if (strcmp(word,"yhi") == 0) {
       addfield("Yhi",&Thermo::compute_yhi,FLOAT);
     } else if (strcmp(word,"zlo") == 0) {
       addfield("Zlo",&Thermo::compute_zlo,FLOAT);
     } else if (strcmp(word,"zhi") == 0) {
       addfield("Zhi",&Thermo::compute_zhi,FLOAT);
 
     } else if (strcmp(word,"xy") == 0) {
       addfield("Xy",&Thermo::compute_xy,FLOAT);
     } else if (strcmp(word,"xz") == 0) {
       addfield("Xz",&Thermo::compute_xz,FLOAT);
     } else if (strcmp(word,"yz") == 0) {
       addfield("Yz",&Thermo::compute_yz,FLOAT);
 
     } else if (strcmp(word,"xlat") == 0) {
       addfield("Xlat",&Thermo::compute_xlat,FLOAT);
     } else if (strcmp(word,"ylat") == 0) {
       addfield("Ylat",&Thermo::compute_ylat,FLOAT);
     } else if (strcmp(word,"zlat") == 0) {
       addfield("Zlat",&Thermo::compute_zlat,FLOAT);
 
     } else if (strcmp(word,"bonds") == 0) {
       addfield("Bonds",&Thermo::compute_bonds,BIGINT);
     } else if (strcmp(word,"angles") == 0) {
       addfield("Angles",&Thermo::compute_angles,BIGINT);
     } else if (strcmp(word,"dihedrals") == 0) {
       addfield("Diheds",&Thermo::compute_dihedrals,BIGINT);
     } else if (strcmp(word,"impropers") == 0) {
       addfield("Impros",&Thermo::compute_impropers,BIGINT);
 
     } else if (strcmp(word,"pxx") == 0) {
       addfield("Pxx",&Thermo::compute_pxx,FLOAT);
       index_press_vector = add_compute(id_press,VECTOR);
     } else if (strcmp(word,"pyy") == 0) {
       addfield("Pyy",&Thermo::compute_pyy,FLOAT);
       index_press_vector = add_compute(id_press,VECTOR);
     } else if (strcmp(word,"pzz") == 0) {
       addfield("Pzz",&Thermo::compute_pzz,FLOAT);
       index_press_vector = add_compute(id_press,VECTOR);
     } else if (strcmp(word,"pxy") == 0) {
       addfield("Pxy",&Thermo::compute_pxy,FLOAT);
       index_press_vector = add_compute(id_press,VECTOR);
     } else if (strcmp(word,"pxz") == 0) {
       addfield("Pxz",&Thermo::compute_pxz,FLOAT);
       index_press_vector = add_compute(id_press,VECTOR);
     } else if (strcmp(word,"pyz") == 0) {
       addfield("Pyz",&Thermo::compute_pyz,FLOAT);
       index_press_vector = add_compute(id_press,VECTOR);
 
     } else if (strcmp(word,"fmax") == 0) {
       addfield("Fmax",&Thermo::compute_fmax,FLOAT);
     } else if (strcmp(word,"fnorm") == 0) {
       addfield("Fnorm",&Thermo::compute_fnorm,FLOAT);
 
     } else if (strcmp(word,"nbuild") == 0) {
       addfield("Nbuild",&Thermo::compute_nbuild,BIGINT);
     } else if (strcmp(word,"ndanger") == 0) {
       addfield("Ndanger",&Thermo::compute_ndanger,BIGINT);
 
     } else if (strcmp(word,"cella") == 0) {
       addfield("Cella",&Thermo::compute_cella,FLOAT);
     } else if (strcmp(word,"cellb") == 0) {
       addfield("Cellb",&Thermo::compute_cellb,FLOAT);
     } else if (strcmp(word,"cellc") == 0) {
       addfield("Cellc",&Thermo::compute_cellc,FLOAT);
     } else if (strcmp(word,"cellalpha") == 0) {
       addfield("CellAlpha",&Thermo::compute_cellalpha,FLOAT);
     } else if (strcmp(word,"cellbeta") == 0) {
       addfield("CellBeta",&Thermo::compute_cellbeta,FLOAT);
     } else if (strcmp(word,"cellgamma") == 0) {
       addfield("CellGamma",&Thermo::compute_cellgamma,FLOAT);
 
     // compute value = c_ID, fix value = f_ID, variable value = v_ID
     // count trailing [] and store int arguments
     // copy = at most 8 chars of ID to pass to addfield
 
     } else if ((strncmp(word,"c_",2) == 0) || (strncmp(word,"f_",2) == 0) ||
                (strncmp(word,"v_",2) == 0)) {
 
       int n = strlen(word);
       char *id = new char[n];
       strcpy(id,&word[2]);
       char copy[9];
       strncpy(copy,id,8);
       copy[8] = '\0';
 
       // parse zero or one or two trailing brackets from ID
       // argindex1,argindex2 = int inside each bracket pair, 0 if no bracket
 
       char *ptr = strchr(id,'[');
       if (ptr == NULL) argindex1[nfield] = 0;
       else {
         *ptr = '\0';
         argindex1[nfield] = input->variable->int_between_brackets(ptr,0);
         ptr++;
         if (*ptr == '[') {
           argindex2[nfield] = input->variable->int_between_brackets(ptr,0);
           ptr++;
         } else argindex2[nfield] = 0;
       }
 
       if (word[0] == 'c') {
         n = modify->find_compute(id);
         if (n < 0) error->all(FLERR,"Could not find thermo custom compute ID");
         if (argindex1[nfield] == 0 && modify->compute[n]->scalar_flag == 0)
           error->all(FLERR,"Thermo compute does not compute scalar");
         if (argindex1[nfield] > 0 && argindex2[nfield] == 0) {
           if (modify->compute[n]->vector_flag == 0)
             error->all(FLERR,"Thermo compute does not compute vector");
           if (argindex1[nfield] > modify->compute[n]->size_vector)
             error->all(FLERR,"Thermo compute vector is accessed out-of-range");
         }
         if (argindex1[nfield] > 0 && argindex2[nfield] > 0) {
           if (modify->compute[n]->array_flag == 0)
             error->all(FLERR,"Thermo compute does not compute array");
           if (argindex1[nfield] > modify->compute[n]->size_array_rows ||
               argindex2[nfield] > modify->compute[n]->size_array_cols)
             error->all(FLERR,"Thermo compute array is accessed out-of-range");
         }
 
         if (argindex1[nfield] == 0)
           field2index[nfield] = add_compute(id,SCALAR);
         else if (argindex2[nfield] == 0)
           field2index[nfield] = add_compute(id,VECTOR);
         else
           field2index[nfield] = add_compute(id,ARRAY);
         addfield(copy,&Thermo::compute_compute,FLOAT);
 
       } else if (word[0] == 'f') {
         n = modify->find_fix(id);
         if (n < 0) error->all(FLERR,"Could not find thermo custom fix ID");
         if (argindex1[nfield] == 0 && modify->fix[n]->scalar_flag == 0)
           error->all(FLERR,"Thermo fix does not compute scalar");
         if (argindex1[nfield] > 0 && argindex2[nfield] == 0) {
           if (modify->fix[n]->vector_flag == 0)
             error->all(FLERR,"Thermo fix does not compute vector");
           if (argindex1[nfield] > modify->fix[n]->size_vector)
             error->all(FLERR,"Thermo fix vector is accessed out-of-range");
         }
         if (argindex1[nfield] > 0 && argindex2[nfield] > 0) {
           if (modify->fix[n]->array_flag == 0)
             error->all(FLERR,"Thermo fix does not compute array");
           if (argindex1[nfield] > modify->fix[n]->size_array_rows ||
               argindex2[nfield] > modify->fix[n]->size_array_cols)
             error->all(FLERR,"Thermo fix array is accessed out-of-range");
         }
 
         field2index[nfield] = add_fix(id);
         addfield(copy,&Thermo::compute_fix,FLOAT);
 
       } else if (word[0] == 'v') {
         n = input->variable->find(id);
         if (n < 0) 
           error->all(FLERR,"Could not find thermo custom variable name");
         if (input->variable->equalstyle(n) == 0)
           error->all(FLERR,
                      "Thermo custom variable is not equal-style variable");
         if (argindex1[nfield])
           error->all(FLERR,"Thermo custom variable cannot be indexed");
 
         field2index[nfield] = add_variable(id);
         addfield(copy,&Thermo::compute_variable,FLOAT);
       }
 
       delete [] id;
 
     } else error->all(FLERR,"Invalid keyword in thermo_style custom command");
 
     word = strtok(NULL," \0");
   }
 }
 
 /* ----------------------------------------------------------------------
    add field to list of quantities to print
 ------------------------------------------------------------------------- */
 
 void Thermo::addfield(const char *key, FnPtr func, int typeflag)
 {
   strcpy(keyword[nfield],key);
   vfunc[nfield] = func;
   vtype[nfield] = typeflag;
   nfield++;
 }
 
 /* ----------------------------------------------------------------------
    add compute ID to list of Compute objects to call
    return location of where this Compute is in list
    if already in list with same which, do not add, just return index
 ------------------------------------------------------------------------- */
 
 int Thermo::add_compute(const char *id, int which)
 {
   int icompute;
   for (icompute = 0; icompute < ncompute; icompute++)
     if ((strcmp(id,id_compute[icompute]) == 0) &&
         which == compute_which[icompute]) break;
   if (icompute < ncompute) return icompute;
 
   int n = strlen(id) + 1;
   id_compute[ncompute] = new char[n];
   strcpy(id_compute[ncompute],id);
   compute_which[ncompute] = which;
   ncompute++;
   return ncompute-1;
 }
 
 /* ----------------------------------------------------------------------
    add fix ID to list of Fix objects to call
 ------------------------------------------------------------------------- */
 
 int Thermo::add_fix(const char *id)
 {
   int n = strlen(id) + 1;
   id_fix[nfix] = new char[n];
   strcpy(id_fix[nfix],id);
   nfix++;
   return nfix-1;
 }
 
 /* ----------------------------------------------------------------------
    add variable ID to list of Variables to evaluate
 ------------------------------------------------------------------------- */
 
 int Thermo::add_variable(const char *id)
 {
   int n = strlen(id) + 1;
   id_variable[nvariable] = new char[n];
   strcpy(id_variable[nvariable],id);
   nvariable++;
   return nvariable-1;
 }
 
 /* ----------------------------------------------------------------------
    compute a single thermodyanmic value, word is any keyword in custom list
    called when a variable is evaluated by Variable class
    return value as double in answer
    return 0 if str is recoginzed keyword, 1 if unrecognized
    customize a new keyword by adding to if statement
 ------------------------------------------------------------------------- */
 
 int Thermo::evaluate_keyword(char *word, double *answer)
 {
   // turn off normflag if natoms = 0 to avoid divide by 0
   // normflag must be set for lo-level thermo routines that may be invoked
 
   natoms = atom->natoms;
   if (natoms == 0) normflag = 0;
   else normflag = normvalue;
 
   // invoke a lo-level thermo routine to compute the variable value
   // if keyword requires a compute, error if thermo doesn't use the compute
   // if inbetween runs and needed compute is not current, error
   // if in middle of run and needed compute is not current, invoke it
   // for keywords that use pe indirectly (evdwl, ebond, etc):
   //   check if energy was tallied on this timestep and set pe->invoked_flag
   //   this will trigger next timestep for energy tallying via addstep()
 
   if (strcmp(word,"step") == 0) {
     compute_step();
     dvalue = bivalue;
 
   } else if (strcmp(word,"elapsed") == 0) {
     if (update->whichflag == 0)
       error->all(FLERR,
                  "This variable thermo keyword cannot be used between runs");
     compute_elapsed();
     dvalue = bivalue;
 
   } else if (strcmp(word,"elaplong") == 0) {
     if (update->whichflag == 0)
       error->all(FLERR,
                  "This variable thermo keyword cannot be used between runs");
     compute_elapsed_long();
     dvalue = bivalue;
 
   } else if (strcmp(word,"dt") == 0) {
     compute_dt();
 
   } else if (strcmp(word,"time") == 0) {
     compute_time();
 
   } else if (strcmp(word,"cpu") == 0) {
     if (update->whichflag == 0)
       error->all(FLERR,
                  "This variable thermo keyword cannot be used between runs");
     compute_cpu();
 
   } else if (strcmp(word,"tpcpu") == 0) {
     if (update->whichflag == 0)
       error->all(FLERR,
                  "This variable thermo keyword cannot be used between runs");
     compute_tpcpu();
 
   } else if (strcmp(word,"spcpu") == 0) {
     if (update->whichflag == 0)
       error->all(FLERR,
                  "This variable thermo keyword cannot be used between runs");
     compute_spcpu();
 
   } else if (strcmp(word,"cpuremain") == 0) {
     if (update->whichflag == 0)
       error->all(FLERR,
                  "This variable thermo keyword cannot be used between runs");
     compute_cpuremain();
 
   } else if (strcmp(word,"part") == 0) {
     compute_part();
     dvalue = ivalue;
 
   } else if (strcmp(word,"atoms") == 0) {
     compute_atoms();
     dvalue = bivalue;
 
   } else if (strcmp(word,"temp") == 0) {
     if (!temperature)
       error->all(FLERR,"Thermo keyword in variable requires "
                  "thermo to use/init temp");
     if (update->whichflag == 0) {
       if (temperature->invoked_scalar != update->ntimestep)
         error->all(FLERR,"Compute used in variable thermo keyword between runs "
                    "is not current");
     } else if (!(temperature->invoked_flag & INVOKED_SCALAR)) {
       temperature->compute_scalar();
       temperature->invoked_flag |= INVOKED_SCALAR;
     }
     compute_temp();
 
   } else if (strcmp(word,"press") == 0) {
     if (!pressure)
       error->all(FLERR,"Thermo keyword in variable requires "
                  "thermo to use/init press");
     if (update->whichflag == 0) {
       if (pressure->invoked_scalar != update->ntimestep)
         error->all(FLERR,"Compute used in variable thermo keyword between runs "
                    "is not current");
     } else if (!(pressure->invoked_flag & INVOKED_SCALAR)) {
       pressure->compute_scalar();
       pressure->invoked_flag |= INVOKED_SCALAR;
     }
     compute_press();
 
   } else if (strcmp(word,"pe") == 0) {
     if (!pe)
       error->all(FLERR,
                  "Thermo keyword in variable requires thermo to use/init pe");
     if (update->whichflag == 0) {
       if (pe->invoked_scalar != update->ntimestep)
         error->all(FLERR,"Compute used in variable thermo keyword between runs "
                    "is not current");
     } else if (!(pe->invoked_flag & INVOKED_SCALAR)) {
       pe->compute_scalar();
       pe->invoked_flag |= INVOKED_SCALAR;
     }
     compute_pe();
 
   } else if (strcmp(word,"ke") == 0) {
     if (!temperature)
       error->all(FLERR,"Thermo keyword in variable requires "
                  "thermo to use/init temp");
     if (update->whichflag == 0) {
       if (temperature->invoked_scalar != update->ntimestep)
         error->all(FLERR,"Compute used in variable thermo keyword between runs "
                    "is not current");
     } else if (!(temperature->invoked_flag & INVOKED_SCALAR)) {
       temperature->compute_scalar();
       temperature->invoked_flag |= INVOKED_SCALAR;
     }
     compute_ke();
 
   } else if (strcmp(word,"etotal") == 0) {
     if (!pe)
       error->all(FLERR,
                  "Thermo keyword in variable requires thermo to use/init pe");
     if (update->whichflag == 0) {
       if (pe->invoked_scalar != update->ntimestep)
         error->all(FLERR,"Compute used in variable thermo keyword between runs "
                    "is not current");
     } else if (!(pe->invoked_flag & INVOKED_SCALAR)) {
       pe->compute_scalar();
       pe->invoked_flag |= INVOKED_SCALAR;
     }
     if (!temperature)
       error->all(FLERR,"Thermo keyword in variable requires "
                  "thermo to use/init temp");
     if (update->whichflag == 0) {
       if (temperature->invoked_scalar != update->ntimestep)
         error->all(FLERR,"Compute used in variable thermo keyword between runs "
                    "is not current");
     } else if (!(temperature->invoked_flag & INVOKED_SCALAR)) {
       temperature->compute_scalar();
       temperature->invoked_flag |= INVOKED_SCALAR;
     }
     compute_etotal();
 
   } else if (strcmp(word,"enthalpy") == 0) {
     if (!pe)
       error->all(FLERR,
                  "Thermo keyword in variable requires thermo to use/init pe");
     if (update->whichflag == 0) {
       if (pe->invoked_scalar != update->ntimestep)
         error->all(FLERR,"Compute used in variable thermo keyword between runs "
                    "is not current");
     } else if (!(pe->invoked_flag & INVOKED_SCALAR)) {
       pe->compute_scalar();
       pe->invoked_flag |= INVOKED_SCALAR;
     }
     if (!temperature)
       error->all(FLERR,"Thermo keyword in variable requires "
                  "thermo to use/init temp");
     if (update->whichflag == 0) {
       if (temperature->invoked_scalar != update->ntimestep)
         error->all(FLERR,"Compute used in variable thermo keyword between runs "
                    "is not current");
     } else if (!(temperature->invoked_flag & INVOKED_SCALAR)) {
       temperature->compute_scalar();
       temperature->invoked_flag |= INVOKED_SCALAR;
     }
     if (!pressure)
       error->all(FLERR,"Thermo keyword in variable requires "
                  "thermo to use/init press");
     if (update->whichflag == 0) {
       if (pressure->invoked_scalar != update->ntimestep)
         error->all(FLERR,"Compute used in variable thermo keyword between runs "
                    "is not current");
     } else if (!(pressure->invoked_flag & INVOKED_SCALAR)) {
       pressure->compute_scalar();
       pressure->invoked_flag |= INVOKED_SCALAR;
     }
     compute_enthalpy();
 
   } else if (strcmp(word,"evdwl") == 0) {
     if (update->eflag_global != update->ntimestep)
       error->all(FLERR,"Energy was not tallied on needed timestep");
     if (!pe)
       error->all(FLERR,
                  "Thermo keyword in variable requires thermo to use/init pe");
     pe->invoked_flag |= INVOKED_SCALAR;
     compute_evdwl();
 
   } else if (strcmp(word,"ecoul") == 0) {
     if (update->eflag_global != update->ntimestep)
       error->all(FLERR,"Energy was not tallied on needed timestep");
     if (!pe)
       error->all(FLERR,
                  "Thermo keyword in variable requires thermo to use/init pe");
     pe->invoked_flag |= INVOKED_SCALAR;
     compute_ecoul();
 
   } else if (strcmp(word,"epair") == 0) {
     if (update->eflag_global != update->ntimestep)
       error->all(FLERR,"Energy was not tallied on needed timestep");
     if (!pe)
       error->all(FLERR,
                  "Thermo keyword in variable requires thermo to use/init pe");
     pe->invoked_flag |= INVOKED_SCALAR;
     compute_epair();
 
   } else if (strcmp(word,"ebond") == 0) {
     if (update->eflag_global != update->ntimestep)
       error->all(FLERR,"Energy was not tallied on needed timestep");
     if (!pe)
       error->all(FLERR,
                  "Thermo keyword in variable requires thermo to use/init pe");
     pe->invoked_flag |= INVOKED_SCALAR;
     compute_ebond();
 
   } else if (strcmp(word,"eangle") == 0) {
     if (update->eflag_global != update->ntimestep)
       error->all(FLERR,"Energy was not tallied on needed timestep");
     if (!pe)
       error->all(FLERR,
                  "Thermo keyword in variable requires thermo to use/init pe");
     pe->invoked_flag |= INVOKED_SCALAR;
     compute_eangle();
 
   } else if (strcmp(word,"edihed") == 0) {
     if (update->eflag_global != update->ntimestep)
       error->all(FLERR,"Energy was not tallied on needed timestep");
     if (!pe)
       error->all(FLERR,
                  "Thermo keyword in variable requires thermo to use/init pe");
     pe->invoked_flag |= INVOKED_SCALAR;
     compute_edihed();
 
   } else if (strcmp(word,"eimp") == 0) {
     if (update->eflag_global != update->ntimestep)
       error->all(FLERR,"Energy was not tallied on needed timestep");
     if (!pe)
       error->all(FLERR,
                  "Thermo keyword in variable requires thermo to use/init pe");
     pe->invoked_flag |= INVOKED_SCALAR;
     compute_eimp();
 
   } else if (strcmp(word,"emol") == 0) {
     if (update->eflag_global != update->ntimestep)
       error->all(FLERR,"Energy was not tallied on needed timestep");
     if (!pe)
       error->all(FLERR,
                  "Thermo keyword in variable requires thermo to use/init pe");
     pe->invoked_flag |= INVOKED_SCALAR;
     compute_emol();
 
   } else if (strcmp(word,"elong") == 0) {
     if (update->eflag_global != update->ntimestep)
       error->all(FLERR,"Energy was not tallied on needed timestep");
     if (!pe)
       error->all(FLERR,
                  "Thermo keyword in variable requires thermo to use/init pe");
     pe->invoked_flag |= INVOKED_SCALAR;
     compute_elong();
 
   } else if (strcmp(word,"etail") == 0) {
     if (update->eflag_global != update->ntimestep)
       error->all(FLERR,"Energy was not tallied on needed timestep");
     if (!pe)
       error->all(FLERR,
                  "Thermo keyword in variable requires thermo to use/init pe");
     pe->invoked_flag |= INVOKED_SCALAR;
     compute_etail();
 
   } else if (strcmp(word,"vol") == 0) compute_vol();
   else if (strcmp(word,"density") == 0) compute_density();
   else if (strcmp(word,"lx") == 0) compute_lx();
   else if (strcmp(word,"ly") == 0) compute_ly();
   else if (strcmp(word,"lz") == 0) compute_lz();
 
   else if (strcmp(word,"xlo") == 0) compute_xlo();
   else if (strcmp(word,"xhi") == 0) compute_xhi();
   else if (strcmp(word,"ylo") == 0) compute_ylo();
   else if (strcmp(word,"yhi") == 0) compute_yhi();
   else if (strcmp(word,"zlo") == 0) compute_zlo();
   else if (strcmp(word,"zhi") == 0) compute_zhi();
 
   else if (strcmp(word,"xy") == 0) compute_xy();
   else if (strcmp(word,"xz") == 0) compute_xz();
   else if (strcmp(word,"yz") == 0) compute_yz();
 
   else if (strcmp(word,"xlat") == 0) compute_xlat();
   else if (strcmp(word,"ylat") == 0) compute_ylat();
   else if (strcmp(word,"zlat") == 0) compute_zlat();
 
   else if (strcmp(word,"bonds") == 0) compute_bonds();
   else if (strcmp(word,"angles") == 0) compute_angles();
   else if (strcmp(word,"dihedrals") == 0) compute_dihedrals();
   else if (strcmp(word,"impropers") == 0) compute_impropers();
 
   else if (strcmp(word,"pxx") == 0) {
     if (!pressure)
       error->all(FLERR,"Thermo keyword in variable requires "
                  "thermo to use/init press");
     if (update->whichflag == 0) {
       if (pressure->invoked_vector != update->ntimestep)
         error->all(FLERR,"Compute used in variable thermo keyword between runs "
                    "is not current");
     } else if (!(pressure->invoked_flag & INVOKED_VECTOR)) {
       pressure->compute_vector();
       pressure->invoked_flag |= INVOKED_VECTOR;
     }
     compute_pxx();
 
   } else if (strcmp(word,"pyy") == 0) {
     if (!pressure)
       error->all(FLERR,"Thermo keyword in variable requires "
                  "thermo to use/init press");
     if (update->whichflag == 0) {
       if (pressure->invoked_vector != update->ntimestep)
         error->all(FLERR,"Compute used in variable thermo keyword between runs "
                    "is not current");
     } else if (!(pressure->invoked_flag & INVOKED_VECTOR)) {
       pressure->compute_vector();
       pressure->invoked_flag |= INVOKED_VECTOR;
     }
     compute_pyy();
 
   } else if (strcmp(word,"pzz") == 0) {
     if (!pressure)
       error->all(FLERR,"Thermo keyword in variable requires "
                  "thermo to use/init press");
     if (update->whichflag == 0) {
       if (pressure->invoked_vector != update->ntimestep)
         error->all(FLERR,"Compute used in variable thermo keyword between runs "
                    "is not current");
     } else if (!(pressure->invoked_flag & INVOKED_VECTOR)) {
       pressure->compute_vector();
       pressure->invoked_flag |= INVOKED_VECTOR;
     }
     compute_pzz();
 
   } else if (strcmp(word,"pxy") == 0) {
     if (!pressure)
       error->all(FLERR,"Thermo keyword in variable requires "
                  "thermo to use/init press");
     if (update->whichflag == 0) {
       if (pressure->invoked_vector != update->ntimestep)
         error->all(FLERR,"Compute used in variable thermo keyword between runs "
                    "is not current");
     } else if (!(pressure->invoked_flag & INVOKED_VECTOR)) {
       pressure->compute_vector();
       pressure->invoked_flag |= INVOKED_VECTOR;
     }
     compute_pxy();
 
   } else if (strcmp(word,"pxz") == 0) {
     if (!pressure)
       error->all(FLERR,"Thermo keyword in variable requires "
                  "thermo to use/init press");
     if (update->whichflag == 0) {
       if (pressure->invoked_vector != update->ntimestep)
         error->all(FLERR,"Compute used in variable thermo keyword between runs "
                    "is not current");
     } else if (!(pressure->invoked_flag & INVOKED_VECTOR)) {
       pressure->compute_vector();
       pressure->invoked_flag |= INVOKED_VECTOR;
     }
     compute_pxz();
 
   } else if (strcmp(word,"pyz") == 0) {
     if (!pressure)
       error->all(FLERR,"Thermo keyword in variable requires "
                  "thermo to use/init press");
     if (update->whichflag == 0) {
       if (pressure->invoked_vector != update->ntimestep)
         error->all(FLERR,"Compute used in variable thermo keyword between runs "
                    "is not current");
     } else if (!(pressure->invoked_flag & INVOKED_VECTOR)) {
       pressure->compute_vector();
       pressure->invoked_flag |= INVOKED_VECTOR;
     }
     compute_pyz();
   }
 
   else if (strcmp(word,"fmax") == 0) compute_fmax();
   else if (strcmp(word,"fnorm") == 0) compute_fnorm();
 
   else if (strcmp(word,"nbuild") == 0) {
     compute_nbuild();
     dvalue = bivalue;
   } else if (strcmp(word,"ndanger") == 0) {
     compute_ndanger();
     dvalue = bivalue;
   }
 
   else if (strcmp(word,"cella") == 0) compute_cella();
   else if (strcmp(word,"cellb") == 0) compute_cellb();
   else if (strcmp(word,"cellc") == 0) compute_cellc();
   else if (strcmp(word,"cellalpha") == 0) compute_cellalpha();
   else if (strcmp(word,"cellbeta") == 0) compute_cellbeta();
   else if (strcmp(word,"cellgamma") == 0) compute_cellgamma();
 
   else return 1;
 
   *answer = dvalue;
   return 0;
 }
 
 /* ----------------------------------------------------------------------
    extraction of Compute, Fix, Variable results
    compute/fix are normalized by atoms if returning extensive value
    variable value is not normalized (formula should normalize if desired)
 ------------------------------------------------------------------------- */
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_compute()
 {
   int m = field2index[ifield];
   Compute *compute = computes[m];
 
   if (compute_which[m] == SCALAR) {
     dvalue = compute->scalar;
     if (normflag && compute->extscalar) dvalue /= natoms;
   } else if (compute_which[m] == VECTOR) {
     dvalue = compute->vector[argindex1[ifield]-1];
     if (normflag) {
       if (compute->extvector == 0) return;
       else if (compute->extvector == 1) dvalue /= natoms;
       else if (compute->extlist[argindex1[ifield]-1]) dvalue /= natoms;
     }
   } else {
     dvalue = compute->array[argindex1[ifield]-1][argindex2[ifield]-1];
     if (normflag && compute->extarray) dvalue /= natoms;
   }
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_fix()
 {
   int m = field2index[ifield];
   Fix *fix = fixes[m];
 
   if (argindex1[ifield] == 0) {
     dvalue = fix->compute_scalar();
     if (normflag && fix->extscalar) dvalue /= natoms;
   } else if (argindex2[ifield] == 0) {
     dvalue = fix->compute_vector(argindex1[ifield]-1);
     if (normflag) {
       if (fix->extvector == 0) return;
       else if (fix->extvector == 1) dvalue /= natoms;
       else if (fix->extlist[argindex1[ifield]-1]) dvalue /= natoms;
     }
   } else {
     dvalue = fix->compute_array(argindex1[ifield]-1,argindex2[ifield]-1);
     if (normflag && fix->extarray) dvalue /= natoms;
   }
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_variable()
 {
   dvalue = input->variable->compute_equal(variables[field2index[ifield]]);
 }
 
 /* ----------------------------------------------------------------------
    one method for every keyword thermo can output
    called by compute() or evaluate_keyword()
    compute will have already been called
    set ivalue/dvalue/bivalue if value is int/double/bigint
    customize a new keyword by adding a method
 ------------------------------------------------------------------------- */
 
 void Thermo::compute_step()
 {
   bivalue = update->ntimestep;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_elapsed()
 {
   bivalue = update->ntimestep - update->firststep;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_elapsed_long()
 {
   bivalue = update->ntimestep - update->beginstep;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_dt()
 {
   dvalue = update->dt;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_time()
 {
   dvalue = update->atime + (update->ntimestep-update->atimestep)*update->dt;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_cpu()
 {
   if (firststep == 0) dvalue = 0.0;
   else dvalue = timer->elapsed(Timer::TOTAL);
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_tpcpu()
 {
   double new_cpu;
   double new_time = update->ntimestep * update->dt;
 
   if (firststep == 0) {
     new_cpu = 0.0;
     dvalue = 0.0;
   } else {
     new_cpu = timer->elapsed(Timer::TOTAL);
     double cpu_diff = new_cpu - last_tpcpu;
     double time_diff = new_time - last_time;
     if (time_diff > 0.0 && cpu_diff > 0.0) dvalue = time_diff/cpu_diff;
     else dvalue = 0.0;
   }
 
   last_time = new_time;
   last_tpcpu = new_cpu;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_spcpu()
 {
   double new_cpu;
   int new_step = update->ntimestep;
 
   if (firststep == 0) {
     new_cpu = 0.0;
     dvalue = 0.0;
   } else {
     new_cpu = timer->elapsed(Timer::TOTAL);
     double cpu_diff = new_cpu - last_spcpu;
     int step_diff = new_step - last_step;
     if (cpu_diff > 0.0) dvalue = step_diff/cpu_diff;
     else dvalue = 0.0;
   }
 
   last_step = new_step;
   last_spcpu = new_cpu;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_cpuremain()
 {
   if (firststep == 0) dvalue = 0.0;
   else dvalue = timer->elapsed(Timer::TOTAL) * 
          (update->laststep - update->ntimestep) /
          (update->ntimestep - update->firststep);
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_part()
 {
   ivalue = universe->iworld;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_atoms()
 {
   bivalue = atom->natoms;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_temp()
 {
   dvalue = temperature->scalar;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_press()
 {
   dvalue = pressure->scalar;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_pe()
 {
   dvalue = pe->scalar;
   if (normflag) dvalue /= natoms;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_ke()
 {
   dvalue = temperature->scalar;
   dvalue *= 0.5 * temperature->dof * force->boltz;
   if (normflag) dvalue /= natoms;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_etotal()
 {
   compute_pe();
   double ke = temperature->scalar;
   ke *= 0.5 * temperature->dof * force->boltz;
   if (normflag) ke /= natoms;
   dvalue += ke;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_enthalpy()
 {
   compute_etotal();
   double etmp = dvalue;
 
   compute_vol();
   double vtmp = dvalue;
   if (normflag) vtmp /= natoms;
 
   compute_press();
   double ptmp = dvalue;
 
   dvalue = etmp + ptmp*vtmp/(force->nktv2p);
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_evdwl()
 {
   double tmp = 0.0;
   if (force->pair) tmp += force->pair->eng_vdwl;
   MPI_Allreduce(&tmp,&dvalue,1,MPI_DOUBLE,MPI_SUM,world);
 
   if (force->pair && force->pair->tail_flag) {
     double volume = domain->xprd * domain->yprd * domain->zprd;
     dvalue += force->pair->etail / volume;
   }
 
   if (normflag) dvalue /= natoms;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_ecoul()
 {
   double tmp = 0.0;
   if (force->pair) tmp += force->pair->eng_coul;
   MPI_Allreduce(&tmp,&dvalue,1,MPI_DOUBLE,MPI_SUM,world);
   if (normflag) dvalue /= natoms;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_epair()
 {
   double tmp = 0.0;
   if (force->pair) tmp += force->pair->eng_vdwl + force->pair->eng_coul;
   MPI_Allreduce(&tmp,&dvalue,1,MPI_DOUBLE,MPI_SUM,world);
 
   if (force->kspace) dvalue += force->kspace->energy;
   if (force->pair && force->pair->tail_flag) {
     double volume = domain->xprd * domain->yprd * domain->zprd;
     dvalue += force->pair->etail / volume;
   }
 
   if (normflag) dvalue /= natoms;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_ebond()
 {
   if (force->bond) {
     double tmp = force->bond->energy;
     MPI_Allreduce(&tmp,&dvalue,1,MPI_DOUBLE,MPI_SUM,world);
     if (normflag) dvalue /= natoms;
   } else dvalue = 0.0;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_eangle()
 {
   if (force->angle) {
     double tmp = force->angle->energy;
     MPI_Allreduce(&tmp,&dvalue,1,MPI_DOUBLE,MPI_SUM,world);
     if (normflag) dvalue /= natoms;
   } else dvalue = 0.0;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_edihed()
 {
   if (force->dihedral) {
     double tmp = force->dihedral->energy;
     MPI_Allreduce(&tmp,&dvalue,1,MPI_DOUBLE,MPI_SUM,world);
     if (normflag) dvalue /= natoms;
   } else dvalue = 0.0;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_eimp()
 {
   if (force->improper) {
     double tmp = force->improper->energy;
     MPI_Allreduce(&tmp,&dvalue,1,MPI_DOUBLE,MPI_SUM,world);
     if (normflag) dvalue /= natoms;
   } else dvalue = 0.0;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_emol()
 {
   double tmp = 0.0;
   if (atom->molecular) {
     if (force->bond) tmp += force->bond->energy;
     if (force->angle) tmp += force->angle->energy;
     if (force->dihedral) tmp += force->dihedral->energy;
     if (force->improper) tmp += force->improper->energy;
     MPI_Allreduce(&tmp,&dvalue,1,MPI_DOUBLE,MPI_SUM,world);
     if (normflag) dvalue /= natoms;
   } else dvalue = 0.0;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_elong()
 {
   if (force->kspace) {
     dvalue = force->kspace->energy;
     if (normflag) dvalue /= natoms;
   } else dvalue = 0.0;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_etail()
 {
   if (force->pair && force->pair->tail_flag) {
     double volume = domain->xprd * domain->yprd * domain->zprd;
     dvalue = force->pair->etail / volume;
     if (normflag) dvalue /= natoms;
   } else dvalue = 0.0;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_vol()
 {
   if (domain->dimension == 3)
     dvalue = domain->xprd * domain->yprd * domain->zprd;
   else
     dvalue = domain->xprd * domain->yprd;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_density()
 {
   double mass = group->mass(0);
   compute_vol();
   dvalue = force->mv2d * mass/dvalue;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_lx()
 {
   dvalue = domain->xprd;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_ly()
 {
   dvalue = domain->yprd;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_lz()
 {
   dvalue = domain->zprd;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_xlo()
 {
   dvalue = domain->boxlo[0];
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_xhi()
 {
   dvalue = domain->boxhi[0];
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_ylo()
 {
   dvalue = domain->boxlo[1];
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_yhi()
 {
   dvalue = domain->boxhi[1];
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_zlo()
 {
   dvalue = domain->boxlo[2];
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_zhi()
 {
   dvalue = domain->boxhi[2];
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_xy()
 {
   dvalue = domain->xy;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_xz()
 {
   dvalue = domain->xz;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_yz()
 {
   dvalue = domain->yz;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_xlat()
 {
   dvalue = domain->lattice->xlattice;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_ylat()
 {
   dvalue = domain->lattice->ylattice;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_zlat()
 {
   dvalue = domain->lattice->zlattice;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_bonds()
 {
   bivalue = atom->nbonds;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_angles()
 {
   bivalue = atom->nangles;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_dihedrals()
 {
   bivalue = atom->ndihedrals;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_impropers()
 {
   bivalue = atom->nimpropers;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_pxx()
 {
   dvalue = pressure->vector[0];
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_pyy()
 {
   dvalue = pressure->vector[1];
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_pzz()
 {
   dvalue = pressure->vector[2];
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_pxy()
 {
   dvalue = pressure->vector[3];
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_pxz()
 {
   dvalue = pressure->vector[4];
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_pyz()
 {
   dvalue = pressure->vector[5];
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_fmax()
 {
   double **f = atom->f;
   int nlocal = atom->nlocal;
 
   double max = 0.0;
   for (int i = 0; i < nlocal; i++) {
     max = MAX(max,fabs(f[i][0]));
     max = MAX(max,fabs(f[i][1]));
     max = MAX(max,fabs(f[i][2]));
   }
   double maxall;
   MPI_Allreduce(&max,&maxall,1,MPI_DOUBLE,MPI_MAX,world);
   dvalue = maxall;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_fnorm()
 {
   double **f = atom->f;
   int nlocal = atom->nlocal;
 
   double dot = 0.0;
   for (int i = 0; i < nlocal; i++)
     dot += f[i][0]*f[i][0] + f[i][1]*f[i][1] + f[i][2]*f[i][2];
   double dotall;
   MPI_Allreduce(&dot,&dotall,1,MPI_DOUBLE,MPI_SUM,world);
   dvalue = sqrt(dotall);
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_nbuild()
 {
   bivalue = neighbor->ncalls;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_ndanger()
 {
   bivalue = neighbor->ndanger;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_cella()
 {
   dvalue = domain->xprd;
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_cellb()
 {
   if (!domain->triclinic)
     dvalue = domain->yprd;
   else {
     double* h = domain->h;
     dvalue = sqrt(h[1]*h[1]+h[5]*h[5]);
   }
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_cellc()
 {
   if (!domain->triclinic)
     dvalue = domain->zprd;
   else {
     double* h = domain->h;
     dvalue = sqrt(h[2]*h[2]+h[3]*h[3]+h[4]*h[4]);
   }
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_cellalpha()
 {
   if (!domain->triclinic)
     dvalue = 90.0;
   else {
 
     // Cos(alpha) = (xy.xz + ly.yz)/(b.c)
 
     double* h = domain->h;
     double cosalpha = (h[5]*h[4]+h[1]*h[3])/
       sqrt((h[1]*h[1]+h[5]*h[5])*(h[2]*h[2]+h[3]*h[3]+h[4]*h[4]));
     dvalue = acos(cosalpha)*180.0/MY_PI;
   }
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_cellbeta()
 {
   if (!domain->triclinic)
     dvalue = 90.0;
   else {
 
     // Cos(beta) = xz/c
 
     double* h = domain->h;
     double cosbeta = h[4]/sqrt(h[2]*h[2]+h[3]*h[3]+h[4]*h[4]);
     dvalue = acos(cosbeta)*180.0/MY_PI;
   }
 }
 
 /* ---------------------------------------------------------------------- */
 
 void Thermo::compute_cellgamma()
 {
   if (!domain->triclinic)
     dvalue = 90.0;
   else {
 
     // Cos(gamma) = xy/b
 
     double* h = domain->h;
     double cosgamma = h[5]/sqrt(h[1]*h[1]+h[5]*h[5]);
     dvalue = acos(cosgamma)*180.0/MY_PI;
   }
 }